Repe [T3DU] Update - 31f26d171bba0355ce2a77031e3aad4c64dbc7e9

This commit is contained in:
2026-09-04 10:46:13 -07:00
parent c915312901
commit 0460b9d587
482 changed files with 27797 additions and 3226 deletions

View File

@ -64,6 +64,25 @@ if lnx.is_reload(__name__):
else:
lnx.enable_reload(__name__)
class LnxInstancedAttr(bpy.types.PropertyGroup):
name: bpy.props.StringProperty()
size: bpy.props.IntProperty(min=1, max=4, default=1)
class LNX_OT_AddInstancedAttr(bpy.types.Operator):
bl_idname = "lnx.add_instanced_attr"
bl_label = ""
def execute(self, context):
context.object.lnx_instanced_attrs.add()
return {'FINISHED'}
class LNX_OT_DelInstancedAttr(bpy.types.Operator):
bl_idname = "lnx.del_instanced_attr"
bl_label = ""
idx: bpy.props.IntProperty()
def execute(self, context):
context.object.lnx_instanced_attrs.remove(self.idx)
return {'FINISHED'}
class LNX_PT_ObjectPropsPanel(bpy.types.Panel):
"""Menu in object region."""
bl_label = "Leenkx Props"
@ -88,10 +107,25 @@ class LNX_PT_ObjectPropsPanel(bpy.types.Panel):
col.prop(obj, 'lnx_spawn')
col.prop(obj, 'lnx_mobile')
col.prop(obj, 'lnx_animation_enabled')
col.prop(obj, 'lnx_visible_shadow')
sub = col.column()
sub.enabled = False
sub.prop(obj, 'lnx_visible_shadow')
if obj.type == 'MESH':
layout.prop(obj, 'lnx_instanced')
if 'Rot' in obj.lnx_instanced:
layout.prop(obj, 'lnx_instanced_rot_type')
if obj.lnx_instanced != 'Off':
box = layout.box()
box.label(text="Instanced Attributes (must start with i)")
for i, item in enumerate(obj.lnx_instanced_attrs):
row = box.row()
row.prop(item, "name", text="")
row.prop(item, "size", text="")
op = row.operator("lnx.del_instanced_attr", icon='X', text="")
op.idx = i
box.operator("lnx.add_instanced_attr", icon='ADD')
# Properties list
lnx.props_properties.draw_properties(layout, obj)
@ -285,8 +319,16 @@ class LNX_PT_PhysicsPropsPanel(bpy.types.Panel):
layout.prop(obj, 'lnx_rb_ccd')
layout.prop(obj, 'lnx_rb_interpolate')
if obj.soft_body is not None:
is_cloth = any(m.type == 'CLOTH' for m in obj.modifiers)
if obj.soft_body is not None or is_cloth:
layout.prop(obj, 'lnx_soft_body_margin')
if is_cloth:
layout.prop(obj, 'lnx_soft_body_friction')
layout.prop(obj, 'lnx_soft_body_damping')
layout.prop(obj, 'lnx_soft_body_linear_stiffness')
layout.prop(obj, 'lnx_soft_body_angular_stiffness')
layout.prop(obj, 'lnx_soft_body_pressure')
if obj.rigid_body_constraint is not None:
layout.prop(obj, 'lnx_relative_physics_constraint')
@ -342,6 +384,9 @@ class LNX_PT_DataPropsPanel(bpy.types.Panel):
elif obj.type == 'MESH' or obj.type == 'FONT' or obj.type == 'META':
layout.prop(obj.data, 'lnx_dynamic_usage')
layout.operator("lnx.invalidate_cache")
elif obj.type == 'CURVE':
layout.prop(obj.data, 'lnx_draw_strength')
layout.prop(obj.data, 'lnx_draw_color')
elif obj.type == 'LIGHT':
layout.prop(obj.data, 'lnx_clip_start')
layout.prop(obj.data, 'lnx_clip_end')
@ -405,6 +450,8 @@ class LNX_PT_ScenePropsPanel(bpy.types.Panel):
row = layout.row()
column = row.column()
row.prop(scene, 'lnx_export')
lnx.props_properties.draw_properties(layout, scene)
class InvalidateCacheButton(bpy.types.Operator):
"""Delete cached mesh data"""
@ -711,6 +758,12 @@ class LNX_PT_MaterialPropsPanel(bpy.types.Panel):
layout.prop(mat, 'lnx_depth_read')
layout.prop(mat, 'lnx_overlay')
layout.prop(mat, 'lnx_decal')
columnb = layout.column()
columnb.enabled = lnx.utils.get_rp().rp_renderer == 'Forward'
columnb.prop(mat, 'lnx_solid')
columnc = columnb.column()
columnc.enabled = mat.lnx_solid
columnc.prop(mat, 'lnx_solid_factor')
layout.prop(mat, 'lnx_discard')
columnb = layout.column()
columnb.enabled = mat.lnx_discard
@ -958,8 +1011,14 @@ class LNX_PT_LeenkxExporterPanel(bpy.types.Panel):
col.prop(wrd, 'lnx_no_traces')
col = column_with_heading(layout, 'Data', align=True)
col.prop(wrd, 'lnx_minimize')
col.prop(wrd, 'lnx_optimize_data')
sub = col.column()
sub.enabled = False
sub.prop(wrd, 'lnx_minimize')
col.prop(wrd, 'lnx_export_debug_json')
sub = col.column()
sub.enabled = False
sub.prop(wrd, 'lnx_optimize_data')
col.prop(wrd, 'lnx_asset_compression')
col.prop(wrd, 'lnx_single_data_file')
@ -1807,7 +1866,7 @@ class LNX_PT_RenderPathShadowsPanel(bpy.types.Panel):
col = colatlas_single.row()
col.alignment = 'RIGHT'
col.label(text=f'Enough space for { point_lights } point lights or { spot_lights } spot lights or { dir_lights } directional lights.')
col.label(text=f'Enough space for { point_lights } point lights or { spot_lights } spot lights or { dir_lights } directional lights (limit 1 sun light per scene).')
else:
# show size for all types
colatlas_mixed = colatlas.column()
@ -2090,6 +2149,43 @@ class LNX_PT_RenderPathPostProcessPanel(bpy.types.Panel):
if rpdat.lnx_chromatic_aberration_type == "Spectral":
col.prop(rpdat, 'lnx_chromatic_aberration_samples')
class LNX_OT_EditCustomCompositor(bpy.types.Operator):
bl_idname = 'lnx.edit_custom_compositor'
bl_label = 'Edit'
bl_options = {'INTERNAL'}
file_name: bpy.props.StringProperty()
def execute(self, context):
import os
target_file = os.path.join(lnx.utils.get_fp(), 'Compositor', self.file_name)
lnx.utils.open_editor(target_file)
return {'FINISHED'}
def init_custom_compositor():
import os
import shutil
fp = lnx.utils.get_fp()
if fp == "":
return
custom_dir = os.path.join(fp, 'Compositor')
if not os.path.exists(custom_dir):
os.makedirs(custom_dir)
sdk_path = lnx.utils.get_sdk_path()
source_dir = os.path.join(sdk_path, 'leenkx', 'Shaders', 'compositor_pass')
files = ['compositor_pass.json', 'compositor_pass.frag.glsl', 'compositor_pass.vert.glsl']
for f in files:
target = os.path.join(custom_dir, f)
if not os.path.exists(target):
source = os.path.join(source_dir, f)
if os.path.exists(source):
shutil.copy(source, target)
class LNX_PT_RenderPathCompositorPanel(bpy.types.Panel):
bl_label = "Compositor"
bl_space_type = "PROPERTIES"
@ -2115,6 +2211,18 @@ class LNX_PT_RenderPathCompositorPanel(bpy.types.Panel):
rpdat = wrd.lnx_rplist[wrd.lnx_rplist_index]
layout.enabled = rpdat.rp_compositornodes
if rpdat.lnx_custom_compositor:
init_custom_compositor()
row_custom = layout.row(align=True)
row_custom.prop(rpdat, 'lnx_custom_compositor', text="Custom")
sub = row_custom.row(align=True)
sub.enabled = rpdat.lnx_custom_compositor
sub.operator("lnx.edit_custom_compositor", icon='EDITMODE_HLT', text="Frag").file_name = "compositor_pass.frag.glsl"
sub.operator("lnx.edit_custom_compositor", icon='FILE_TEXT', text="Json").file_name = "compositor_pass.json"
layout.separator()
layout.prop(rpdat, 'lnx_tonemap')
layout.prop(rpdat, 'lnx_dithering')
if rpdat.lnx_dithering != 'Off':
@ -2164,7 +2272,7 @@ class LNX_PT_RenderPathCompositorPanel(bpy.types.Panel):
layout.separator()
col = layout.column()
col.prop(rpdat, 'lnx_fisheye')
draw_conditional_prop(col, 'Fish Eye', rpdat, 'lnx_fisheye', 'lnx_fisheye_strength')
col.prop(rpdat, 'lnx_lensflare')
layout.separator()
@ -2461,10 +2569,8 @@ class LnxPrintTraitsButton(bpy.types.Operator):
for s in bpy.data.scenes:
print('Scene: {0}'.format(s.name))
for t in s.lnx_traitlist:
if not t.enabled_prop:
continue
tname = "undefined"
if t.type_prop == 'Haxe Script' or "Bundled":
if t.type_prop in ('Haxe Script', 'Bundled Script'):
tname = t.class_name_prop
if t.type_prop == 'Logic Nodes':
tname = t.node_tree_prop.name
@ -2472,13 +2578,13 @@ class LnxPrintTraitsButton(bpy.types.Operator):
tname = t.canvas_name_prop
if t.type_prop == 'WebAssembly':
tname = t.webassembly_prop
print('Scene Trait: {0} ("{1}")'.format(s.name, tname))
status = "" if t.enabled_prop else "[D]"
fake_user = "[FU]" if t.fake_user else ""
print(' Scene Trait: {0} ("{1}") {2} {3}'.format(s.name, tname, status, fake_user))
for o in s.objects:
for t in o.lnx_traitlist:
if not t.enabled_prop:
continue
tname = "undefined"
if t.type_prop == 'Haxe Script' or "Bundled":
if t.type_prop in ('Haxe Script', 'Bundled Script'):
tname = t.class_name_prop
if t.type_prop == 'Logic Nodes':
tname = t.node_tree_prop.name
@ -2486,7 +2592,9 @@ class LnxPrintTraitsButton(bpy.types.Operator):
tname = t.canvas_name_prop
if t.type_prop == 'WebAssembly':
tname = t.webassembly_prop
print(' Object Trait: {0} ("{1}")'.format(o.name, tname))
status = "" if t.enabled_prop else "[D]"
fake_user = "[FU]" if t.fake_user else ""
print(' Object Trait: {0} ("{1}") {2} {3}'.format(o.name, tname, status, fake_user))
return{'FINISHED'}
class LNX_PT_MaterialNodePanel(bpy.types.Panel):
@ -2961,6 +3069,9 @@ def draw_multiline_with_icon(layout: bpy.types.UILayout, layout_width_px: int, i
__REG_CLASSES = (
LnxInstancedAttr,
LNX_OT_AddInstancedAttr,
LNX_OT_DelInstancedAttr,
LNX_PT_ObjectPropsPanel,
LNX_PT_ModifiersPropsPanel,
LNX_PT_ParticlesPropsPanel,
@ -3002,6 +3113,7 @@ __REG_CLASSES = (
LNX_PT_RenderPathWorldPanel,
LNX_PT_RenderPathPostProcessPanel,
LNX_PT_RenderPathCompositorPanel,
LNX_OT_EditCustomCompositor,
LNX_PT_BakePanel,
# LnxVirtualInputPanel,
LeenkxPlayButton,
@ -3051,6 +3163,8 @@ def register():
bpy.types.Material.lnx_bind_textures_list = CollectionProperty(type=LNX_PG_BindTexturesListItem)
bpy.types.Material.lnx_bind_textures_list_index = IntProperty(name='Index for lnx_bind_textures_list', default=0)
bpy.types.Object.lnx_instanced_attrs = bpy.props.CollectionProperty(type=LnxInstancedAttr)
def unregister():
bpy.types.NODE_MT_context_menu.remove(draw_custom_node_menu)