From d0337f5daebe51f49518911b634e615ffb0b4f49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mois=C3=A9s=20Pel=C3=A1ez?= Date: Thu, 17 Sep 2026 15:59:45 -0400 Subject: [PATCH] Fix thinWall and passes --- leenkx/Sources/iron/RenderPath.hx | 4 +- leenkx/Sources/iron/data/ShaderData.hx | 1 + leenkx/blender/lnx/make.py | 4 +- leenkx/blender/lnx/make_renderpath.py | 7 ++-- leenkx/blender/lnx/material/cycles.py | 52 +++++++++++++++----------- leenkx/blender/lnx/material/make.py | 6 ++- leenkx/blender/lnx/material/shader.py | 19 +++++++--- 7 files changed, 60 insertions(+), 33 deletions(-) diff --git a/leenkx/Sources/iron/RenderPath.hx b/leenkx/Sources/iron/RenderPath.hx index ecb4de90..704826d8 100644 --- a/leenkx/Sources/iron/RenderPath.hx +++ b/leenkx/Sources/iron/RenderPath.hx @@ -908,7 +908,9 @@ class RenderPath { #end Data.getShader(shaderPath[0], shaderPath[1], function(res: ShaderData) { - cc.context = res.getContext(shaderPath[2]); + if (res != null) { + cc.context = res.getContext(shaderPath[2]); + } loading--; }); } diff --git a/leenkx/Sources/iron/data/ShaderData.hx b/leenkx/Sources/iron/data/ShaderData.hx index 0eaa68ab..3bcbc8e4 100644 --- a/leenkx/Sources/iron/data/ShaderData.hx +++ b/leenkx/Sources/iron/data/ShaderData.hx @@ -55,6 +55,7 @@ class ShaderData { if (raw == null) { trace('Shader data "$name" not found!'); done(null); + return; } new ShaderData(raw, done, overrideContext); }); diff --git a/leenkx/blender/lnx/make.py b/leenkx/blender/lnx/make.py index f6730036..9d8bd846 100644 --- a/leenkx/blender/lnx/make.py +++ b/leenkx/blender/lnx/make.py @@ -384,7 +384,8 @@ def export_data_impl(fp, sdk_path): os.utime(g, None) # Write referenced shader passes - if not os.path.isfile(build_dir + '/compiled/Shaders/shader_datas.lnx') or state.last_world_defs != wrd.world_defs: + current_passes = tuple(sorted(assets.shader_passes)) + if not os.path.isfile(build_dir + '/compiled/Shaders/shader_datas.lnx') or state.last_world_defs != wrd.world_defs or getattr(state, 'last_shader_passes', None) != current_passes: res = {'shader_datas': []} for ref in assets.shader_passes: @@ -431,6 +432,7 @@ def export_data_impl(fp, sdk_path): if not os.path.exists(target): shutil.copy(file, target) state.last_world_defs = wrd.world_defs + state.last_shader_passes = current_passes # Reset path os.chdir(fp) diff --git a/leenkx/blender/lnx/make_renderpath.py b/leenkx/blender/lnx/make_renderpath.py index 6eee2aca..74d6b4ff 100644 --- a/leenkx/blender/lnx/make_renderpath.py +++ b/leenkx/blender/lnx/make_renderpath.py @@ -236,6 +236,8 @@ def build(): if rpdat.rp_renderer == 'Deferred': assets.add_shader_pass('copy_pass') + elif rpdat.rp_renderer == 'Forward' and not rpdat.rp_compositornodes: + assets.add_shader_pass('copy_pass') assets.add_shader_pass('blend_pass') assets.add_shader_pass('add_pass') @@ -243,9 +245,6 @@ def build(): if rpdat.rp_render_to_texture: assets.add_khafile_def('rp_render_to_texture') - if rpdat.rp_renderer == 'Forward' and not rpdat.rp_compositornodes: - assets.add_shader_pass('copy_pass') - if rpdat.rp_compositornodes: assets.add_khafile_def('rp_compositornodes') compo_depth = False @@ -341,6 +340,8 @@ def build(): wrd.world_defs += '_FSR1_{0}'.format(rpdat.rp_fsr1) assets.add_shader_pass('fsr1_easu_pass') assets.add_shader_pass('fsr1_rcas_pass') + if rpdat.rp_renderer == 'Forward': + assets.add_shader_pass('copy_pass') if rpdat.rp_ssao: assets.add_khafile_def('rp_ssao') diff --git a/leenkx/blender/lnx/material/cycles.py b/leenkx/blender/lnx/material/cycles.py index 0867ab39..54bc1c3d 100644 --- a/leenkx/blender/lnx/material/cycles.py +++ b/leenkx/blender/lnx/material/cycles.py @@ -67,19 +67,19 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in """ if max_size <= 0: return filepath - + if image.size[0] <= max_size and image.size[1] <= max_size: return filepath - + wrd = bpy.data.worlds['Lnx'] texture_quality = wrd.lnx_texture_quality - + cache_key = (filepath, max_size, texture_quality, os.path.getmtime(filepath) if os.path.exists(filepath) else 0) if cache_key in texture_resize_cache: cached_path = texture_resize_cache[cache_key] if os.path.exists(cached_path): return cached_path - + width, height = image.size[0], image.size[1] if width > height: new_width = max_size @@ -87,55 +87,55 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in else: new_height = max_size new_width = int((width / height) * max_size) - + build_dir = lnx.utils.get_fp_build() resized_dir = os.path.join(build_dir, 'compiled', 'Assets', 'unpacked') os.makedirs(resized_dir, exist_ok=True) - + basename = os.path.basename(filepath) name, ext = os.path.splitext(basename) quality_suffix = f"q{int(texture_quality * 100)}" resized_path = os.path.join(resized_dir, f"{name}_{max_size}px_{quality_suffix}{ext}") - + if os.path.exists(resized_path): src_mtime = os.path.getmtime(filepath) dst_mtime = os.path.getmtime(resized_path) if dst_mtime >= src_mtime: texture_resize_cache[cache_key] = resized_path return resized_path - + try: ffmpeg_path = lnx.utils.get_ffmpeg_path() - + if ffmpeg_path is None or ffmpeg_path == '': print(f"[Texture Optimizer] WARNING: FFmpeg not found. Please set FFmpeg path in addon preferences.") print(f"[Texture Optimizer] Skipping resize for: {basename}") return filepath - + file_ext = os.path.splitext(filepath)[1].lower().lstrip('.') - + cmd = [ ffmpeg_path, - '-y', + '-y', '-i', filepath, '-vf', f'scale={new_width}:{new_height}:flags=lanczos', ] - + if file_ext in ('png', 'tga', 'bmp'): compression_level = round((1.0 - texture_quality) * 9) cmd.extend(['-compression_level', str(compression_level)]) else: qscale = round(2 + (1.0 - texture_quality) * 29) cmd.extend(['-q:v', str(qscale)]) - + cmd.append(resized_path) - + startupinfo = None - if os.name == 'nt': + if os.name == 'nt': startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE - + result = subprocess.run( cmd, stdout=subprocess.PIPE, @@ -143,7 +143,7 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in startupinfo=startupinfo, timeout=60 ) - + if result.returncode == 0 and os.path.exists(resized_path): print(f"[Texture Optimizer] Resized: {basename} {width}x{height} -> {new_width}x{new_height}") texture_resize_cache[cache_key] = resized_path @@ -152,7 +152,7 @@ def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: in error_msg = result.stderr.decode('utf-8', errors='ignore') if result.stderr else 'Unknown error' print(f"[Texture Optimizer] WARNING: FFmpeg failed to resize {basename}: {error_msg}") return filepath - + except subprocess.TimeoutExpired: print(f"[Texture Optimizer] WARNING: FFmpeg timeout while resizing {basename}") return filepath @@ -641,7 +641,7 @@ def parse_normal_map_color_input(inp, strength_input=None, space='TANGENT'): state.normal_parsed = True frag.write_normal += 1 - + color_val = parse_vector_input(inp) strength = parse_value_input(strength_input) if strength_input is not None else '1.0' @@ -660,7 +660,7 @@ def parse_normal_map_color_input(inp, strength_input=None, space='TANGENT'): frag.write(f'texn.xy *= {strength};') frag.write('n = normalize(TBN * texn);') state.con.add_elem('tang', 'short4norm') - + elif space in ['OBJECT', 'BLENDER_OBJECT']: frag.add_uniform('mat3 N', '_normalMatrix') frag.write(f'vec3 objn = ({color_val}) * 2.0 - 1.0;') @@ -693,6 +693,8 @@ def parse_value_input(inp: bpy.types.NodeSocket) -> floatstr: return rgb_to_bw(res_var) elif socket_type in ('VALUE', 'INT'): return res_var + elif socket_type == 'BOOLEAN': + return f'({res_var} ? 1.0 : 0.0)' else: log.warn(f'Node tree "{tree_name()}": socket "{link.from_socket.name}" of node "{link.from_node.name}" cannot be connected to a scalar value socket') return '0.0' @@ -990,6 +992,12 @@ def dfdy_fine(val: str) -> str: def to_vec1(v): + if isinstance(v, bool): + return '1.0' if v else '0.0' + if v == 'False': + return '0.0' + if v == 'True': + return '1.0' return str(v) @@ -1177,7 +1185,7 @@ def make_texture( if filepath != original_filepath: resized_filename = lnx.utils.extract_filename(filepath) tex['file'] = lnx.utils.safestr(resized_filename) - + # Link image path to assets # TODO: Khamake converts .PNG to .jpg? Convert ext to lowercase on windows if lnx.utils.get_os() == 'win': diff --git a/leenkx/blender/lnx/material/make.py b/leenkx/blender/lnx/material/make.py index 5ab27330..d43ae298 100644 --- a/leenkx/blender/lnx/material/make.py +++ b/leenkx/blender/lnx/material/make.py @@ -149,6 +149,10 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]], if val_str is None: return None val_str = str(val_str).strip() + if val_str in ('True', 'true'): + return 1.0 + if val_str in ('False', 'false'): + return 0.0 try: return float(val_str) except (ValueError, TypeError): @@ -296,7 +300,7 @@ def parse(material: Material, mat_data, mat_users: Dict[Material, List[Object]], elif rp == 'translucent' or rp == 'refraction': c['bind_constants'].append({'name': 'receiveShadow', 'boolValue': material.lnx_receive_shadow}) - + elif rp == 'shadowmap': if wrd.lnx_batch_materials: if len(c['bind_textures']) > 0: diff --git a/leenkx/blender/lnx/material/shader.py b/leenkx/blender/lnx/material/shader.py index db8c656b..37364f69 100644 --- a/leenkx/blender/lnx/material/shader.py +++ b/leenkx/blender/lnx/material/shader.py @@ -99,12 +99,12 @@ class ShaderContext: def sort_vs(self): vs = [] ar = ['pos', 'nor', 'tex', 'tex1', 'morph', 'col', 'tang', 'bone', 'weight', 'ipos', 'irot', 'iscl'] - + if 'vertex_elements' in self.data: for elem in self.data['vertex_elements']: if elem['name'] not in ar: ar.append(elem['name']) - + for ename in ar: elem = self.get_elem(ename) if elem != None: @@ -137,6 +137,15 @@ class ShaderContext: if default_value is not None: if ctype == 'float': c['floatValue'] = default_value + if isinstance(default_value, bool): + c['floatValue'] = 1.0 if default_value else 0.0 + elif isinstance(default_value, (int, float)): + c['floatValue'] = float(default_value) + else: + try: + c['floatValue'] = float(default_value) + except (ValueError, TypeError): + c['floatValue'] = default_value if ctype == 'vec3': c['vec3Value'] = default_value if is_lnx_mat_param is not None: @@ -418,11 +427,11 @@ class Shader: def validate(self): import re issues = [] - + # Check for duplicate variable declarations in main_attribs var_pattern = re.compile(r'\b(vec[234]|float|int|mat[234])\s+(\w+)\s*[;=]') declared_vars = {} - + for line in self.main_attribs.split('\n'): match = var_pattern.search(line) if match: @@ -431,7 +440,7 @@ class Shader: issues.append(f"Duplicate variable declaration: '{var_name}' (type: {var_type})") else: declared_vars[var_name] = var_type - + return issues def get(self):