relative imports
This commit is contained in:
@@ -33,6 +33,10 @@
|
||||
|
||||
## UPDATES
|
||||
|
||||
**2024/01/07** @1.0.3:
|
||||
* relative imports
|
||||
* node names cleaned
|
||||
|
||||
**2024/01/05** @1.0.2:
|
||||
* reorganized imports
|
||||
|
||||
|
||||
+83
-15
@@ -22,7 +22,7 @@
|
||||
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS", "WEB_DIRECTORY"]
|
||||
__author__ = """Alexander G. Morano"""
|
||||
__email__ = "amorano@gmail.com"
|
||||
__version__ = "1.0.2"
|
||||
__version__ = "1.0.3"
|
||||
|
||||
import os
|
||||
import sys
|
||||
@@ -30,6 +30,7 @@ import json
|
||||
import inspect
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
|
||||
from loguru import logger
|
||||
|
||||
@@ -50,7 +51,59 @@ JOV_INTERNAL = os.getenv("JOV_INTERNAL", 'false').strip().lower() in ('true', '1
|
||||
JOV_LOG_LEVEL = os.getenv("JOV_LOG_LEVEL", "INFO")
|
||||
logger.configure(handlers=[{"sink": sys.stdout, "level": JOV_LOG_LEVEL}])
|
||||
|
||||
JOV_PACKAGE = "Jovi_GLSL"
|
||||
JOV_PACKAGE = "JOV_GL"
|
||||
|
||||
# ==============================================================================
|
||||
# === CORE NODES ===
|
||||
# ==============================================================================
|
||||
|
||||
class JOVBaseNode:
|
||||
NOT_IDEMPOTENT = True
|
||||
CATEGORY = f"{JOV_PACKAGE} 🦚"
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK")
|
||||
RETURN_NAMES = ('RGBA', 'RGB', 'MASK')
|
||||
FUNCTION = "run"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, *arg, **kw) -> bool:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls, prompt:bool=False, extra_png:bool=False, dynprompt:bool=False) -> dict:
|
||||
data = {
|
||||
"required": {},
|
||||
"optional": {},
|
||||
"outputs": {
|
||||
0: ("IMAGE", {"tooltips":"Full channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output."}),
|
||||
1: ("IMAGE", {"tooltips":"Three channel [RGB] image. There will be no alpha."}),
|
||||
2: ("MASK", {"tooltips":"Single channel mask output."}),
|
||||
},
|
||||
"hidden": {
|
||||
"ident": "UNIQUE_ID"
|
||||
}
|
||||
}
|
||||
if prompt:
|
||||
data["hidden"]["prompt"] = "PROMPT"
|
||||
if extra_png:
|
||||
data["hidden"]["extra_pnginfo"] = "EXTRA_PNGINFO"
|
||||
|
||||
if dynprompt:
|
||||
data["hidden"]["dynprompt"] = "DYNPROMPT"
|
||||
return data
|
||||
|
||||
# ==============================================================================
|
||||
# === TYPE ===
|
||||
# ==============================================================================
|
||||
|
||||
class AnyType(str):
|
||||
"""AnyType input wildcard trick taken from pythongossss's:
|
||||
|
||||
https://github.com/pythongosssss/ComfyUI-Custom-Scripts
|
||||
"""
|
||||
def __ne__(self, __value: object) -> bool:
|
||||
return False
|
||||
|
||||
JOV_TYPE_ANY = AnyType("*")
|
||||
|
||||
# ==============================================================================
|
||||
# === SUPPORT ===
|
||||
@@ -67,6 +120,27 @@ def load_file(fname: str) -> str | None:
|
||||
# === LOADER ===
|
||||
# ==============================================================================
|
||||
|
||||
def load_module(name: str) -> None|ModuleType:
|
||||
module = inspect.getmodule(inspect.stack()[0][0]).__name__
|
||||
try:
|
||||
route = str(name).replace("\\", "/")
|
||||
route = route.split(f"{module}/core/")[1]
|
||||
route = route.split('.')[0].replace('/', '.')
|
||||
except Exception as e:
|
||||
logger.warning(f"module failed {name}")
|
||||
logger.warning(str(e))
|
||||
return
|
||||
|
||||
try:
|
||||
module = f"{module}.core.{route}"
|
||||
module = importlib.import_module(module)
|
||||
except Exception as e:
|
||||
logger.warning(f"module failed {module}")
|
||||
logger.warning(str(e))
|
||||
return
|
||||
|
||||
return module
|
||||
|
||||
def loader():
|
||||
global NODE_DISPLAY_NAME_MAPPINGS, NODE_CLASS_MAPPINGS
|
||||
NODE_LIST_MAP = {}
|
||||
@@ -75,39 +149,33 @@ def loader():
|
||||
if fname.stem.startswith('_'):
|
||||
continue
|
||||
|
||||
try:
|
||||
route = str(fname).replace("\\", "/").split(f"{JOV_PACKAGE}/core/")[1]
|
||||
route = route.split('.')[0].replace('/', '.')
|
||||
module = f"{JOV_PACKAGE}.core.{route}"
|
||||
module = importlib.import_module(module)
|
||||
except Exception as e:
|
||||
logger.warning(f"module failed {fname}")
|
||||
logger.warning(str(e))
|
||||
if (module := load_module(fname)) is None:
|
||||
continue
|
||||
|
||||
# check if there is a dynamic register function....
|
||||
try:
|
||||
for class_name, class_def in module.import_dynamic():
|
||||
setattr(module, class_name, class_def)
|
||||
# logger.debug(f"shader: {class_name}")
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
classes = inspect.getmembers(module, inspect.isclass)
|
||||
for class_name, class_object in classes:
|
||||
if not class_name.endswith('BaseNode') and hasattr(class_object, 'NAME') and hasattr(class_object, 'CATEGORY'):
|
||||
name = class_object.NAME
|
||||
name = f"{class_object.NAME} ({JOV_PACKAGE})"
|
||||
NODE_DISPLAY_NAME_MAPPINGS[name] = name
|
||||
NODE_CLASS_MAPPINGS[name] = class_object
|
||||
desc = class_object.DESCRIPTION if hasattr(class_object, 'DESCRIPTION') else name
|
||||
NODE_LIST_MAP[name] = desc.split('.')[0].strip('\n')
|
||||
|
||||
if class_object.SORT < 5000:
|
||||
desc = class_object.DESCRIPTION if hasattr(class_object, 'DESCRIPTION') else name
|
||||
NODE_LIST_MAP[name] = desc.split('.')[0].strip('\n')
|
||||
|
||||
NODE_CLASS_MAPPINGS = {x[0] : x[1] for x in sorted(NODE_CLASS_MAPPINGS.items(),
|
||||
key=lambda item: getattr(item[1], 'SORT', 0))}
|
||||
|
||||
keys = NODE_CLASS_MAPPINGS.keys()
|
||||
for name in keys:
|
||||
logger.debug(f"✅ {name} :: {NODE_DISPLAY_NAME_MAPPINGS[name]}")
|
||||
logger.debug(f"✅ {name}")
|
||||
logger.info(f"{len(keys)} nodes loaded")
|
||||
|
||||
# only do the list on local runs...
|
||||
|
||||
+3
-44
@@ -15,7 +15,9 @@ import torch
|
||||
import numpy as np
|
||||
from loguru import logger
|
||||
|
||||
from Jovi_GLSL import JOV_PACKAGE, ROOT, load_file
|
||||
from .. import JOV_TYPE_ANY, ROOT, \
|
||||
JOVBaseNode, \
|
||||
load_file
|
||||
|
||||
# ==============================================================================
|
||||
# === SHADER LOADER ===
|
||||
@@ -90,48 +92,6 @@ class Singleton(type):
|
||||
# === CORE NODES ===
|
||||
# ==============================================================================
|
||||
|
||||
class JOVBaseNode:
|
||||
NOT_IDEMPOTENT = True
|
||||
CATEGORY = f"{JOV_PACKAGE.upper()} 🦚"
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK")
|
||||
RETURN_NAMES = ('RGBA', 'RGB', 'MASK')
|
||||
FUNCTION = "run"
|
||||
|
||||
@classmethod
|
||||
def VALIDATE_INPUTS(cls, *arg, **kw) -> bool:
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls, prompt:bool=False, extra_png:bool=False, dynprompt:bool=False) -> dict:
|
||||
data = {
|
||||
"required": {},
|
||||
"optional": {},
|
||||
"outputs": {
|
||||
0: ("IMAGE", {"tooltips":"Full channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output."}),
|
||||
1: ("IMAGE", {"tooltips":"Three channel [RGB] image. There will be no alpha."}),
|
||||
2: ("MASK", {"tooltips":"Single channel mask output."}),
|
||||
},
|
||||
"hidden": {
|
||||
"ident": "UNIQUE_ID"
|
||||
}
|
||||
}
|
||||
if prompt:
|
||||
data["hidden"]["prompt"] = "PROMPT"
|
||||
if extra_png:
|
||||
data["hidden"]["extra_pnginfo"] = "EXTRA_PNGINFO"
|
||||
|
||||
if dynprompt:
|
||||
data["hidden"]["dynprompt"] = "DYNPROMPT"
|
||||
return data
|
||||
|
||||
class AnyType(str):
|
||||
"""AnyType input wildcard trick taken from pythongossss's:
|
||||
|
||||
https://github.com/pythongosssss/ComfyUI-Custom-Scripts
|
||||
"""
|
||||
def __ne__(self, __value: object) -> bool:
|
||||
return False
|
||||
|
||||
class JOVBaseGLSLNode(JOVBaseNode):
|
||||
NOT_IDEMPOTENT = True
|
||||
RETURN_TYPES = ("IMAGE", "IMAGE", "MASK")
|
||||
@@ -220,7 +180,6 @@ JOV_TYPE_NUMBER = f"{JOV_TYPE_COMFY}|{JOV_TYPE_VECTOR}"
|
||||
JOV_TYPE_IMAGE = "IMAGE|MASK"
|
||||
JOV_TYPE_FULL = f"{JOV_TYPE_NUMBER}|{JOV_TYPE_IMAGE}"
|
||||
|
||||
JOV_TYPE_ANY = AnyType("*")
|
||||
JOV_TYPE_COMFY = JOV_TYPE_ANY
|
||||
JOV_TYPE_VECTOR = JOV_TYPE_ANY
|
||||
JOV_TYPE_NUMBER = JOV_TYPE_ANY
|
||||
|
||||
+9
-12
@@ -13,22 +13,20 @@ from loguru import logger
|
||||
|
||||
from comfy.utils import ProgressBar
|
||||
|
||||
from Jovi_GLSL import load_file
|
||||
from .. import load_file
|
||||
|
||||
from Jovi_GLSL.core import GLSL_PROGRAMS, JOV_TYPE_IMAGE, PTYPE, RE_VARIABLE, \
|
||||
from ..core import GLSL_PROGRAMS, JOV_TYPE_IMAGE, PTYPE, RE_VARIABLE, \
|
||||
ROOT_GLSL, IMAGE_SIZE_MIN, IMAGE_SIZE_DEFAULT, IMAGE_SIZE_MAX, \
|
||||
CompileException, JOVBaseGLSLNode, EnumConvertType, \
|
||||
cv2tensor_full, image_convert, parse_param, parse_value, tensor2cv, zip_longest_fill
|
||||
cv2tensor_full, image_convert, parse_param, parse_value, \
|
||||
tensor2cv, zip_longest_fill
|
||||
|
||||
from Jovi_GLSL.core.glsl_shader import GLSLShader
|
||||
from ..core.glsl_shader import GLSLShader
|
||||
|
||||
# ==============================================================================
|
||||
# === CONSTANT ===
|
||||
# ==============================================================================
|
||||
|
||||
GLSL_INTERNAL = '🌈'
|
||||
GLSL_CUSTOM = '🦄'
|
||||
|
||||
RE_INCLUDE = re.compile(r"^\s*#include\s+([A-Za-z_\-\.\\\/]{3,})$", re.MULTILINE)
|
||||
RE_SHADER_META = re.compile(r"^\/\/\s?([A-Za-z_]{3,}):\s?(.+)$", re.MULTILINE)
|
||||
|
||||
@@ -297,7 +295,7 @@ def load_file_glsl(fname: str) -> str:
|
||||
|
||||
def import_dynamic() -> Tuple[str,...]:
|
||||
ret = []
|
||||
sort = 4000
|
||||
sort = 5000
|
||||
root = str(ROOT_GLSL)
|
||||
for name, fname in GLSL_PROGRAMS['fragment'].items():
|
||||
if (shader := load_file_glsl(fname)) is None:
|
||||
@@ -312,18 +310,17 @@ def import_dynamic() -> Tuple[str,...]:
|
||||
class_name = name.title().replace(' ', '_')
|
||||
class_name = f'GLSLNode_{class_name}'
|
||||
|
||||
emoji = GLSL_CUSTOM
|
||||
sort_order = sort
|
||||
# put custom user nodes last
|
||||
if fname.startswith(root):
|
||||
emoji = GLSL_INTERNAL
|
||||
sort_order -= 2500
|
||||
sort_order -= 5000
|
||||
|
||||
category = GLSLNodeDynamic.CATEGORY
|
||||
if (sub := meta.get('category', None)) is not None:
|
||||
category += f'/{sub}'
|
||||
|
||||
class_def = type(class_name, (GLSLNodeDynamic,), {
|
||||
"NAME": f'GLSL {name} (JOV_GL) {emoji}'.upper(),
|
||||
"NAME": name,
|
||||
"DESCRIPTION": meta.get('desc', name),
|
||||
"CATEGORY": category.upper(),
|
||||
"FRAGMENT": shader,
|
||||
|
||||
@@ -8,7 +8,7 @@ import gc
|
||||
import glfw
|
||||
from loguru import logger
|
||||
|
||||
from Jovi_GLSL.core import Singleton
|
||||
from ..core import Singleton
|
||||
|
||||
# ==============================================================================
|
||||
# === MANAGER ===
|
||||
|
||||
+2
-2
@@ -13,12 +13,12 @@ import numpy as np
|
||||
import OpenGL.GL as gl
|
||||
from loguru import logger
|
||||
|
||||
from Jovi_GLSL.core import IMAGE_SIZE_MAX, IMAGE_SIZE_MIN, PROG_VERTEX, \
|
||||
from ..core import IMAGE_SIZE_MAX, IMAGE_SIZE_MIN, PROG_VERTEX, \
|
||||
PROG_FRAGMENT, PROG_FOOTER, PROG_HEADER, PTYPE, RE_VARIABLE, \
|
||||
CompileException, \
|
||||
image_convert, parse_value
|
||||
|
||||
from Jovi_GLSL.core.glsl_manager import GLSLManager
|
||||
from ..core.glsl_manager import GLSLManager
|
||||
|
||||
# ==============================================================================
|
||||
# === CONSTANT ===
|
||||
|
||||
+19
-19
@@ -1,21 +1,21 @@
|
||||
{
|
||||
"GLSL BLEND LINEAR (JOV_GL) \ud83c\udf08": "Simple linear blend between two images",
|
||||
"GLSL COLOR CONVERSION (JOV_GL) \ud83c\udf08": "Convert an image from one color space (RGB, HSV, LAB, XYZ) to another",
|
||||
"GLSL COLOR PALETTE (JOV_GL) \ud83c\udf08": "Color palette creation using the formula: color(t) = a + b * cos[tau(c*t+d)]",
|
||||
"GLSL CONICAL GRADIENT (JOV_GL) \ud83c\udf08": "Generate a conical gradient from black to white",
|
||||
"GLSL DIRECTIONAL WARP (JOV_GL) \ud83c\udf08": "Domain warp an image with a direction and distortion map",
|
||||
"GLSL FILTER RANGE (JOV_GL) \ud83c\udf08": "Select pixels from start color through end color",
|
||||
"GLSL GRAYSCALE (JOV_GL) \ud83c\udf08": "Convert input to grayscale",
|
||||
"GLSL HSV ADJUST (JOV_GL) \ud83c\udf08": "Hue, Saturation and Value adjustment control",
|
||||
"GLSL INVERT (JOV_GL) \ud83c\udf08": "Invert the channels of an image along a scalar [0",
|
||||
"GLSL MIN MAX (JOV_GL) \ud83c\udf08": "Gets the minimum and maximum of an image",
|
||||
"GLSL NOISE PERLIN (JOV_GL) \ud83c\udf08": "Classic Perlin noise",
|
||||
"GLSL NOISE SIMPLEX (JOV_GL) \ud83c\udf08": "Simplex noise, simply",
|
||||
"GLSL NOISE WORLEY (JOV_GL) \ud83c\udf08": "Worley noise with the best",
|
||||
"GLSL NORMAL (JOV_GL) \ud83c\udf08": "Convert input into a Normal map",
|
||||
"GLSL NORMAL BLEND (JOV_GL) \ud83c\udf08": "Blend two Normal maps",
|
||||
"GLSL PIXELATE (JOV_GL) \ud83c\udf08": "Pixelate input image",
|
||||
"GLSL POSTERIZE (JOV_GL) \ud83c\udf08": "Reduce the pixel color data range",
|
||||
"GLSL SOBEL (JOV_GL) \ud83c\udf08": "Finds the edges of an image",
|
||||
"GLSL TRANSFORM (JOV_GL) \ud83c\udf08": "Move, Rotate, Scale and Tile an image"
|
||||
"BLEND LINEAR (JOV_GL)": "Simple linear blend between two images",
|
||||
"COLOR CONVERSION (JOV_GL)": "Convert an image from one color space (RGB, HSV, LAB, XYZ) to another",
|
||||
"COLOR PALETTE (JOV_GL)": "Color palette creation using the formula: color(t) = a + b * cos[tau(c*t+d)]",
|
||||
"CONICAL GRADIENT (JOV_GL)": "Generate a conical gradient from black to white",
|
||||
"DIRECTIONAL WARP (JOV_GL)": "Domain warp an image with a direction and distortion map",
|
||||
"FILTER RANGE (JOV_GL)": "Select pixels from start color through end color",
|
||||
"GRAYSCALE (JOV_GL)": "Convert input to grayscale",
|
||||
"HSV ADJUST (JOV_GL)": "Hue, Saturation and Value adjustment control",
|
||||
"INVERT (JOV_GL)": "Invert the channels of an image along a scalar [0",
|
||||
"MIN MAX (JOV_GL)": "Gets the minimum and maximum of an image",
|
||||
"NOISE PERLIN (JOV_GL)": "Classic Perlin noise",
|
||||
"NOISE SIMPLEX (JOV_GL)": "Simplex noise, simply",
|
||||
"NOISE WORLEY (JOV_GL)": "Worley noise with the best",
|
||||
"NORMAL (JOV_GL)": "Convert input into a Normal map",
|
||||
"NORMAL BLEND (JOV_GL)": "Blend two Normal maps",
|
||||
"PIXELATE (JOV_GL)": "Pixelate input image",
|
||||
"POSTERIZE (JOV_GL)": "Reduce the pixel color data range",
|
||||
"SOBEL (JOV_GL)": "Finds the edges of an image",
|
||||
"TRANSFORM (JOV_GL)": "Move, Rotate, Scale and Tile an image"
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
[project]
|
||||
name = "jovi_glsl"
|
||||
description = "Integrates GLSL shader support."
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = [
|
||||
"aenum>=3.1.15",
|
||||
|
||||
@@ -12,7 +12,7 @@ const _id = "GLSL DYNAMIC (JOV_GL)";
|
||||
app.registerExtension({
|
||||
name: 'jovi_glsl.node.' + _id,
|
||||
async beforeRegisterNodeDef(nodeType, nodeData) {
|
||||
if ((!nodeData.name.endsWith("(JOV_GL) 🌈") && !nodeData.name.endsWith("(JOV_GL) 🦄"))) {
|
||||
if (!nodeData.name.endsWith("(JOV_GL)")) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user