merge upstream

This commit is contained in:
2025-06-13 15:18:22 +00:00
10 changed files with 263 additions and 0 deletions

View File

@ -783,6 +783,11 @@ class Scene {
if (o.tilesheet_ref != null) {
cast(object, MeshObject).setupTilesheet(sceneName, o.tilesheet_ref, o.tilesheet_action_ref);
}
if (o.camera_list != null){
cast(object, MeshObject).cameraList = o.camera_list;
}
returnObject(object, o, done);
});
}

View File

@ -441,6 +441,7 @@ typedef TObj = {
@:optional public var traits: Array<TTrait>;
@:optional public var properties: Array<TProperty>;
@:optional public var vertex_groups: Array<TVertex_groups>;
@:optional public var camera_list: Array<String>;
@:optional public var constraints: Array<TConstraint>;
@:optional public var dimensions: Float32Array; // Geometry objects
@:optional public var object_actions: Array<String>;

View File

@ -24,6 +24,7 @@ class MeshObject extends Object {
public var render_emitter = true;
#end
public var cameraDistance: Float;
public var cameraList: Array<String> = null;
public var screenSize = 0.0;
public var frustumCulling = true;
public var activeTilesheet: Tilesheet = null;
@ -235,6 +236,8 @@ class MeshObject extends Object {
if (cullMesh(context, Scene.active.camera, RenderPath.active.light)) return;
var meshContext = raw != null ? context == "mesh" : false;
if (cameraList != null && cameraList.indexOf(Scene.active.camera.name) < 0) return;
#if lnx_particles
if (raw != null && raw.is_particle && particleOwner == null) return; // Instancing not yet set-up by particle system owner
if (particleSystems != null && meshContext) {
@ -245,6 +248,7 @@ class MeshObject extends Object {
Scene.active.spawnObject(psys.data.raw.instance_object, null, function(o: Object) {
if (o != null) {
var c: MeshObject = cast o;
c.cameraList = this.cameraList;
particleChildren.push(c);
c.particleOwner = this;
c.particleIndex = particleChildren.length - 1;

View File

@ -0,0 +1,19 @@
package leenkx.logicnode;
import iron.object.MeshObject;
import iron.object.CameraObject;
class GetCameraRenderFilterNode extends LogicNode {
public function new(tree: LogicTree) {
super(tree);
}
override function get(from: Int): Dynamic {
var mo: MeshObject = cast inputs[0].get();
if (mo == null) return null;
return mo.cameraList;
}
}

View File

@ -0,0 +1,38 @@
package leenkx.logicnode;
import iron.object.MeshObject;
import iron.object.CameraObject;
class SetCameraRenderFilterNode extends LogicNode {
public var property0: String;
public function new(tree: LogicTree) {
super(tree);
}
override function run(from: Int) {
var mo: MeshObject = cast inputs[1].get();
var camera: CameraObject = inputs[2].get();
assert(Error, Std.isOfType(camera, CameraObject), "Camera must be a camera object!");
if (camera == null || mo == null) return;
if (property0 == 'Add'){
if (mo.cameraList == null || mo.cameraList.indexOf(camera.name) == -1){
if (mo.cameraList == null) mo.cameraList = [];
mo.cameraList.push(camera.name);
}
}
else{
if (mo.cameraList != null){
mo.cameraList.remove(camera.name);
if (mo.cameraList.length == 0)
mo.cameraList = null;
}
}
runOutput(0);
}
}

View File

@ -835,6 +835,13 @@ class LeenkxExporter:
}
out_object['vertex_groups'].append(out_vertex_groups)
if len(bobject.lnx_camera_list) > 0:
out_camera_list = []
for camera in bobject.lnx_camera_list:
if camera.lnx_camera_object_ptr != None:
out_camera_list.append(camera.lnx_camera_object_ptr.name)
if len(out_camera_list) > 0:
out_object['camera_list'] = out_camera_list
if len(bobject.lnx_propertylist) > 0:
out_object['properties'] = []

View File

@ -0,0 +1,15 @@
from lnx.logicnode.lnx_nodes import *
class GetCameraRenderFilterNode(LnxLogicTreeNode):
"""
Gets Camera Render Filter array with the names of the cameras
that can render the mesh. If null all cameras can render the mesh.
"""
bl_idname = 'LNGetCameraRenderFilterNode'
bl_label = 'Get Object Camera Render Filter'
lnx_section = 'camera'
lnx_version = 1
def lnx_init(self, context):
self.add_input('LnxNodeSocketObject', 'Object')
self.add_output('LnxNodeSocketArray', 'Array')

View File

@ -0,0 +1,29 @@
from lnx.logicnode.lnx_nodes import *
class SetCameraRenderFilterNode(LnxLogicTreeNode):
"""
Sets Camera Render Filter array with the names of the cameras
that can render the mesh. If null all cameras can render the mesh.
A camera can be added or removed from the arraw list.
"""
bl_idname = 'LNSetCameraRenderFilterNode'
bl_label = 'Set Object Camera Render Filter'
lnx_section = 'camera'
lnx_version = 1
property0: HaxeEnumProperty(
'property0',
items = [('Add', 'Add', 'Add'),
('Remove', 'Remove', 'Remove')],
name='', default='Add', update='')
def lnx_init(self, context):
self.add_input('LnxNodeSocketAction', 'In')
self.add_input('LnxNodeSocketObject', 'Object')
self.add_input('LnxNodeSocketObject', 'Camera')
self.add_output('LnxNodeSocketAction', 'Out')
def draw_buttons(self, context, layout):
layout.prop(self, 'property0')

View File

@ -0,0 +1,141 @@
import bpy
from bpy.props import *
class LNX_UL_CameraList(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
layout.prop_search(item, "lnx_camera_object_ptr", bpy.data, "objects", text="", icon='VIEW_CAMERA')
class LNX_CameraListItem(bpy.types.PropertyGroup):
lnx_camera_object_ptr: bpy.props.PointerProperty(
type=bpy.types.Object,
name="Camera Object",
poll=lambda self, obj_to_check: obj_to_check.type == 'CAMERA' and \
(bpy.context.object is None or \
not hasattr(bpy.context.object, 'lnx_camera_list') or \
(obj_to_check.name not in [
item.lnx_camera_object_ptr.name
for item in bpy.context.object.lnx_camera_list
if item.lnx_camera_object_ptr and item != self
]))
)
class LNX_PT_LeenkxCameraRenderFilter(bpy.types.Panel):
bl_label = "Leenkx Camera Render Filter"
bl_idname = "LNX_PT_LeenkxCameraRenderFilter"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data"
@classmethod
def poll(cls, context):
return context.object is not None and context.object.type == 'MESH'
def draw(self, context):
layout = self.layout
obj = context.object
row = layout.row()
col = row.column()
col.template_list(
"LNX_UL_CameraList",
"",
obj,
"lnx_camera_list",
obj,
"lnx_active_camera_index",
rows=5
)
col = row.column(align=True)
col.operator("lnx.add_camera", icon='ADD', text="")
if obj.lnx_camera_list and obj.lnx_active_camera_index >= 0 and obj.lnx_active_camera_index < len(obj.lnx_camera_list):
op_remove = col.operator("lnx.remove_camera", icon='REMOVE', text="")
op_remove.lnx_index = obj.lnx_active_camera_index
op_up = col.operator("lnx.move_camera", icon='TRIA_UP', text="")
op_up.lnx_index = obj.lnx_active_camera_index
op_up.direction = 'UP'
op_down = col.operator("lnx.move_camera", icon='TRIA_DOWN', text="")
op_down.lnx_index = obj.lnx_active_camera_index
op_down.direction = 'DOWN'
class LNX_OT_AddCamera(bpy.types.Operator):
bl_idname = "lnx.add_camera"
bl_label = "Add Camera"
def execute(self, context):
obj = context.object
new_item = obj.lnx_camera_list.add()
obj.lnx_active_camera_index = len(obj.lnx_camera_list) - 1
return {'FINISHED'}
class LNX_OT_RemoveCamera(bpy.types.Operator):
bl_idname = "lnx.remove_camera"
bl_label = "Remove Camera"
lnx_index: bpy.props.IntProperty()
def execute(self, context):
obj = context.object
if self.lnx_index < len(obj.lnx_camera_list):
obj.lnx_camera_list.remove(self.lnx_index)
if obj.lnx_active_camera_index >= len(obj.lnx_camera_list):
obj.lnx_active_camera_index = len(obj.lnx_camera_list) - 1
return {'FINISHED'}
class LNX_OT_MoveCamera(bpy.types.Operator):
bl_idname = "lnx.move_camera"
bl_label = "Move Camera"
lnx_index: bpy.props.IntProperty()
direction: bpy.props.EnumProperty(
items=[('UP', "Up", "Move camera up"),
('DOWN', "Down", "Move camera down")],
default='UP'
)
def execute(self, context):
obj = context.object
camera_list = obj.lnx_camera_list
target_index = -1
if self.direction == 'UP':
if self.lnx_index > 0:
target_index = self.lnx_index - 1
elif self.direction == 'DOWN':
if self.lnx_index < len(camera_list) - 1:
target_index = self.lnx_index + 1
if target_index != -1:
camera_list.move(self.lnx_index, target_index)
obj.lnx_active_camera_index = target_index
return {'FINISHED'}
def register():
bpy.utils.register_class(LNX_UL_CameraList)
bpy.utils.register_class(LNX_CameraListItem)
bpy.utils.register_class(LNX_PT_LeenkxCameraRenderFilter)
bpy.utils.register_class(LNX_OT_AddCamera)
bpy.utils.register_class(LNX_OT_RemoveCamera)
bpy.utils.register_class(LNX_OT_MoveCamera)
bpy.types.Object.lnx_camera_list = bpy.props.CollectionProperty(type=LNX_CameraListItem)
bpy.types.Object.lnx_active_camera_index = bpy.props.IntProperty(name="Active Camera Index", default=-1)
def unregister():
bpy.utils.unregister_class(LNX_UL_CameraList)
bpy.utils.unregister_class(LNX_CameraListItem)
bpy.utils.unregister_class(LNX_PT_LeenkxCameraRenderFilter)
bpy.utils.unregister_class(LNX_OT_AddCamera)
bpy.utils.unregister_class(LNX_OT_RemoveCamera)
bpy.utils.unregister_class(LNX_OT_MoveCamera)
if hasattr(bpy.types.Object, "lnx_camera_list"):
del bpy.types.Object.lnx_camera_list
if hasattr(bpy.types.Object, "lnx_active_camera_index"):
del bpy.types.Object.lnx_active_camera_index

View File

@ -16,6 +16,7 @@ import lnx.props_properties
import lnx.props_collision_filter_mask
import lnx.props
import lnx.props_ui
import lnx.props_camera_render_filter
import lnx.handlers
import lnx.utils
import lnx.keymap
@ -44,6 +45,7 @@ if lnx.is_reload(__name__):
lnx.props_collision_filter_mask = lnx.reload_module(lnx.props_collision_filter_mask)
lnx.props = lnx.reload_module(lnx.props)
lnx.props_ui = lnx.reload_module(lnx.props_ui)
lnx.props_camera_render_filter = lnx.reload_module(lnx.props_camera_render_filter)
lnx.handlers = lnx.reload_module(lnx.handlers)
lnx.utils = lnx.reload_module(lnx.utils)
lnx.keymap = lnx.reload_module(lnx.keymap)
@ -68,6 +70,7 @@ def register(local_sdk=False):
lnx.props_properties.register()
lnx.props.register()
lnx.props_ui.register()
lnx.props_camera_render_filter.register()
lnx.nodes_logic.register()
lnx.nodes_material.register()
lnx.keymap.register()
@ -100,3 +103,4 @@ def unregister():
lnx.props_renderpath.unregister()
lnx.props_properties.unregister()
lnx.props_collision_filter_mask.unregister()
lnx.props_camera_render_filter.unregister()