Skip to content

Commit

Permalink
api routes for glsl programs tracker for glsl programs as nodes
Browse files Browse the repository at this point in the history
reorg of utils.py
nicer globals for JS side
  • Loading branch information
Amorano committed Jul 22, 2024
1 parent 91259fd commit 50dc794
Show file tree
Hide file tree
Showing 15 changed files with 475 additions and 180 deletions.
59 changes: 58 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,26 @@
JOV_WEB = ROOT / 'web'
JOV_DEFAULT = JOV_WEB / 'default.json'
JOV_CONFIG_FILE = JOV_WEB / 'config.json'
#
JOV_ROOT_GLSL = ROOT / 'res' / 'glsl'
GLSL_PROGRAMS = {
"vertex": { "NONE": None },
"fragment": { "NONE": None }
}

GLSL_PROGRAMS["vertex"].update({str(f.name): str(f) for f in Path(JOV_ROOT_GLSL).glob('*.vert')})
if (USER_GLSL := os.getenv("JOV_GLSL", None)) is not None:
GLSL_PROGRAMS["vertex"].update({str(f.name): str(f) for f in Path(USER_GLSL).glob('*.vert')})

GLSL_PROGRAMS["fragment"].update({str(f.name): str(f) for f in Path(JOV_ROOT_GLSL).glob('*.glsl')})
if USER_GLSL is not None:
GLSL_PROGRAMS["fragment"].update({str(f.name): str(f) for f in Path(USER_GLSL).glob('*.glsl')})

logger.info(f"found {len(GLSL_PROGRAMS['vertex'])} vertex and {len(GLSL_PROGRAMS['fragment'])} fragment programs")
print(GLSL_PROGRAMS)

# nodes to skip on import; for online systems; skip Export, Streamreader, etc...
JOV_IGNORE_NODE = ROOT / 'ignore.txt'
JOV_GLSL = ROOT / 'res' / 'glsl'
JOV_SIDECAR = os.getenv("JOV_SIDECAR", str(ROOT / "_md"))

JOV_LOG_LEVEL = os.getenv("JOV_LOG_LEVEL", "WARNING")
Expand Down Expand Up @@ -142,6 +158,17 @@ def __ne__(self, __value: object) -> bool:
# == API RESPONSE
# =============================================================================

def load_file(fname: str) -> Any:
try:
with open(fname, 'r') as f:
return f.read()
except Exception as e:
logger.error(e)

# =============================================================================
# == API RESPONSE
# =============================================================================

class TimedOutException(Exception): pass

class ComfyAPIMessage:
Expand Down Expand Up @@ -236,6 +263,36 @@ async def jovimetrix_doc(request) -> Any:
f.write(data[k]['.md'])
return web.json_response(data)

@PromptServer.instance.routes.get("/jovimetrix/glsl")
async def jovimetrix_glsl_list(request) -> Any:
ret = {k:[kk for kk, vv in v.items() \
if kk not in ['NONE'] and vv not in [None] and Path(vv).exists()]
for k, v in GLSL_PROGRAMS.items()}
return web.json_response(ret)

@PromptServer.instance.routes.get("/jovimetrix/glsl/{shader}")
async def jovimetrix_glsl_raw(request, shader:str) -> Any:
if (program := GLSL_PROGRAMS.get(shader, None)) is None:
return web.json_response(f"no program {shader}")
response = load_file(program)
return web.json_response(response)

@PromptServer.instance.routes.post("/jovimetrix/glsl")
async def jovimetrix_glsl(request) -> Any:
json_data = await request.json()
response = {k:None for k in json_data.keys()}
for who in response.keys():
if (programs := GLSL_PROGRAMS.get(who, None)) is None:
logger.warning(f"no program type {who}")
continue
fname = json_data[who]
if (data := programs.get(fname, None)) is not None:
response[who] = load_file(data)
else:
logger.warning(f"no glsl shader entry {fname}")

return web.json_response(response)

except Exception as e:
logger.error(e)

Expand Down
29 changes: 16 additions & 13 deletions core/create.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@

from comfy.utils import ProgressBar

from Jovimetrix import comfy_message, parse_reset, JOVBaseNode, ROOT, JOV_TYPE_IMAGE
from Jovimetrix import comfy_message, parse_reset, JOVBaseNode, \
JOV_TYPE_IMAGE, GLSL_PROGRAMS

from Jovimetrix.sup.lexicon import JOVImageNode, Lexicon
from Jovimetrix.sup.util import parse_param, zip_longest_fill, EnumConvertType

from Jovimetrix.sup.image import channel_solid, cv2tensor, cv2tensor_full, image_convert, \
image_grayscale, image_invert, image_mask_add, pil2cv, tensor2pil, \
image_rotate, image_scalefit, image_stereogram, image_transform, image_translate, \
pixel_eval, tensor2cv, shape_ellipse, shape_polygon, shape_quad, \
from Jovimetrix.sup.image import channel_solid, cv2tensor, cv2tensor_full, \
image_grayscale, image_invert, image_mask_add, pil2cv, image_convert, \
image_rotate, image_scalefit, image_stereogram, image_transform, \
tensor2cv, shape_ellipse, shape_polygon, shape_quad, image_translate, \
EnumScaleMode, EnumInterpolation, EnumEdge, EnumImageType, MIN_IMAGE_SIZE

from Jovimetrix.sup.text import font_names, text_autosize, text_draw, \
Expand All @@ -33,7 +34,6 @@
# =============================================================================

