merge upstream

This commit is contained in:
2025-09-29 22:41:09 +00:00
63 changed files with 1944 additions and 1027 deletions

View File

@ -8,6 +8,24 @@ import mathutils
import bpy
from bpy.props import *
# Helper functions for Blender version compatibility
def get_panel_options():
"""Get panel options compatible with current Blender version."""
if bpy.app.version >= (2, 93, 0): # INSTANCED was introduced around 2.93
return {'INSTANCED'}
else:
return set() # Empty set for older versions
def column_with_heading(layout, heading='', align=False):
"""Create a column with optional heading, compatible across Blender versions."""
if bpy.app.version >= (2, 92, 0):
return layout.column(heading=heading, align=align)
else:
col = layout.column(align=align)
if heading:
col.label(text=heading)
return col
from lnx.lightmapper.panels import scene
import lnx.api
@ -63,6 +81,7 @@ class LNX_PT_ObjectPropsPanel(bpy.types.Panel):
return
col = layout.column()
col.prop(obj, 'lnx_sorting_index')
col.prop(obj, 'lnx_export')
if not obj.lnx_export:
return
@ -206,6 +225,7 @@ class LNX_PT_ParticlesPropsPanel(bpy.types.Panel):
return
layout.prop(obj.settings, 'lnx_auto_start')
layout.prop(obj.settings, 'lnx_dynamic_emitter')
layout.prop(obj.settings, 'lnx_is_unique')
layout.prop(obj.settings, 'lnx_loop')
layout.prop(obj.settings, 'lnx_count_mult')
@ -551,6 +571,51 @@ class LNX_OT_NewCustomMaterial(bpy.types.Operator):
return{'FINISHED'}
class LNX_OT_NextPassMaterialSelector(bpy.types.Operator):
"""Select material for next pass"""
bl_idname = "lnx.next_pass_material_selector"
bl_label = "Select Next Pass Material"
def execute(self, context):
return {'FINISHED'}
def invoke(self, context, event):
context.window_manager.popup_menu(self.draw_menu, title="Select Next Pass Material", icon='MATERIAL')
return {'FINISHED'}
def draw_menu(self, popup, context):
layout = popup.layout
# Add 'None' option
op = layout.operator("lnx.set_next_pass_material", text="")
op.material_name = ""
# Add materials from the current object's material slots
if context.object and hasattr(context.object, 'material_slots'):
for slot in context.object.material_slots:
if (slot.material is not None and slot.material != context.material):
op = layout.operator("lnx.set_next_pass_material", text=slot.material.name)
op.material_name = slot.material.name
class LNX_OT_SetNextPassMaterial(bpy.types.Operator):
"""Set the next pass material"""
bl_idname = "lnx.set_next_pass_material"
bl_label = "Set Next Pass Material"
material_name: StringProperty()
def execute(self, context):
if context.material:
context.material.lnx_next_pass = self.material_name
# Redraw the UI to update the display
for area in context.screen.areas:
if area.type == 'PROPERTIES':
area.tag_redraw()
return {'FINISHED'}
class LNX_PG_BindTexturesListItem(bpy.types.PropertyGroup):
uniform_name: StringProperty(
name='Uniform Name',
@ -634,18 +699,23 @@ class LNX_PT_MaterialPropsPanel(bpy.types.Panel):
mat = bpy.context.material
if mat is None:
return
layout.prop(mat, 'lnx_cast_shadow')
columnb = layout.column()
wrd = bpy.data.worlds['Lnx']
columnb.enabled = len(wrd.lnx_rplist) > 0 and lnx.utils.get_rp().rp_renderer == 'Forward'
columnb.prop(mat, 'lnx_receive_shadow')
layout.prop(mat, 'lnx_ignore_irradiance')
layout.prop(mat, 'lnx_compare_mode')
layout.prop(mat, 'lnx_two_sided')
columnb = layout.column()
columnb.enabled = not mat.lnx_two_sided
columnb.prop(mat, 'lnx_cull_mode')
row = layout.row(align=True)
row.prop(mat, 'lnx_next_pass', text="Next Pass")
row.operator('lnx.next_pass_material_selector', text='', icon='MATERIAL')
layout.prop(mat, 'lnx_material_id')
layout.prop(mat, 'lnx_depth_write')
layout.prop(mat, 'lnx_depth_read')
layout.prop(mat, 'lnx_overlay')
layout.prop(mat, 'lnx_decal')
@ -887,13 +957,13 @@ class LNX_PT_LeenkxExporterPanel(bpy.types.Panel):
col = layout.column()
col.prop(wrd, 'lnx_project_icon')
col = layout.column(heading='Code Output', align=True)
col = column_with_heading(layout, 'Code Output', align=True)
col.prop(wrd, 'lnx_dce')
col.prop(wrd, 'lnx_compiler_inline')
col.prop(wrd, 'lnx_minify_js')
col.prop(wrd, 'lnx_no_traces')
col = layout.column(heading='Data', align=True)
col = column_with_heading(layout, 'Data', align=True)
col.prop(wrd, 'lnx_minimize')
col.prop(wrd, 'lnx_optimize_data')
col.prop(wrd, 'lnx_asset_compression')
@ -1126,32 +1196,32 @@ class LNX_PT_ProjectFlagsPanel(bpy.types.Panel):
layout.use_property_decorate = False
wrd = bpy.data.worlds['Lnx']
col = layout.column(heading='Debug', align=True)
col = column_with_heading(layout, 'Debug', align=True)
col.prop(wrd, 'lnx_verbose_output')
col.prop(wrd, 'lnx_cache_build')
col.prop(wrd, 'lnx_clear_on_compile')
col.prop(wrd, 'lnx_assert_level')
col.prop(wrd, 'lnx_assert_quit')
col = layout.column(heading='Runtime', align=True)
col = column_with_heading(layout, 'Runtime', align=True)
col.prop(wrd, 'lnx_live_patch')
col.prop(wrd, 'lnx_stream_scene')
col.prop(wrd, 'lnx_loadscreen')
col.prop(wrd, 'lnx_write_config')
col = layout.column(heading='Renderer', align=True)
col = column_with_heading(layout, 'Renderer', align=True)
col.prop(wrd, 'lnx_batch_meshes')
col.prop(wrd, 'lnx_batch_materials')
col.prop(wrd, 'lnx_deinterleaved_buffers')
col.prop(wrd, 'lnx_export_tangents')
col = layout.column(heading='Quality')
col = column_with_heading(layout, 'Quality')
row = col.row() # To expand below property UI horizontally
row.prop(wrd, 'lnx_canvas_img_scaling_quality', expand=True)
col.prop(wrd, 'lnx_texture_quality')
col.prop(wrd, 'lnx_sound_quality')
col = layout.column(heading='External Assets')
col = column_with_heading(layout, 'External Assets')
col.prop(wrd, 'lnx_copy_override')
col.operator('lnx.copy_to_bundled', icon='IMAGE_DATA')
@ -1229,7 +1299,8 @@ class LNX_PT_ProjectModulesPanel(bpy.types.Panel):
layout.prop_search(wrd, 'lnx_khafile', bpy.data, 'texts')
layout.prop(wrd, 'lnx_project_root')
layout.prop(wrd, 'lnx_external_blends_path')
class LnxVirtualInputPanel(bpy.types.Panel):
bl_label = "Leenkx Virtual Input"
bl_space_type = "PROPERTIES"
@ -1464,7 +1535,7 @@ class LNX_PT_TopbarPanel(bpy.types.Panel):
bl_label = "Leenkx Player"
bl_space_type = "VIEW_3D"
bl_region_type = "WINDOW"
bl_options = {'INSTANCED'}
bl_options = get_panel_options()
def draw_header(self, context):
row = self.layout.row(align=True)
@ -2269,7 +2340,10 @@ class LnxGenTerrainButton(bpy.types.Operator):
node.location = (-200, -200)
node.inputs[0].default_value = 5.0
links.new(nodes['Bump'].inputs[2], nodes['_TerrainHeight'].outputs[0])
links.new(nodes['Principled BSDF'].inputs[20], nodes['Bump'].outputs[0])
if bpy.app.version[0] >= 4:
links.new(nodes['Principled BSDF'].inputs[22], nodes['Bump'].outputs[0])
else:
links.new(nodes['Principled BSDF'].inputs[20], nodes['Bump'].outputs[0])
# Create sectors
root_obj = bpy.data.objects.new("Terrain", None)
@ -2302,7 +2376,16 @@ class LnxGenTerrainButton(bpy.types.Operator):
disp_mod.texture.extension = 'EXTEND'
disp_mod.texture.use_interpolation = False
disp_mod.texture.use_mipmap = False
disp_mod.texture.image = bpy.data.images.load(filepath=scn.lnx_terrain_textures+'/heightmap_' + j + '.png')
try:
disp_mod.texture.image = bpy.data.images.load(filepath=scn.lnx_terrain_textures+'/heightmap_' + j + '.png')
except Exception as e:
if i == 0: # Only show message once
if scn.lnx_terrain_textures.startswith('//') and not bpy.data.filepath:
self.report({'INFO'}, "Generating terrain... Save .blend file and add your heightmaps for each sector in "
"the \"Bundled\" folder using the format \"heightmap_01.png\", \"heightmap_02.png\", etc.")
else:
self.report({'INFO'}, f"Heightmap not found: {scn.lnx_terrain_textures}/heightmap_{j}.png - using blank image")
f = 1
levels = 0
while f < disp_mod.texture.image.size[0]:
@ -2858,7 +2941,7 @@ def draw_conditional_prop(layout: bpy.types.UILayout, heading: str, data: bpy.ty
"""Draws a property row with a checkbox that enables a value field.
The function fails when prop_condition is not a boolean property.
"""
col = layout.column(heading=heading)
col = column_with_heading(layout, heading)
row = col.row()
row.prop(data, prop_condition, text='')
sub = row.row()
@ -2910,6 +2993,8 @@ __REG_CLASSES = (
InvalidateCacheButton,
InvalidateMaterialCacheButton,
LNX_OT_NewCustomMaterial,
LNX_OT_NextPassMaterialSelector,
LNX_OT_SetNextPassMaterial,
LNX_PG_BindTexturesListItem,
LNX_UL_BindTexturesList,
LNX_OT_BindTexturesListNewItem,