diff --git a/leenkx/blender/lnx/material/cycles.py b/leenkx/blender/lnx/material/cycles.py index f5c495f..2b7ec81 100644 --- a/leenkx/blender/lnx/material/cycles.py +++ b/leenkx/blender/lnx/material/cycles.py @@ -53,9 +53,69 @@ else: # Particle info export particle_info: Dict[str, bool] = {} +texture_resize_cache = {} + state: Optional[ParserState] +def resize_texture_if_needed(image: bpy.types.Image, filepath: str, max_size: int) -> str: + """ + Resize texture if it exceeds max_size. Returns path to resized texture or original. + Caches results to avoid re-processing unchanged textures. + """ + if max_size <= 0: + return filepath + + if image.size[0] <= max_size and image.size[1] <= max_size: + return filepath + + cache_key = (filepath, max_size, 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 + new_height = int((height / width) * max_size) + 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', 'resized_textures') + os.makedirs(resized_dir, exist_ok=True) + + basename = os.path.basename(filepath) + name, ext = os.path.splitext(basename) + resized_path = os.path.join(resized_dir, f"{name}_{max_size}px{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: + print(f"Using cached: {basename} -> {new_width}x{new_height}") + texture_resize_cache[cache_key] = resized_path + return resized_path + try: + from PIL import Image as PILImage + img = PILImage.open(filepath) + img_resized = img.resize((new_width, new_height), PILImage.Resampling.LANCZOS) + img_resized.save(resized_path, quality=95, optimize=True) + print(f"Resized: {basename} {width}x{height} -> {new_width}x{new_height}") + texture_resize_cache[cache_key] = resized_path + return resized_path + except ImportError: + print(f"WARNING: PIL/Pillow not installed. Install with: pip install Pillow") + print(f"Skipping resize for: {basename}") + return filepath + except Exception as e: + print(f"WARNING: Failed to resize {basename}: {e}") + return filepath + + + + def parse(nodes, con: ShaderContext, vert: Shader, frag: Shader, geom: Shader, tesc: Shader, tese: Shader, parse_surface=True, parse_opacity=True, parse_displacement=True, basecol_only=False): @@ -897,6 +957,11 @@ def make_texture( lnx.utils.convert_image(image, converted_path, file_format=fmt) lnx.assets.add(converted_path) else: + wrd = bpy.data.worlds['Lnx'] + max_size = int(wrd.lnx_max_texture_size) + if max_size > 0 and image is not None: + filepath = resize_texture_if_needed(image, filepath, max_size) + # Link image path to assets # TODO: Khamake converts .PNG to .jpg? Convert ext to lowercase on windows if lnx.utils.get_os() == 'win':