JOV_CATEGORY = "CREATE"
JOV_CONFIG_GLSL = ROOT / 'glsl'

# =============================================================================

Expand Down Expand Up @@ -94,21 +94,23 @@ class GLSLNode(JOVImageNode):
DESCRIPTION = """
Execute custom GLSL (OpenGL Shading Language) fragment shaders to generate images or apply effects. GLSL is a high-level shading language used for graphics programming, particularly in the context of rendering images or animations. This node allows for real-time rendering of shader effects, providing flexibility and creative control over image processing pipelines. It takes advantage of GPU acceleration for efficient computation, enabling the rapid generation of complex visual effects.
"""
INSTANCE = 0

@classmethod
def INPUT_TYPES(cls) -> dict:
d = super().INPUT_TYPES()
d.update({
"optional": {
Lexicon.TIME: ("FLOAT", {"default": 0, "step": 0.001, "min": 0, "precision": 4}),
Lexicon.BATCH: ("INT", {"default": 1, "step": 1, "min": 0, "max": 262144}),
Lexicon.BATCH: ("INT", {"default": 0, "step": 1, "min": 0, "max": 1048576}),
Lexicon.FPS: ("INT", {"default": 24, "step": 1, "min": 1, "max": 120}),
Lexicon.WH: ("VEC2", {"default": (512, 512), "min": MIN_IMAGE_SIZE, "step": 1,}),
Lexicon.MATTE: ("VEC4", {"default": (0, 0, 0, 255), "step": 1,
"label": [Lexicon.R, Lexicon.G, Lexicon.B, Lexicon.A], "rgb": True}),
Lexicon.WAIT: ("BOOLEAN", {"default": False}),
Lexicon.RESET: ("BOOLEAN", {"default": False}),
Lexicon.FRAGMENT: ("STRING", {"default": GLSLShader.PROG_FRAGMENT, "multiline": True, "dynamicPrompts": False}),
Lexicon.PROG_VERT: ("STRING", {"default": GLSLShader.PROG_VERTEX, "multiline": True, "dynamicPrompts": False}),
Lexicon.PROG_FRAG: ("STRING", {"default": GLSLShader.PROG_FRAGMENT, "multiline": True, "dynamicPrompts": False}),
}
})
return Lexicon._parse(d, cls)
Expand All @@ -130,17 +132,18 @@ def run(self, ident, **kw) -> tuple[torch.Tensor]:
reset = parse_param(kw, Lexicon.RESET, EnumConvertType.BOOLEAN, False)[0]
wihi = parse_param(kw, Lexicon.WH, EnumConvertType.VEC2INT, [(512, 512)], MIN_IMAGE_SIZE)[0]
matte = parse_param(kw, Lexicon.MATTE, EnumConvertType.VEC4INT, [(0, 0, 0, 255)], 0, 255)[0]
fragment = parse_param(kw, Lexicon.FRAGMENT, EnumConvertType.STRING, GLSLShader.PROG_FRAGMENT)[0]
vertex_src = parse_param(kw, Lexicon.PROG_VERT, EnumConvertType.STRING, "")[0]
fragment_src = parse_param(kw, Lexicon.PROG_FRAG, EnumConvertType.STRING, "")[0]

variables = kw.copy()
for p in [Lexicon.TIME, Lexicon.BATCH, Lexicon.FPS, Lexicon.WH, Lexicon.FRAGMENT, Lexicon.WAIT, Lexicon.RESET]:
for p in [Lexicon.TIME, Lexicon.BATCH, Lexicon.FPS, Lexicon.WAIT, Lexicon.RESET, Lexicon.WH, Lexicon.MATTE, Lexicon.PROG_VERT, Lexicon.PROG_FRAG]:
variables.pop(p, None)

self.__glsl.bgcolor = matte
self.__glsl.size = wihi
self.__glsl.fps = fps
try:
self.__glsl.fragment = fragment
self.__glsl.program(vertex_src, fragment_src)
except CompileException as e:
comfy_message(ident, "jovi-glsl-error", {"id": ident, "e": str(e)})
logger.error(e)
Expand Down Expand Up @@ -168,8 +171,8 @@ def run(self, ident, **kw) -> tuple[torch.Tensor]:
images.append(cv2tensor_full(image))
if not wait:
self.__delta += step
if batch == 0:
comfy_message(ident, "jovi-glsl-time", {"id": ident, "t": self.__delta})
# if batch == 0:
comfy_message(ident, "jovi-glsl-time", {"id": ident, "t": self.__delta})
pbar.update_absolute(idx)
return [torch.cat(i, dim=0) for i in zip(*images)]

Expand Down
9 changes: 9 additions & 0 deletions res/glsl/basic.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
uniform sampler2D imageA;
uniform sampler2D imageB;

void mainImage( out vec4 fragColor, vec2 fragCoord ) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec3 col = texture2D(imageA, uv).rgb;
vec3 col2 = texture2D(imageB, uv).rgb;
fragColor = vec4(mix(col, col2, 0.5), 1.0);
}
6 changes: 6 additions & 0 deletions res/glsl/basic.vert
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#version 330 core
void main()
{
vec2 verts[3] = vec2[](vec2(-1, -1), vec2(3, -1), vec2(-1, 3));
gl_Position = vec4(verts[gl_VertexID], 0, 1);
}
Loading

0 comments on commit 50dc794

Please sign in to comment.