From 87c3a3803287e92f5ec55327077520011be20b62 Mon Sep 17 00:00:00 2001 From: "Alexander G. Morano" Date: Thu, 1 Aug 2024 01:54:37 -0700 Subject: [PATCH] multi-image support for raw raw needs widget + input no need to terminate on window close version up --- pyproject.toml | 2 +- sup/shader.py | 116 ++++++++++++++++++++++++++-------------------- web/nodes/glsl.js | 8 ++-- 3 files changed, 70 insertions(+), 56 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 2b149de..e37631f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "jovimetrix" description = "Integrates Webcam, MIDI, Spout and GLSL shader support. Animation via tick. Parameter manipulation with wave generator. Math operations with Unary and Binary support. Value conversion for all major types (int, string, list, dict, Image, Mask). Shape mask generation, image stacking and channel ops, batch splitting, merging and randomizing, load images and video from anywhere, dynamic bus routing with a single node, export support for GIPHY, save output anywhere! flatten, crop, transform; check colorblindness, make stereogram or stereoscopic images, or liner interpolate values and more." -version = "1.2.7" +version = "1.2.8" license = { file = "LICENSE" } dependencies = [ "aenum>=3.1.15, <4", diff --git a/sup/shader.py b/sup/shader.py index 48f2bf4..dd286d2 100644 --- a/sup/shader.py +++ b/sup/shader.py @@ -140,6 +140,7 @@ def __cleanup(self) -> None: if self.__window: glfw.destroy_window(self.__window) + logger.debug("cleanup") def __init_window(self, vertex:str=None, fragment:str=None, force:bool=False) -> None: glfw.window_hint(glfw.VISIBLE, glfw.FALSE) @@ -147,7 +148,11 @@ def __init_window(self, vertex:str=None, fragment:str=None, force:bool=False) -> self.__window = glfw.create_window(self.__size[0], self.__size[1], "hidden", None, None) if not self.__window: raise RuntimeError("GLFW did not init window") + + self.__init_framebuffer() self.__init_program(vertex, fragment, force) + self.__init_vars() + logger.debug("init window") def __compile_shader(self, source:str, shader_type:str) -> None: glfw.make_context_current(self.__window) @@ -190,65 +195,74 @@ def __init_program(self, vertex:str=None, fragment:str=None, force:bool=False) - logger.error(f"Program linking error: {log}") raise RuntimeError(log) - gl.glUseProgram(self.__program) + self.__source_fragment_raw = fragment + self.__source_vertex_raw = vertex + logger.debug("init program") - self.__fbo = gl.glGenFramebuffers(1) - gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.__fbo) + def __init_framebuffer(self) -> None: + glfw.make_context_current(self.__window) - self.__fbo_texture = gl.glGenTextures(1) - gl.glBindTexture(gl.GL_TEXTURE_2D, self.__fbo_texture) - glfw.set_window_size(self.__window, self.__size[0], self.__size[1]) + self.__fbo = gl.glGenFramebuffers(1) + gl.glBindFramebuffer(gl.GL_FRAMEBUFFER, self.__fbo) - gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, self.__size[0], self.__size[1], 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) - gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) - gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self.__fbo_texture, 0) + self.__fbo_texture = gl.glGenTextures(1) + gl.glBindTexture(gl.GL_TEXTURE_2D, self.__fbo_texture) + glfw.set_window_size(self.__window, self.__size[0], self.__size[1]) - gl.glViewport(0, 0, self.__size[0], self.__size[1]) + gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGBA, self.__size[0], self.__size[1], 0, gl.GL_RGBA, gl.GL_UNSIGNED_BYTE, None) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MIN_FILTER, gl.GL_LINEAR) + gl.glTexParameteri(gl.GL_TEXTURE_2D, gl.GL_TEXTURE_MAG_FILTER, gl.GL_LINEAR) + gl.glFramebufferTexture2D(gl.GL_FRAMEBUFFER, gl.GL_COLOR_ATTACHMENT0, gl.GL_TEXTURE_2D, self.__fbo_texture, 0) - self.__source_fragment_raw = fragment - self.__source_vertex_raw = vertex - self.__shaderVar = { - 'iResolution': gl.glGetUniformLocation(self.__program, "iResolution"), - 'iTime': gl.glGetUniformLocation(self.__program, "iTime"), - 'iFrameRate': gl.glGetUniformLocation(self.__program, "iFrameRate"), - 'iFrame': gl.glGetUniformLocation(self.__program, "iFrame"), - 'iMouse': gl.glGetUniformLocation(self.__program, "iMouse") - } - - if (resolution := self.__shaderVar['iResolution']) > -1: - gl.glUniform3f(resolution, self.__size[0], self.__size[1], 0) - - if (framerate := self.__shaderVar['iFrameRate']) > -1: - gl.glUniform1i(framerate, self.__fps) - - self.__userVar = {} - # read the fragment and setup the vars.... - for match in RE_VARIABLE.finditer(fragment): - typ, name, default, val_min, val_max, val_step, tooltip = match.groups() - self.__textures[name] = None - if typ in ['sampler2D']: - self.__textures[name] = gl.glGenTextures(1) - # logger.debug(f"{name}.{typ}: {default} {val_min} {val_max} {val_step} {tooltip}") - self.__userVar[name] = [ - # type - typ, - # gl location - gl.glGetUniformLocation(self.__program, name), - # default value - default, - # texture id -- if a texture - self.__textures[name] - ] - - logger.info("program compiled") + gl.glViewport(0, 0, self.__size[0], self.__size[1]) + logger.debug("init framebuffer") + + def __init_vars(self) -> None: + glfw.make_context_current(self.__window) + gl.glUseProgram(self.__program) + + self.__shaderVar = { + 'iResolution': gl.glGetUniformLocation(self.__program, "iResolution"), + 'iTime': gl.glGetUniformLocation(self.__program, "iTime"), + 'iFrameRate': gl.glGetUniformLocation(self.__program, "iFrameRate"), + 'iFrame': gl.glGetUniformLocation(self.__program, "iFrame"), + 'iMouse': gl.glGetUniformLocation(self.__program, "iMouse") + } + + if (resolution := self.__shaderVar['iResolution']) > -1: + gl.glUniform3f(resolution, self.__size[0], self.__size[1], 0) + + if (framerate := self.__shaderVar['iFrameRate']) > -1: + gl.glUniform1i(framerate, self.__fps) + + self.__userVar = {} + # read the fragment and setup the vars.... + for match in RE_VARIABLE.finditer(self.__source_fragment_raw): + typ, name, default, val_min, val_max, val_step, tooltip = match.groups() + self.__textures[name] = None + if typ in ['sampler2D']: + self.__textures[name] = gl.glGenTextures(1) + # logger.debug(f"{name}.{typ}: {default} {val_min} {val_max} {val_step} {tooltip}") + self.__userVar[name] = [ + # type + typ, + # gl location + gl.glGetUniformLocation(self.__program, name), + # default value + default, + # texture id -- if a texture + self.__textures[name] + ] + + logger.debug("init vars") def __del__(self) -> None: self.__cleanup() - if self.__window: - glfw.destroy_window(self.__window) - self.__window = None - glfw.terminate() + #if self.__window is not None: + # if glfw is not None: + # glfw.destroy_window(self.__window) + # self.__window = None + # glfw.terminate() @property def vertex(self) -> str: diff --git a/web/nodes/glsl.js b/web/nodes/glsl.js index 21ed873..f77b4d1 100644 --- a/web/nodes/glsl.js +++ b/web/nodes/glsl.js @@ -54,11 +54,11 @@ app.registerExtension({ const [full_match, varType, varName, varValue] = match; let exist = self.inputs?.find(w => w.name === varName); let type; - if (varType === 'int') { + if (varType == 'int') { type = "INT"; - } else if (varType === 'float') { + } else if (varType == 'float') { type = "FLOAT"; - } else if (varType === 'bool') { + } else if (varType == 'bool') { type = "BOOLEAN"; } else if (varType.startsWith('ivec') || varType.startsWith('vec')) { const idx = varType[varType.length - 1]; @@ -66,7 +66,7 @@ app.registerExtension({ if (varType.startsWith('ivec')) { type += 'INT'; } - } else if (varType === "sampler2D") { + } else if (varType == "sampler2D") { type = "IMAGE"; }