forked from LeenkxTeam/LNXSDK
Repe [T3DU] Update - 31f26d171bba0355ce2a77031e3aad4c64dbc7e9
This commit is contained in:
@ -64,13 +64,14 @@ class NodeType(Enum):
|
||||
SPEAKER = 5
|
||||
DECAL = 6
|
||||
PROBE = 7
|
||||
CURVE = 8
|
||||
|
||||
@classmethod
|
||||
def get_bobject_type(cls, bobject: bpy.types.Object) -> "NodeType":
|
||||
"""Returns the NodeType enum member belonging to the type of
|
||||
the given blender object."""
|
||||
if bobject.type == "MESH":
|
||||
if bobject.data.polygons or bobject.data.edges or bobject.data.vertices:
|
||||
if bobject.data.polygons: #or bobject.data.edges or bobject.data.vertices:
|
||||
return cls.MESH
|
||||
elif bobject.type in ('FONT', 'META', 'CURVE'): # FIXME: curves with meshes shouldn't be used in modifiers for now.
|
||||
if bobject.type == 'CURVE':
|
||||
@ -89,12 +90,14 @@ class NodeType(Enum):
|
||||
return cls.SPEAKER
|
||||
elif bobject.type == "LIGHT_PROBE":
|
||||
return cls.PROBE
|
||||
elif bobject.type == "CURVE":
|
||||
return cls.CURVE
|
||||
return cls.EMPTY
|
||||
|
||||
|
||||
STRUCT_IDENTIFIER = ("object", "bone_object", "mesh_object",
|
||||
"light_object", "camera_object", "speaker_object",
|
||||
"decal_object", "probe_object")
|
||||
"decal_object", "probe_object", "curve_object")
|
||||
|
||||
# Internal target names for single FCurve data paths
|
||||
FCURVE_TARGET_NAMES = {
|
||||
@ -161,6 +164,7 @@ class LeenkxExporter:
|
||||
self.bobject_array: Dict[bpy.types.Object, Dict[str, Union[NodeType, str]]] = {}
|
||||
self.bobject_bone_array = {}
|
||||
self.mesh_array = {}
|
||||
self.curve_array = {}
|
||||
self.light_array = {}
|
||||
self.probe_array = {}
|
||||
self.camera_array = {}
|
||||
@ -405,7 +409,7 @@ class LeenkxExporter:
|
||||
o['transform'] = {'values': LeenkxExporter.write_matrix(matrix_local)}
|
||||
|
||||
# Animated transform
|
||||
if bobject.animation_data is not None and bobject.type != "ARMATURE":
|
||||
if bobject.animation_data is not None and bobject.type != "ARMATURE" and bobject.lnx_animation_enabled:
|
||||
action = bobject.animation_data.action
|
||||
|
||||
if action is not None:
|
||||
@ -987,7 +991,7 @@ class LeenkxExporter:
|
||||
|
||||
out_object = self.object_to_lnx_object_dict[bobject]
|
||||
out_object['type'] = STRUCT_IDENTIFIER[object_type.value]
|
||||
out_object['name'] = bobject_ref["structName"]
|
||||
out_object['name'] = lnx.utils.safestr(bobject_ref["structName"])
|
||||
|
||||
if bobject.parent_type == "BONE":
|
||||
out_object['parent_bone'] = bobject.parent_bone
|
||||
@ -1064,7 +1068,7 @@ class LeenkxExporter:
|
||||
_num_verts = len(_verts)
|
||||
_all_co = np.empty(_num_verts * 3, dtype='<f8')
|
||||
_verts.foreach_get('co', _all_co)
|
||||
_all_str = _all_co.astype('U32').tolist()
|
||||
_all_f = _all_co.tolist()
|
||||
_num_groups = len(bobject.vertex_groups)
|
||||
_vg_idx = [[] for _ in range(_num_groups)]
|
||||
for v in _verts:
|
||||
@ -1079,9 +1083,9 @@ class LeenkxExporter:
|
||||
_values = []
|
||||
for vi in indices:
|
||||
base = vi * 3
|
||||
_values.append(_all_str[base])
|
||||
_values.append(_all_str[base + 1])
|
||||
_values.append(_all_str[base + 2])
|
||||
_values.append(_all_f[base])
|
||||
_values.append(_all_f[base + 1])
|
||||
_values.append(_all_f[base + 2])
|
||||
else:
|
||||
_values = []
|
||||
out_object['vertex_groups'].append({
|
||||
@ -1100,16 +1104,24 @@ class LeenkxExporter:
|
||||
if len(bobject.lnx_propertylist) > 0:
|
||||
out_object['properties'] = []
|
||||
for proplist_item in bobject.lnx_propertylist:
|
||||
# Check if the property is a collection (array type).
|
||||
if proplist_item.type_prop == 'array':
|
||||
# Convert the collection to a list.
|
||||
|
||||
array_type = proplist_item.array_item_type
|
||||
collection_value = getattr(proplist_item, 'array_prop')
|
||||
property_name = array_type + '_prop'
|
||||
value = [str(getattr(item, property_name)) for item in collection_value]
|
||||
|
||||
if array_type == 'vector':
|
||||
value = []
|
||||
for item in collection_value:
|
||||
v = getattr(item, property_name)
|
||||
value.append([float(v[0]), float(v[1]), float(v[2])])
|
||||
else:
|
||||
value = [getattr(item, property_name) for item in collection_value]
|
||||
|
||||
elif proplist_item.type_prop == 'vector':
|
||||
v = getattr(proplist_item, 'vector_prop')
|
||||
value = [float(v[0]), float(v[1]), float(v[2])]
|
||||
|
||||
else:
|
||||
# Handle other types of properties.
|
||||
value = getattr(proplist_item, proplist_item.type_prop + '_prop')
|
||||
|
||||
out_property = {
|
||||
@ -1163,6 +1175,9 @@ class LeenkxExporter:
|
||||
# Decal flag
|
||||
if mat is not None and mat.lnx_decal:
|
||||
out_object['type'] = 'decal_object'
|
||||
if mat is not None:
|
||||
if 'Rot' in bobject.lnx_instanced:
|
||||
mat.lnx_instanced_rot_type = bobject.lnx_instanced_rot_type
|
||||
# No material, mimic cycles and assign default
|
||||
if len(out_object['material_refs']) == 0:
|
||||
self.use_default_material(bobject, out_object)
|
||||
@ -1228,15 +1243,32 @@ class LeenkxExporter:
|
||||
self.speaker_array[objref]["objectTable"].append(bobject)
|
||||
out_object['data_ref'] = self.speaker_array[objref]["structName"]
|
||||
|
||||
elif object_type is NodeType.CURVE:
|
||||
if objref not in self.curve_array:
|
||||
self.curve_array[objref] = {"structName" : objname, "objectTable" : [bobject]}
|
||||
else:
|
||||
self.curve_array[objref]["objectTable"].append(bobject)
|
||||
out_object['data_ref'] = lnx.utils.safestr(self.curve_array[objref]["structName"])
|
||||
|
||||
out_object['material_refs'] = []
|
||||
for i in range(len(bobject.material_slots)):
|
||||
mat = self.slot_to_material(bobject, bobject.material_slots[i])
|
||||
# Export ref
|
||||
self.export_material_ref(bobject, mat, i, out_object)
|
||||
# Decal flag
|
||||
if mat is not None and mat.lnx_decal:
|
||||
out_object['type'] = 'decal_object'
|
||||
|
||||
|
||||
# Export the transform. If object is animated, then animation tracks are exported here
|
||||
if bobject.type != 'ARMATURE' and bobject.animation_data is not None:
|
||||
action = bobject.animation_data.action
|
||||
export_actions = [action]
|
||||
for track in bobject.animation_data.nla_tracks:
|
||||
if track.strips is None:
|
||||
if track.strips is None or track.mute:
|
||||
continue
|
||||
for strip in track.strips:
|
||||
if strip.action is None or strip.action in export_actions:
|
||||
if strip.action is None or strip.action in export_actions or strip.mute:
|
||||
continue
|
||||
export_actions.append(strip.action)
|
||||
orig_action = action
|
||||
@ -1265,7 +1297,7 @@ class LeenkxExporter:
|
||||
bone_translation_pose = pose_bone.tail - pose_bone.head
|
||||
out_object['parent_bone_tail_pose'] = [bone_translation_pose[0], bone_translation_pose[1], bone_translation_pose[2]]
|
||||
|
||||
if bobject.type == 'ARMATURE' and bobject.data is not None:
|
||||
if lnx.utils.get_rp().lnx_skin != 'Off' and bobject.type == 'ARMATURE' and bobject.data is not None:
|
||||
# Armature data
|
||||
bdata = bobject.data
|
||||
# Reference start action
|
||||
@ -1290,10 +1322,10 @@ class LeenkxExporter:
|
||||
# armature object to deform with
|
||||
if hasattr(adata, 'nla_tracks') and adata.nla_tracks is not None:
|
||||
for track in adata.nla_tracks:
|
||||
if track.strips is None:
|
||||
if track.strips is None or track.mute:
|
||||
continue
|
||||
for strip in track.strips:
|
||||
if strip.action is None:
|
||||
if strip.action is None or strip.mute:
|
||||
continue
|
||||
if strip.action.name == action.name:
|
||||
continue
|
||||
@ -2196,6 +2228,86 @@ class LeenkxExporter:
|
||||
except ReferenceError:
|
||||
pass
|
||||
|
||||
def export_curve(self, object_ref):
|
||||
"""Exports a single curve object."""
|
||||
table = object_ref[1]["objectTable"]
|
||||
bobject = table[0]
|
||||
curve_id = lnx.utils.safestr(object_ref[1]["structName"])
|
||||
|
||||
world = bpy.data.worlds['Lnx']
|
||||
if world.lnx_verbose_output:
|
||||
print('Exporting curve ' + lnx.utils.asset_name(bobject.data))
|
||||
|
||||
curve_data = bobject.data
|
||||
|
||||
out_curve = {
|
||||
'name': curve_id,
|
||||
'object': bobject.name,
|
||||
'splines': [],
|
||||
'strength': curve_data.lnx_draw_strength,
|
||||
'color': [curve_data.lnx_draw_color[0], curve_data.lnx_draw_color[1], curve_data.lnx_draw_color[2], curve_data.lnx_draw_color[3]]
|
||||
}
|
||||
|
||||
for spline in curve_data.splines:
|
||||
if spline.type == 'BEZIER':
|
||||
current_spline = {
|
||||
'closed': spline.use_cyclic_u,
|
||||
'resolution': spline.resolution_u,
|
||||
'points': [],
|
||||
'material_index': spline.material_index,
|
||||
}
|
||||
|
||||
for bezier_point in spline.bezier_points:
|
||||
point_data = {
|
||||
'co': [bezier_point.co.x, bezier_point.co.y, bezier_point.co.z],
|
||||
'handle_left': [bezier_point.handle_left.x, bezier_point.handle_left.y, bezier_point.handle_left.z],
|
||||
'handle_right': [bezier_point.handle_right.x, bezier_point.handle_right.y, bezier_point.handle_right.z]
|
||||
}
|
||||
current_spline['points'].append(point_data)
|
||||
|
||||
out_curve['splines'].append(current_spline)
|
||||
|
||||
active_keys = [kb for kb in bobject.data.shape_keys.key_blocks if not kb.mute] if bobject.data.shape_keys else []
|
||||
|
||||
if len(active_keys) == 0:
|
||||
temp_obj = bobject.to_mesh()
|
||||
|
||||
if len(temp_obj.polygons) > 0:
|
||||
temp_ref = [object_ref[0], {
|
||||
"objectTable": table,
|
||||
"structName": lnx.utils.safestr(curve_id)
|
||||
}]
|
||||
|
||||
self.export_mesh(temp_ref)
|
||||
|
||||
bobject.to_mesh_clear()
|
||||
else:
|
||||
out_curve['shape_keys'] = []
|
||||
for kb in bobject.data.shape_keys.key_blocks:
|
||||
key_data = {
|
||||
'name': kb.name,
|
||||
'value': kb.value,
|
||||
'points': []
|
||||
}
|
||||
for p in kb.data:
|
||||
key_data['points'].append({
|
||||
'co': p.co[:],
|
||||
'handle_left': p.handle_left[:],
|
||||
'handle_right': p.handle_right[:]
|
||||
})
|
||||
out_curve['shape_keys'].append(key_data)
|
||||
|
||||
mat_count = len(bobject.material_slots)
|
||||
if mat_count > 0:
|
||||
out_curve['material_refs'] = []
|
||||
for i in range(mat_count):
|
||||
mat = self.slot_to_material(bobject, bobject.material_slots[i])
|
||||
self.export_material_ref(bobject, mat, i, out_curve)
|
||||
|
||||
self.output['curve_datas'].append(out_curve)
|
||||
|
||||
|
||||
|
||||
def export_light(self, object_ref):
|
||||
"""Exports a single light object."""
|
||||
rpdat = lnx.utils.get_rp()
|
||||
@ -2288,11 +2400,11 @@ class LeenkxExporter:
|
||||
o = {'name': objectRef[1]["structName"]}
|
||||
bo = objectRef[0]
|
||||
|
||||
if bo.type == 'GRID':
|
||||
if bo.type in ('GRID', 'VOLUME'):
|
||||
o['type'] = 'grid'
|
||||
elif bo.type == 'PLANAR':
|
||||
elif bo.type in ('PLANAR', 'PLANE'):
|
||||
o['type'] = 'planar'
|
||||
else:
|
||||
else: # (CUBEMAP, SPHERE)
|
||||
o['type'] = 'cubemap'
|
||||
|
||||
self.output['probe_datas'].append(o)
|
||||
@ -2348,6 +2460,7 @@ class LeenkxExporter:
|
||||
if bobject.type == 'CAMERA':
|
||||
self.output['camera_ref'] = asset_name
|
||||
self.has_spawning_camera = True
|
||||
asset_name = bobject.name
|
||||
|
||||
out_collection['object_refs'].append(asset_name)
|
||||
|
||||
@ -2731,7 +2844,7 @@ class LeenkxExporter:
|
||||
'lifetime_random': psettings.lifetime_random,
|
||||
'emit_from': emit_from,
|
||||
# Velocity
|
||||
# 'normal_factor': psettings.normal_factor,
|
||||
'normal_factor': psettings.normal_factor,
|
||||
# 'tangent_factor': psettings.tangent_factor,
|
||||
# 'tangent_phase': psettings.tangent_phase,
|
||||
'object_align_factor': (
|
||||
@ -2815,20 +2928,19 @@ class LeenkxExporter:
|
||||
|
||||
def export_world(self):
|
||||
"""Exports the world of the current scene."""
|
||||
world = self.scene.world
|
||||
for world in bpy.data.worlds:
|
||||
if world is not None:
|
||||
world_name = lnx.utils.safestr(lnx.utils.asset_name(world) if world.library else world.name)
|
||||
|
||||
if world is not None:
|
||||
world_name = lnx.utils.safestr(lnx.utils.asset_name(world) if world.library else world.name)
|
||||
if world_name not in self.world_array:
|
||||
self.world_array.append(world_name)
|
||||
out_world = {'name': world_name}
|
||||
|
||||
if world_name not in self.world_array:
|
||||
self.world_array.append(world_name)
|
||||
out_world = {'name': world_name}
|
||||
self.post_export_world(world, out_world)
|
||||
self.output['world_datas'].append(out_world)
|
||||
|
||||
self.post_export_world(world, out_world)
|
||||
self.output['world_datas'].append(out_world)
|
||||
|
||||
elif lnx.utils.get_rp().rp_background == 'World':
|
||||
log.warn(f'Scene "{self.scene.name}" is missing a world, some render targets will not be cleared')
|
||||
elif lnx.utils.get_rp().rp_background == 'World':
|
||||
log.warn(f'Scene "{self.scene.name}" is missing a world, some render targets will not be cleared')
|
||||
|
||||
def export_objects(self, scene):
|
||||
"""Exports all supported blender objects.
|
||||
@ -2847,6 +2959,7 @@ class LeenkxExporter:
|
||||
self.output['light_datas'] = []
|
||||
self.output['camera_datas'] = []
|
||||
self.output['speaker_datas'] = []
|
||||
self.output['curve_datas'] = []
|
||||
|
||||
for light_ref in self.light_array.items():
|
||||
self.export_light(light_ref)
|
||||
@ -2867,6 +2980,9 @@ class LeenkxExporter:
|
||||
for lightprobe_object in self.probe_array.items():
|
||||
self.export_probe(lightprobe_object)
|
||||
|
||||
for curve_ref in self.curve_array.items():
|
||||
self.export_curve(curve_ref)
|
||||
|
||||
self.output['mesh_datas'] = []
|
||||
for mesh_ref in self.mesh_array.items():
|
||||
self.export_mesh(mesh_ref)
|
||||
@ -2896,9 +3012,9 @@ class LeenkxExporter:
|
||||
self.process_bobject(bobject)
|
||||
# Softbody needs connected triangles, use optimized
|
||||
# geometry export
|
||||
for mod in bobject.modifiers:
|
||||
"""for mod in bobject.modifiers:
|
||||
if mod.type in ('CLOTH', 'SOFT_BODY'):
|
||||
LeenkxExporter.optimize_enabled = True
|
||||
LeenkxExporter.optimize_enabled = True"""
|
||||
|
||||
self.process_skinned_meshes()
|
||||
|
||||
@ -3029,6 +3145,8 @@ class LeenkxExporter:
|
||||
|
||||
self.export_scene_traits()
|
||||
|
||||
self.export_scene_properties()
|
||||
|
||||
self.export_canvas_themes()
|
||||
|
||||
# Write embedded data references
|
||||
@ -3145,6 +3263,14 @@ class LeenkxExporter:
|
||||
instanced_type = 4
|
||||
instanced_data = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0]
|
||||
|
||||
attr_data_block = []
|
||||
for attr in bobject.lnx_instanced_attrs:
|
||||
attr_data_block.extend([0.0] * attr.size)
|
||||
instanced_data.extend(attr_data_block)
|
||||
|
||||
if lnx.utils.export_morph_targets(bobject):
|
||||
instanced_data.extend([0.0, 0.0, 0.0, 0.0])
|
||||
|
||||
for child in bobject.children:
|
||||
if not child.lnx_export or child.hide_render:
|
||||
continue
|
||||
@ -3163,6 +3289,9 @@ class LeenkxExporter:
|
||||
instanced_data.append(scale.x)
|
||||
instanced_data.append(scale.y)
|
||||
instanced_data.append(scale.z)
|
||||
instanced_data.extend(attr_data_block)
|
||||
if lnx.utils.export_morph_targets(child):
|
||||
instanced_data.extend([0.0, 0.0, 0.0, 0.0])
|
||||
break
|
||||
|
||||
# Instance render collections with same children?
|
||||
@ -3338,9 +3467,9 @@ class LeenkxExporter:
|
||||
# Phys traits
|
||||
if phys_enabled:
|
||||
for modifier in bobject.modifiers:
|
||||
if modifier.type in ('CLOTH', 'SOFT_BODY'):
|
||||
if modifier.type in ('CLOTH', 'SOFT_BODY') and modifier.show_render:
|
||||
self.add_softbody_mod(o, bobject, modifier)
|
||||
elif modifier.type == 'HOOK':
|
||||
elif modifier.type == 'HOOK' and modifier.show_render:
|
||||
self.add_hook_mod(o, bobject, modifier.object.name, modifier.vertex_group)
|
||||
|
||||
# Rigid body constraint
|
||||
@ -3392,7 +3521,7 @@ class LeenkxExporter:
|
||||
if bone:
|
||||
out_constraint['bone'] = bobject.name
|
||||
if hasattr(constraint, 'target') and constraint.target is not None:
|
||||
if constraint.type == 'COPY_LOCATION':
|
||||
if constraint.type in ('COPY_LOCATION', 'COPY_ROTATION'):
|
||||
out_constraint['target'] = constraint.target.name
|
||||
out_constraint['use_x'] = constraint.use_x
|
||||
out_constraint['use_y'] = constraint.use_y
|
||||
@ -3402,9 +3531,38 @@ class LeenkxExporter:
|
||||
out_constraint['invert_z'] = constraint.invert_z
|
||||
out_constraint['use_offset'] = constraint.use_offset
|
||||
out_constraint['influence'] = constraint.influence
|
||||
elif constraint.type in ('COPY_SCALE'):
|
||||
out_constraint['target'] = constraint.target.name
|
||||
out_constraint['use_x'] = constraint.use_x
|
||||
out_constraint['use_y'] = constraint.use_y
|
||||
out_constraint['use_z'] = constraint.use_z
|
||||
out_constraint['use_offset'] = constraint.use_offset
|
||||
out_constraint['influence'] = constraint.influence
|
||||
elif constraint.type == 'COPY_TRANSFORMS':
|
||||
out_constraint['target'] = constraint.target.name
|
||||
out_constraint['influence'] = constraint.influence
|
||||
elif constraint.type == 'CHILD_OF':
|
||||
out_constraint['target'] = constraint.target.name
|
||||
out_constraint['influence'] = constraint.influence
|
||||
elif constraint.type in ('LIMIT_LOCATION', 'LIMIT_ROTATION', 'LIMIT_SCALE'):
|
||||
if constraint.type == 'LIMIT_ROTATION':
|
||||
out_constraint['use_limit_x'] = constraint.use_limit_x
|
||||
out_constraint['use_limit_y'] = constraint.use_limit_y
|
||||
out_constraint['use_limit_z'] = constraint.use_limit_z
|
||||
else:
|
||||
out_constraint['use_min_x'] = constraint.use_min_x
|
||||
out_constraint['use_min_y'] = constraint.use_min_y
|
||||
out_constraint['use_min_z'] = constraint.use_min_z
|
||||
out_constraint['use_max_x'] = constraint.use_max_x
|
||||
out_constraint['use_max_y'] = constraint.use_max_y
|
||||
out_constraint['use_max_z'] = constraint.use_max_z
|
||||
out_constraint['min_x'] = constraint.min_x
|
||||
out_constraint['min_y'] = constraint.min_y
|
||||
out_constraint['min_z'] = constraint.min_z
|
||||
out_constraint['max_x'] = constraint.max_x
|
||||
out_constraint['max_y'] = constraint.max_y
|
||||
out_constraint['max_z'] = constraint.max_z
|
||||
out_constraint['influence'] = constraint.influence
|
||||
|
||||
o['constraints'].append(out_constraint)
|
||||
|
||||
@ -3632,6 +3790,35 @@ class LeenkxExporter:
|
||||
for out_trait in self.output['traits']:
|
||||
LeenkxExporter.import_traits.append(out_trait['class_name'])
|
||||
|
||||
def export_scene_properties(self) -> None:
|
||||
bscene = self.scene
|
||||
if len(bscene.lnx_propertylist) > 0:
|
||||
if 'properties' not in self.output:
|
||||
self.output['properties'] = []
|
||||
|
||||
for proplist_item in bscene.lnx_propertylist:
|
||||
if proplist_item.type_prop == 'array':
|
||||
array_type = proplist_item.array_item_type
|
||||
collection_value = getattr(proplist_item, 'array_prop')
|
||||
property_name = array_type + '_prop'
|
||||
|
||||
if array_type == 'vector':
|
||||
value = [[v for v in getattr(item, property_name)] for item in collection_value]
|
||||
else:
|
||||
value = [getattr(item, property_name) for item in collection_value]
|
||||
|
||||
elif proplist_item.type_prop == 'vector':
|
||||
value = [v for v in getattr(proplist_item, 'vector_prop')]
|
||||
|
||||
else:
|
||||
value = getattr(proplist_item, proplist_item.type_prop + '_prop')
|
||||
|
||||
out_property = {
|
||||
'name': proplist_item.name_prop,
|
||||
'value': value
|
||||
}
|
||||
self.output['properties'].append(out_property)
|
||||
|
||||
@staticmethod
|
||||
def export_canvas_themes():
|
||||
path_themes = os.path.join(lnx.utils.get_fp(), 'Bundled', 'canvas')
|
||||
@ -3657,16 +3844,21 @@ class LeenkxExporter:
|
||||
# ClothModifier
|
||||
if modifier.type == 'CLOTH':
|
||||
bend = modifier.settings.bending_stiffness
|
||||
friction = bobject.lnx_soft_body_friction
|
||||
damping = bobject.lnx_soft_body_damping
|
||||
soft_type = 0
|
||||
# SoftBodyModifier
|
||||
elif modifier.type == 'SOFT_BODY':
|
||||
bend = (modifier.settings.bend + 1.0) * 10
|
||||
bend = modifier.settings.bend
|
||||
friction = modifier.settings.friction
|
||||
damping = modifier.settings.goal_friction
|
||||
soft_type = 1
|
||||
else:
|
||||
# Wrong modifier type
|
||||
return
|
||||
|
||||
out_trait['parameters'] = [str(soft_type), str(bend), str(modifier.settings.mass), str(bobject.lnx_soft_body_margin)]
|
||||
out_trait['parameters'] = [str(soft_type), str(bend), str(modifier.settings.mass), str(bobject.lnx_soft_body_margin), str(friction), str(damping),
|
||||
str(bobject.lnx_soft_body_linear_stiffness), str(bobject.lnx_soft_body_angular_stiffness), str(bobject.lnx_soft_body_pressure)]
|
||||
o['traits'].append(out_trait)
|
||||
|
||||
if soft_type == 0:
|
||||
|
||||
@ -214,7 +214,7 @@ def export_mesh_data(self, export_mesh: bpy.types.Mesh, bobject: bpy.types.Objec
|
||||
# Scale for packed coords
|
||||
maxdim = max(bobject.data.lnx_aabb[0], max(bobject.data.lnx_aabb[1], bobject.data.lnx_aabb[2]))
|
||||
if maxdim > 2:
|
||||
o['scale_pos'] = maxdim / 2
|
||||
o['scale_pos'] = maxdim / 1 if bpy.app.version >= (4, 1, 0) else 2
|
||||
else:
|
||||
o['scale_pos'] = 1.0
|
||||
if has_armature: # Allow up to 2x bigger bounds for skinned mesh
|
||||
|
||||
@ -228,7 +228,7 @@ context_screen = None
|
||||
@persistent
|
||||
def on_save_pre(context):
|
||||
# Ensure that files are saved with the correct version number
|
||||
# (e.g. startup files with an "Arm" world may have old version numbers)
|
||||
# (e.g. startup files with an "Lnx" world may have old version numbers)
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
wrd.lnx_version = props.lnx_version
|
||||
wrd.lnx_commit = props.lnx_commit
|
||||
|
||||
@ -29,8 +29,9 @@ def register():
|
||||
if not lnx_start:
|
||||
kmw = keyconfig.keymaps.new(name='Window', space_type='EMPTY', region_type="WINDOW")
|
||||
kmw.keymap_items.new(props_ui.LeenkxPlayButton.bl_idname, type='F5', value='PRESS')
|
||||
kmw.keymap_items.new('tlm.build_lightmaps', type='F6', value='PRESS')
|
||||
kmw.keymap_items.new('tlm.clean_lightmaps', type='F7', value='PRESS')
|
||||
kmw.keymap_items.new(props_ui.LeenkxCleanProjectButton.bl_idname, type='F6', value='PRESS')
|
||||
#kmw.keymap_items.new('tlm.build_lightmaps', type='F6', value='PRESS')
|
||||
#kmw.keymap_items.new('tlm.clean_lightmaps', type='F7', value='PRESS')
|
||||
kmn = keyconfig.keymaps.new(name='Node Editor', space_type='NODE_EDITOR')
|
||||
kmn.keymap_items.new('lnx.add_call_group_node', 'G', 'PRESS', shift=True)
|
||||
kmn.keymap_items.new('lnx.add_group_tree_from_selected', 'G', 'PRESS', ctrl=True)
|
||||
@ -44,8 +45,9 @@ def register():
|
||||
def unregister():
|
||||
kmw = bpy.context.window_manager.keyconfigs.user.keymaps.get('Window')
|
||||
kmw.keymap_items.remove(kmw.keymap_items[props_ui.LeenkxPlayButton.bl_idname])
|
||||
kmw.keymap_items.remove(kmw.keymap_items['tlm.build_lightmaps'])
|
||||
kmw.keymap_items.remove(kmw.keymap_items['tlm.clean_lightmaps'])
|
||||
kmw.keymap_items.remove(kmw.keymap_items[props_ui.LeenkxCleanProjectButton.bl_idname])
|
||||
#kmw.keymap_items.remove(kmw.keymap_items['tlm.build_lightmaps'])
|
||||
#kmw.keymap_items.remove(kmw.keymap_items['tlm.clean_lightmaps'])
|
||||
kmn = bpy.context.window_manager.keyconfigs.user.keymaps.get('Node Editor')
|
||||
kmn.keymap_items.remove(kmn.keymap_items['lnx.add_call_group_node'])
|
||||
kmn.keymap_items.remove(kmn.keymap_items['lnx.add_group_tree_from_selected'])
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import os
|
||||
import bpy
|
||||
from typing import List, Dict, Optional, Any
|
||||
|
||||
import lnx.utils
|
||||
@ -11,6 +13,14 @@ def parse_context(
|
||||
vert: Optional[List[str]] = None,
|
||||
frag: Optional[List[str]] = None,
|
||||
):
|
||||
if c["name"] == "compositor_pass":
|
||||
wrd = bpy.data.worlds['Lnx']
|
||||
rpdat = wrd.lnx_rplist[wrd.lnx_rplist_index]
|
||||
if rpdat.lnx_custom_compositor:
|
||||
custom_path = lnx.utils.get_fp().replace("\\", "/") + "/Compositor"
|
||||
c["vertex_shader"] = custom_path + "/compositor_pass.vert.glsl"
|
||||
c["fragment_shader"] = custom_path + "/compositor_pass.frag.glsl"
|
||||
|
||||
con = {
|
||||
"name": c["name"],
|
||||
"constants": [],
|
||||
@ -233,6 +243,8 @@ def parse_shader(
|
||||
const = {"type": ctype, "name": cid}
|
||||
con["constants"].append(const)
|
||||
|
||||
#print(f"file: {c.get('vertex_shader', 'Unknown')} | Constant: {cid} ({ctype})")
|
||||
|
||||
check_link(c, defs, cid, const)
|
||||
|
||||
|
||||
|
||||
@ -43,6 +43,7 @@ def init_categories():
|
||||
lnx_nodes.add_category('Light', icon='LIGHT', section="data")
|
||||
lnx_nodes.add_category('World', icon='WORLD', section="data")
|
||||
lnx_nodes.add_category('Object', icon='OBJECT_DATA', section="data")
|
||||
lnx_nodes.add_category('Curve', icon='IPO_EASE_IN_OUT', section="data")
|
||||
lnx_nodes.add_category('Scene', icon='SCENE_DATA', section="data")
|
||||
lnx_nodes.add_category('Trait', icon='NODETREE', section="data")
|
||||
lnx_nodes.add_category('Network', icon='WORLD', section="data")
|
||||
|
||||
13
leenkx/blender/lnx/logicnode/animation/LN_get_actions.py
Normal file
13
leenkx/blender/lnx/logicnode/animation/LN_get_actions.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AnimationNode(LnxLogicTreeNode):
|
||||
"""Returns the actions list of the given object."""
|
||||
bl_idname = 'LNAnimationNode'
|
||||
bl_label = 'Get Actions'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Actions', is_var=False)
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
@ -0,0 +1,18 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class AsyncArrayLoopNode(LnxLogicTreeNode):
|
||||
"""Loops through each item of the given array."""
|
||||
bl_idname = 'LNAsyncArrayLoopNode'
|
||||
bl_label = 'Async Array Loop'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketArray', 'Array')
|
||||
self.add_input('LnxIntSocket', 'Async Items')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Loop')
|
||||
self.add_output('LnxDynamicSocket', 'Value')
|
||||
self.add_output('LnxIntSocket', 'Index')
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
||||
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetCameraProjectionNode(LnxLogicTreeNode):
|
||||
"""Sets the projection of the given camera."""
|
||||
bl_idname = 'LNSetCameraProjectionNode'
|
||||
bl_label = 'Set Camera Projection'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Camera')
|
||||
self.add_input('LnxIntSocket', 'Width')
|
||||
self.add_input('LnxIntSocket', 'Height')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
@ -13,9 +13,9 @@ class SetCameraStartEndNode(LnxLogicTreeNode):
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Start':
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
if self.property0 == 'End':
|
||||
elif self.property0 == 'End':
|
||||
self.add_input('LnxFloatSocket', 'End')
|
||||
if self.property0 == 'Start&End':
|
||||
elif self.property0 == 'Start&End':
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
self.add_input('LnxFloatSocket', 'End')
|
||||
|
||||
|
||||
60
leenkx/blender/lnx/logicnode/camera/LN_set_screen_cameras.py
Normal file
60
leenkx/blender/lnx/logicnode/camera/LN_set_screen_cameras.py
Normal file
@ -0,0 +1,60 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetScreenCamerasNode(LnxLogicTreeNode):
|
||||
"""Renders the scene from the view of specified cameras.
|
||||
|
||||
@input Start: Evaluate the inputs and start drawing the camera render targets.
|
||||
@input Stop: Stops the rendering and drawing of the camera render targets.
|
||||
@input Camera: The camera from which to render.
|
||||
@input X/Y: Position where the camera's render target is drawn, in pixels from the top left corner.
|
||||
@input Width/Height: Size of the camera's render target in pixels.
|
||||
|
||||
@output On Start: Activated after the `Start` input has been activated.
|
||||
@output On Stop: Activated after the `Stop` input has been activated.
|
||||
"""
|
||||
bl_idname = 'LNSetScreenCamerasNode'
|
||||
bl_label = 'Set Screen Cameras'
|
||||
lnx_version = 1
|
||||
min_inputs = 7
|
||||
|
||||
num_choices: IntProperty(default=0, min=0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(SetScreenCamerasNode, self).__init__(*args, **kwargs)
|
||||
array_nodes[str(id(self))] = self
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Start')
|
||||
self.add_input('LnxNodeSocketAction', 'Stop')
|
||||
self.add_sockets()
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'On Start')
|
||||
self.add_output('LnxNodeSocketAction', 'On Stop')
|
||||
|
||||
def add_sockets(self):
|
||||
self.num_choices += 1
|
||||
self.add_input('LnxNodeSocketObject', 'Camera ' + str(self.num_choices))
|
||||
self.add_input('LnxIntSocket', 'X')
|
||||
self.add_input('LnxIntSocket', 'Y')
|
||||
self.add_input('LnxIntSocket', 'Width')
|
||||
self.add_input('LnxIntSocket', 'Height')
|
||||
|
||||
def remove_sockets(self):
|
||||
if self.num_choices > 1:
|
||||
for _ in range(5):
|
||||
self.inputs.remove(self.inputs.values()[-1])
|
||||
self.num_choices -= 1
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_call_func', text='Add Camera', icon='PLUS', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'add_sockets'
|
||||
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_call_func', text='', icon='X', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'remove_sockets'
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
17
leenkx/blender/lnx/logicnode/curve/LN_along_curve.py
Normal file
17
leenkx/blender/lnx/logicnode/curve/LN_along_curve.py
Normal file
@ -0,0 +1,17 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AlongCurveNode(LnxLogicTreeNode):
|
||||
"""Sets an object along a curve."""
|
||||
bl_idname = 'LNAlongCurveNode'
|
||||
bl_label = 'Along Curve'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxIntSocket', 'Spline Index')
|
||||
self.add_input('LnxStringSocket', 'Forward Axis', default_value = 'X')
|
||||
self.add_input('LnxFloatSocket', 'Position')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
18
leenkx/blender/lnx/logicnode/curve/LN_deform_curve.py
Normal file
18
leenkx/blender/lnx/logicnode/curve/LN_deform_curve.py
Normal file
@ -0,0 +1,18 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class DeformCurveNode(LnxLogicTreeNode):
|
||||
"""Sets an object to deform using a curve."""
|
||||
bl_idname = 'LNDeformCurveNode'
|
||||
bl_label = 'Deform Curve'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxIntSocket', 'Spline Index')
|
||||
self.add_input('LnxStringSocket', 'Forward Axis', default_value = 'X')
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
self.add_input('LnxFloatSocket', 'End', default_value = 1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
22
leenkx/blender/lnx/logicnode/curve/LN_follow_curve.py
Normal file
22
leenkx/blender/lnx/logicnode/curve/LN_follow_curve.py
Normal file
@ -0,0 +1,22 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class FollowCurveNode(LnxLogicTreeNode):
|
||||
"""Sets an object to follow a curve."""
|
||||
bl_idname = 'LNFollowCurveNode'
|
||||
bl_label = 'Follow Curve'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxIntSocket', 'Spline Index')
|
||||
self.add_input('LnxStringSocket', 'Forward Axis', default_value = 'X')
|
||||
self.add_input('LnxFloatSocket', 'Speed')
|
||||
self.add_input('LnxBoolSocket', 'Forward', default_value = True)
|
||||
self.add_input('LnxBoolSocket', 'Cyclic')
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketAction', 'Cycle')
|
||||
self.add_output('LnxFloatSocket', 'Progress')
|
||||
18
leenkx/blender/lnx/logicnode/curve/LN_get_curve_data.py
Normal file
18
leenkx/blender/lnx/logicnode/curve/LN_get_curve_data.py
Normal file
@ -0,0 +1,18 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetCurveDataNode(LnxLogicTreeNode):
|
||||
"""Gets curve data."""
|
||||
bl_idname = 'LNGetCurveDataNode'
|
||||
bl_label = 'Get Curve Data'
|
||||
lnx_section = 'get'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
|
||||
self.add_output('LnxIntSocket', 'Splines Length')
|
||||
self.add_output('LnxIntSocket', 'Equidistant Samples')
|
||||
self.add_output('LnxBoolSocket', 'Draw')
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
self.add_output('LnxNodeSocketObject', 'Curve Mesh')
|
||||
16
leenkx/blender/lnx/logicnode/curve/LN_get_curve_spline.py
Normal file
16
leenkx/blender/lnx/logicnode/curve/LN_get_curve_spline.py
Normal file
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetCurveSplineNode(LnxLogicTreeNode):
|
||||
"""Gets curve spline."""
|
||||
bl_idname = 'LNGetCurveSplineNode'
|
||||
bl_label = 'Get Curve Spline'
|
||||
lnx_section = 'get'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxIntSocket', 'Spline Index')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Points')
|
||||
self.add_output('LnxBoolSocket', 'Closed')
|
||||
self.add_output('LnxIntSocket', 'Resolution')
|
||||
38
leenkx/blender/lnx/logicnode/curve/LN_set_curve_data.py
Normal file
38
leenkx/blender/lnx/logicnode/curve/LN_set_curve_data.py
Normal file
@ -0,0 +1,38 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetCurveDataNode(LnxLogicTreeNode):
|
||||
"""Sets curve data."""
|
||||
bl_idname = 'LNSetCurveDataNode'
|
||||
bl_label = 'Set Curve Data'
|
||||
lnx_section = 'set'
|
||||
lnx_version = 1
|
||||
|
||||
def update_sockets(self, context):
|
||||
while len(self.inputs) > 2:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Equidistant Samples':
|
||||
self.add_input('LnxIntSocket', 'Equidistant Samples')
|
||||
elif self.property0 == 'Strength':
|
||||
self.add_input('LnxFloatSocket', 'Strength')
|
||||
elif self.property0 == 'Color':
|
||||
self.add_input('LnxColorSocket', 'Color')
|
||||
else:
|
||||
self.add_input('LnxIntSocket', 'Resolution', default_value = 12)
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Equidistant Samples', 'Equidistant Samples', 'Equidistant Samples'),
|
||||
('Resolution', 'Resolution', 'Resolution'),
|
||||
('Strength', 'Strength', 'Strength'),
|
||||
('Color', 'Color', 'Color')],
|
||||
name='', default='Equidistant Samples', update=update_sockets)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxIntSocket', 'Equidistant Samples')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
52
leenkx/blender/lnx/logicnode/curve/LN_set_curve_mesh.py
Normal file
52
leenkx/blender/lnx/logicnode/curve/LN_set_curve_mesh.py
Normal file
@ -0,0 +1,52 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetCurveMeshNode(LnxLogicTreeNode):
|
||||
"""Sets curve mesh."""
|
||||
bl_idname = 'LNSetCurveMeshNode'
|
||||
bl_label = 'Set Curve Mesh'
|
||||
lnx_section = 'set'
|
||||
lnx_version = 1
|
||||
|
||||
def update_sockets(self, context):
|
||||
while len(self.inputs) > 2:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Extrude':
|
||||
self.add_input('LnxFloatSocket', 'Width', default_value = 0.1)
|
||||
self.add_input('LnxFloatSocket', 'Thickness')
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
self.add_input('LnxFloatSocket', 'End', default_value = 1.0)
|
||||
self.add_input('LnxBoolSocket', 'Fill Caps')
|
||||
elif self.property0 == 'Bevel':
|
||||
self.add_input('LnxFloatSocket', 'Depth', default_value = 0.1)
|
||||
self.add_input('LnxIntSocket', 'Resolution')
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
self.add_input('LnxFloatSocket', 'End', default_value = 1.0)
|
||||
self.add_input('LnxBoolSocket', 'Fill Caps')
|
||||
else:
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Forward Axis', default_value = 'X')
|
||||
self.add_input('LnxIntSocket', 'Repetitions', default_value = 1)
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
self.add_input('LnxFloatSocket', 'End', default_value = 1.0)
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Extrude', 'Extrude', 'Extrude'),
|
||||
('Bevel', 'Bevel', 'Bevel'),
|
||||
('Deform', 'Deform', 'Deform')],
|
||||
name='', default='Extrude', update=update_sockets)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxFloatSocket', 'Width', default_value = 0.1)
|
||||
self.add_input('LnxFloatSocket', 'Thickness')
|
||||
self.add_input('LnxFloatSocket', 'Start')
|
||||
self.add_input('LnxFloatSocket', 'End', default_value = 1.0)
|
||||
self.add_input('LnxBoolSocket', 'Fill Caps')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketObject', 'Curve Mesh')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
16
leenkx/blender/lnx/logicnode/curve/LN_set_curve_shape_key.py
Normal file
16
leenkx/blender/lnx/logicnode/curve/LN_set_curve_shape_key.py
Normal file
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetCurveShapeKeyNode(LnxLogicTreeNode):
|
||||
"""Sets shape key value of the curve"""
|
||||
bl_idname = 'LNSetCurveShapeKeyNode'
|
||||
bl_label = 'Set Curve Shape Key'
|
||||
lnx_section = 'set'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxStringSocket', 'Shape Key')
|
||||
self.add_input('LnxFloatSocket', 'Value')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
17
leenkx/blender/lnx/logicnode/curve/LN_set_curve_spline.py
Normal file
17
leenkx/blender/lnx/logicnode/curve/LN_set_curve_spline.py
Normal file
@ -0,0 +1,17 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetCurveSplineNode(LnxLogicTreeNode):
|
||||
"""Sets curve spline."""
|
||||
bl_idname = 'LNSetCurveSplineNode'
|
||||
bl_label = 'Set Curve Spline'
|
||||
lnx_section = 'set'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Curve')
|
||||
self.add_input('LnxIntSocket', 'Spline Index')
|
||||
self.add_input('LnxBoolSocket', 'Closed')
|
||||
self.add_input('LnxIntSocket', 'Resolution', default_value = 12)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
3
leenkx/blender/lnx/logicnode/curve/__init__.py
Normal file
3
leenkx/blender/lnx/logicnode/curve/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
from lnx.logicnode.lnx_nodes import add_node_section
|
||||
|
||||
add_node_section(name='default', category='curve')
|
||||
@ -16,53 +16,22 @@ class DrawCameraNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNDrawCameraNode'
|
||||
bl_label = 'Draw Camera'
|
||||
lnx_section = 'draw'
|
||||
lnx_version = 2
|
||||
min_inputs = 7
|
||||
lnx_version = 4
|
||||
|
||||
num_choices: IntProperty(default=0, min=0)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(DrawCameraNode, self).__init__(*args, **kwargs)
|
||||
array_nodes[str(id(self))] = self
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Start')
|
||||
self.add_input('LnxNodeSocketAction', 'Stop')
|
||||
self.add_sockets()
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'On Start')
|
||||
self.add_output('LnxNodeSocketAction', 'On Stop')
|
||||
|
||||
def add_sockets(self):
|
||||
self.num_choices += 1
|
||||
self.add_input('LnxNodeSocketObject', 'Camera ' + str(self.num_choices))
|
||||
self.add_input('LnxIntSocket', 'X')
|
||||
self.add_input('LnxIntSocket', 'Y')
|
||||
self.add_input('LnxIntSocket', 'Width')
|
||||
self.add_input('LnxIntSocket', 'Height')
|
||||
self.add_input('LnxBoolSocket', 'Paused')
|
||||
|
||||
def remove_sockets(self):
|
||||
if self.num_choices > 1:
|
||||
for _ in range(5):
|
||||
self.inputs.remove(self.inputs.values()[-1])
|
||||
self.num_choices -= 1
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
row = layout.row(align=True)
|
||||
|
||||
op = row.operator('lnx.node_call_func', text='Add Camera', icon='PLUS', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'add_sockets'
|
||||
|
||||
column = row.column(align=True)
|
||||
op = column.operator('lnx.node_call_func', text='', icon='X', emboss=True)
|
||||
op.node_index = str(id(self))
|
||||
op.callback_name = 'remove_sockets'
|
||||
if len(self.inputs) == self.min_inputs:
|
||||
column.enabled = False
|
||||
self.add_output('LnxNodeSocketAction', 'On Start')
|
||||
self.add_output('LnxNodeSocketAction', 'On Stop')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
||||
|
||||
49
leenkx/blender/lnx/logicnode/draw/LN_draw_gif.py
Normal file
49
leenkx/blender/lnx/logicnode/draw/LN_draw_gif.py
Normal file
@ -0,0 +1,49 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class DrawGifNode(LnxLogicTreeNode):
|
||||
"""Draws an image.
|
||||
|
||||
@input Draw: Activate to draw the image on this frame. The input must
|
||||
@input In:
|
||||
be (indirectly) called from an `On Render2D` node.
|
||||
@input Image: The filename of the image.
|
||||
@input Color: The color that the image's pixels are multiplied with.
|
||||
@input Left/Center/Right: Horizontal anchor point of the image.
|
||||
0 = Left, 1 = Center, 2 = Right
|
||||
@input Top/Middle/Bottom: Vertical anchor point of the image.
|
||||
0 = Top, 1 = Middle, 2 = Bottom
|
||||
@input X/Y: Position of the anchor point in pixels.
|
||||
@input Width/Height: Size of the image in pixels.
|
||||
@input Angle: Rotation angle in radians. Image will be rotated cloclwiswe
|
||||
at the anchor point.
|
||||
|
||||
@output Out: Activated after the image has been drawn.
|
||||
|
||||
@see [`kha.graphics2.Graphics.drawImage()`](http://kha.tech/api/kha/graphics2/Graphics.html#drawImage).
|
||||
"""
|
||||
bl_idname = 'LNDrawGifNode'
|
||||
bl_label = 'Draw Gif'
|
||||
lnx_section = 'draw'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Draw')
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxStringSocket', 'Image File')
|
||||
self.add_input('LnxColorSocket', 'Color', default_value=[1.0, 1.0, 1.0, 1.0])
|
||||
self.add_input('LnxIntSocket', '0/1/2 = Left/Center/Right', default_value=0)
|
||||
self.add_input('LnxIntSocket', '0/1/2 = Top/Middle/Bottom', default_value=0)
|
||||
self.add_input('LnxFloatSocket', 'X')
|
||||
self.add_input('LnxFloatSocket', 'Y')
|
||||
self.add_input('LnxFloatSocket', 'Width')
|
||||
self.add_input('LnxFloatSocket', 'Height')
|
||||
self.add_input('LnxFloatSocket', 'Angle')
|
||||
self.add_input('LnxIntSocket', 'Start Index')
|
||||
self.add_input('LnxIntSocket', 'End Index', default_value=-1)
|
||||
self.add_input('LnxFloatSocket', 'Frame Duration', default_value=1.0)
|
||||
self.add_input('LnxBoolSocket', 'Loop', default_value=True)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxIntSocket', 'Total Frames')
|
||||
self.add_output('LnxIntSocket', 'Index')
|
||||
@ -50,5 +50,6 @@ class DrawImageRenderNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxFloatSocket', 'sHeight')
|
||||
self.add_input('LnxFloatSocket', 'Angle')
|
||||
self.add_input('LnxBoolSocket', 'Render2D')
|
||||
self.add_input('LnxBoolSocket', 'Continuous')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
@ -27,6 +27,20 @@ class DrawStringNode(LnxLogicTreeNode):
|
||||
lnx_section = 'draw'
|
||||
lnx_version = 3
|
||||
|
||||
property1: HaxeEnumProperty(
|
||||
'property1',
|
||||
items = [('TextLeft', 'Hor. Align. Left', 'Hor. Align. Left'),
|
||||
('TextCenter', 'Hor. Align. Center', 'Hor. Align. Center'),
|
||||
('TextRight', 'Hor. Align. Right', 'Hor. Align. Right'),],
|
||||
name='', default='TextLeft')
|
||||
|
||||
property2: HaxeEnumProperty(
|
||||
'property2',
|
||||
items = [('TextTop', 'Ver. Align. Top', 'Ver. Align. Top'),
|
||||
('TextMiddle', 'Ver. Align. Middle', 'Ver. Align. Middle'),
|
||||
('TextBottom', 'Ver. Align. Bottom', 'Ver. Align. Bottom'),],
|
||||
name='', default='TextTop')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Draw')
|
||||
self.add_input('LnxStringSocket', 'String')
|
||||
@ -41,6 +55,10 @@ class DrawStringNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxFloatSocket', 'Width')
|
||||
self.add_output('LnxFloatSocket', 'Height')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property1')
|
||||
layout.prop(self, 'property2')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1, 2):
|
||||
raise LookupError()
|
||||
|
||||
17
leenkx/blender/lnx/logicnode/draw/LN_reorder_render2D.py
Normal file
17
leenkx/blender/lnx/logicnode/draw/LN_reorder_render2D.py
Normal file
@ -0,0 +1,17 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class ReorderRender2DNode(LnxLogicTreeNode):
|
||||
|
||||
bl_idname = 'LNReorderRender2DNode'
|
||||
bl_label = 'Reorder Render2D'
|
||||
lnx_section = 'draw'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxDynamicSocket', 'Render2D')
|
||||
self.add_input('LnxIntSocket', 'Index')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxIntSocket', 'Index')
|
||||
@ -8,7 +8,18 @@ class OnRender2DNode(LnxLogicTreeNode):
|
||||
"""
|
||||
bl_idname = 'LNOnRender2DNode'
|
||||
bl_label = 'On Render2D'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxIntSocket', 'Index')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxDynamicSocket', 'Render2D')
|
||||
self.add_output('LnxIntSocket', 'Index', default_value = -1)
|
||||
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
||||
|
||||
@ -4,6 +4,7 @@ class GetGamepadStartedNode(LnxLogicTreeNode):
|
||||
"""."""
|
||||
bl_idname = 'LNGetGamepadStartedNode'
|
||||
bl_label = 'Get Gamepad Started'
|
||||
lnx_section = 'gamepad'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
45
leenkx/blender/lnx/logicnode/input/LN_get_image_color.py
Normal file
45
leenkx/blender/lnx/logicnode/input/LN_get_image_color.py
Normal file
@ -0,0 +1,45 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class GetImageColorNode(LnxLogicTreeNode):
|
||||
"""Gets Color of the pixel in X,Y position of: input Image, Render, Render2D and Render+Render2D.
|
||||
|
||||
@input X: pixel position regarding width.
|
||||
@input Y: pixel position regarding height.
|
||||
|
||||
@output Color: Color of the pixel in X,Y position.
|
||||
|
||||
WARNING: Calling getPixels() on a renderTarget with non-standard non-POT dimensions
|
||||
can cause a system crash. Ensure renderTarget resolution is a power of two
|
||||
(e.g., 256x256) or a common standard resolution (e.g., 1920x1080).
|
||||
|
||||
"""
|
||||
bl_idname = 'LNGetImageColorNode'
|
||||
bl_label = 'Get Image Color'
|
||||
lnx_section = 'image'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 0:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 == 'Image':
|
||||
self.add_input('LnxStringSocket', 'Image')
|
||||
self.add_input('LnxIntSocket', 'X')
|
||||
self.add_input('LnxIntSocket', 'Y')
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Image', 'Image', 'Image'),
|
||||
('Render2D', 'Render2D', 'Render2D'),
|
||||
('Render', 'Render', 'Render'),
|
||||
('Render&Render2D', 'Render&Render2D', 'Render&Render2D')],
|
||||
name='', default='Image', update=remove_extra_inputs)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxStringSocket', 'Image')
|
||||
self.add_input('LnxIntSocket', 'X')
|
||||
self.add_input('LnxIntSocket', 'Y')
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
30
leenkx/blender/lnx/logicnode/input/LN_get_keyboard.py
Normal file
30
leenkx/blender/lnx/logicnode/input/LN_get_keyboard.py
Normal file
@ -0,0 +1,30 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetKeyboardNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNGetKeyboardNode'
|
||||
bl_label = 'Get Keyboard'
|
||||
lnx_section = 'keyboard'
|
||||
lnx_version = 1
|
||||
|
||||
def update(self):
|
||||
self.label = f'{self.bl_label}: {self.property0}'
|
||||
|
||||
def upd(self, context):
|
||||
self.label = f'{self.bl_label}: {self.property0}'
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('started', 'Started', 'The keyboard button starts to be pressed'),
|
||||
('down', 'Down', 'The keyboard button is pressed'),
|
||||
('released', 'Released', 'The keyboard button stops being pressed')],
|
||||
name='', default='started', update=upd)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxStringSocket', 'Key')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def draw_label(self) -> str:
|
||||
return f'{self.bl_label}: {self.property0}'
|
||||
@ -4,6 +4,7 @@ class GetKeyboardStartedNode(LnxLogicTreeNode):
|
||||
"""."""
|
||||
bl_idname = 'LNGetKeyboardStartedNode'
|
||||
bl_label = 'Get Keyboard Started'
|
||||
lnx_section = 'keyboard'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -5,6 +5,7 @@ class GetMouseStartedNode(LnxLogicTreeNode):
|
||||
"""."""
|
||||
bl_idname = 'LNGetMouseStartedNode'
|
||||
bl_label = 'Get Mouse Started'
|
||||
lnx_section = 'mouse'
|
||||
lnx_version = 2
|
||||
|
||||
property0: HaxeBoolProperty(
|
||||
|
||||
@ -19,7 +19,7 @@ class KeyboardNode(LnxLogicTreeNode):
|
||||
items = [('started', 'Started', 'The keyboard button starts to be pressed'),
|
||||
('down', 'Down', 'The keyboard button is pressed'),
|
||||
('released', 'Released', 'The keyboard button stops being pressed')],
|
||||
name='', default='down', update=upd)
|
||||
name='', default='started', update=upd)
|
||||
|
||||
property1: HaxeEnumProperty(
|
||||
'property1',
|
||||
|
||||
@ -26,7 +26,7 @@ class MouseNode(LnxLogicTreeNode):
|
||||
('down', 'Down', 'The mouse button is pressed'),
|
||||
('released', 'Released', 'The mouse button stops being pressed'),
|
||||
('moved', 'Moved', 'Moved')],
|
||||
name='', default='down', update=upd)
|
||||
name='', default='started', update=upd)
|
||||
property1: HaxeEnumProperty(
|
||||
'property1',
|
||||
items = [('left', 'Left', 'Left mouse button'),
|
||||
|
||||
26
leenkx/blender/lnx/logicnode/input/LN_set_virtual_button.py
Normal file
26
leenkx/blender/lnx/logicnode/input/LN_set_virtual_button.py
Normal file
@ -0,0 +1,26 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetVirtualButtonNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNSetVirtualButtonNode'
|
||||
bl_label = 'Set Virtual Button'
|
||||
lnx_section = 'virtual'
|
||||
lnx_version = 1
|
||||
|
||||
property0: bpy.props.EnumProperty(
|
||||
items=[('Keyboard', 'Keyboard', 'Keyboard'),
|
||||
('Mouse', 'Mouse', 'Mouse'),
|
||||
('Gamepad', 'Gamepad', 'Gamepad')],
|
||||
name='Input',
|
||||
default='Keyboard'
|
||||
)
|
||||
property1: bpy.props.StringProperty(name='Virtual Button', default='')
|
||||
property2: bpy.props.StringProperty(name='Physical Button', default='')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
layout.prop(self, 'property1')
|
||||
layout.prop(self, 'property2')
|
||||
@ -13,7 +13,7 @@ class SurfaceNode(LnxLogicTreeNode):
|
||||
('down', 'Down', 'The screen surface is touched'),
|
||||
('released', 'Released', 'The screen surface stops being touched'),
|
||||
('moved', 'Moved', 'Moved')],
|
||||
name='', default='down')
|
||||
name='', default='started')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
13
leenkx/blender/lnx/logicnode/light/LN_get_area_light_data.py
Normal file
13
leenkx/blender/lnx/logicnode/light/LN_get_area_light_data.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetAreaLightDataNode(LnxLogicTreeNode):
|
||||
"""Gets the data of the given area light."""
|
||||
bl_idname = 'LNGetAreaLightDataNode'
|
||||
bl_label = 'Get Area Light Data'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Light')
|
||||
|
||||
self.add_output('LnxFloatSocket', 'Size X')
|
||||
self.add_output('LnxFloatSocket', 'Size Y')
|
||||
15
leenkx/blender/lnx/logicnode/light/LN_get_light_data.py
Normal file
15
leenkx/blender/lnx/logicnode/light/LN_get_light_data.py
Normal file
@ -0,0 +1,15 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetLightDataNode(LnxLogicTreeNode):
|
||||
"""Get lights data info."""
|
||||
bl_idname = 'LNGetLightDataNode'
|
||||
bl_label = 'Get Light Data'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Light')
|
||||
|
||||
self.add_output('LnxIntSocket', 'Type')
|
||||
self.add_output('LnxFloatSocket', 'Strength')
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
self.add_output('LnxBoolSocket', 'Shadow')
|
||||
13
leenkx/blender/lnx/logicnode/light/LN_get_spot_light_data.py
Normal file
13
leenkx/blender/lnx/logicnode/light/LN_get_spot_light_data.py
Normal file
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetSpotLightDataNode(LnxLogicTreeNode):
|
||||
"""Gets the data of the given spot light."""
|
||||
bl_idname = 'LNGetSpotLightDataNode'
|
||||
bl_label = 'Get Spot Light Data'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Light')
|
||||
|
||||
self.add_output('LnxFloatSocket', 'Size')
|
||||
self.add_output('LnxFloatSocket', 'Blend')
|
||||
@ -286,7 +286,7 @@ class LnxRotationSocket(LnxCustomSocket):
|
||||
default_value_unit: EnumProperty(
|
||||
items=[('Deg', 'Degrees', 'Degrees'),
|
||||
('Rad', 'Radians', 'Radians')],
|
||||
name='', default='Rad',
|
||||
name='', default='Deg',
|
||||
update=on_unit_update)
|
||||
default_value_order: EnumProperty(
|
||||
items=[('XYZ','XYZ','XYZ'),
|
||||
|
||||
42
leenkx/blender/lnx/logicnode/logic/LN_async_loop.py
Normal file
42
leenkx/blender/lnx/logicnode/logic/LN_async_loop.py
Normal file
@ -0,0 +1,42 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AsyncLoopNode(LnxLogicTreeNode):
|
||||
"""Resembles a for-loop (`for (i in from...to)`) that is executed at
|
||||
once when this node is activated.
|
||||
|
||||
@seeNode While
|
||||
@seeNode Loop Break
|
||||
|
||||
@input From: The value to start the loop from (inclusive)
|
||||
@input To: The value to end the loop at (exclusive)
|
||||
|
||||
@output Loop: Active at every iteration of the loop
|
||||
@output Index: The index for the current iteration
|
||||
@output Done: Activated once when the looping is done
|
||||
"""
|
||||
bl_idname = 'LNAsyncLoopNode'
|
||||
bl_label = 'Async Loop'
|
||||
bl_description = 'Resembles a for-loop that is executed at once when this node is activated'
|
||||
lnx_section = 'flow'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxIntSocket', 'From')
|
||||
self.add_input('LnxIntSocket', 'To')
|
||||
self.add_input('LnxIntSocket', 'Async Items')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Loop')
|
||||
self.add_output('LnxIntSocket', 'Index')
|
||||
self.add_output('LnxNodeSocketAction', 'Done')
|
||||
|
||||
def draw_label(self) -> str:
|
||||
inp_from = self.inputs['From']
|
||||
inp_to = self.inputs['To']
|
||||
if inp_from.is_linked and inp_to.is_linked:
|
||||
return self.bl_label
|
||||
|
||||
val_from = 'x' if inp_from.is_linked else inp_from.default_value_raw
|
||||
val_to = 'y' if inp_to.is_linked else inp_to.default_value_raw
|
||||
|
||||
return f'{self.bl_label}: {val_from}...{val_to}'
|
||||
@ -16,7 +16,7 @@ class CallFunctionNode(LnxLogicTreeNode):
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxDynamicSocket', 'Trait/Any')
|
||||
self.add_input('LnxDynamicSocket', 'Trait')
|
||||
self.add_input('LnxStringSocket', 'Function')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
@ -22,6 +22,8 @@ class SetCameraRenderFilterNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Camera')
|
||||
self.add_input('LnxBoolSocket', 'Children', default_value=True)
|
||||
self.add_input('LnxBoolSocket', 'Recursive', default_value=False)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetMaterialImageParamNode(LnxLogicTreeNode):
|
||||
"""Set an image value material parameter to the specified object.
|
||||
|
||||
@seeNode Get Scene Root
|
||||
|
||||
@input Object: Object whose material parameter should change. Use `Get Scene Root` node to set parameter globally.
|
||||
|
||||
@input Per Object:
|
||||
- `Enabled`: Set material parameter specific to this object. Global parameter will be ignored.
|
||||
- `Disabled`: Set parameter globally, including this object.
|
||||
|
||||
@input Material: Material whose parameter to be set.
|
||||
|
||||
@input Node: Name of the parameter.
|
||||
|
||||
@output Image: Name of the image.
|
||||
"""
|
||||
bl_idname = 'LNGetMaterialImageParamNode'
|
||||
bl_label = 'Get Material Image Param'
|
||||
lnx_section = 'params'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxBoolSocket', 'Per Object')
|
||||
self.add_input('LnxDynamicSocket', 'Material')
|
||||
self.add_input('LnxStringSocket', 'Node')
|
||||
|
||||
self.add_output('LnxStringSocket', 'Image')
|
||||
@ -0,0 +1,31 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetMaterialRgbParamNode(LnxLogicTreeNode):
|
||||
"""Get a color or vector value material parameter to the specified object.
|
||||
|
||||
@seeNode Get Scene Root
|
||||
|
||||
@input Object: Object whose material parameter should change. Use `Get Scene Root` node to set parameter globally.
|
||||
|
||||
@input Per Object:
|
||||
- `Enabled`: Set material parameter specific to this object. Global parameter will be ignored.
|
||||
- `Disabled`: Set parameter globally, including this object.
|
||||
|
||||
@input Material: Material whose parameter to be set.
|
||||
|
||||
@input Node: Name of the parameter.
|
||||
|
||||
@output Color: Color or vector input.
|
||||
"""
|
||||
bl_idname = 'LNGetMaterialRgbParamNode'
|
||||
bl_label = 'Get Material RGB Param'
|
||||
lnx_section = 'params'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxBoolSocket', 'Per Object')
|
||||
self.add_input('LnxDynamicSocket', 'Material')
|
||||
self.add_input('LnxStringSocket', 'Node')
|
||||
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
@ -0,0 +1,31 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetMaterialValueParamNode(LnxLogicTreeNode):
|
||||
"""Get a float value material parameter to the specified object.
|
||||
|
||||
@seeNode Get Scene Root
|
||||
|
||||
@input Object: Object whose material parameter should change. Use `Get Scene Root` node to set parameter globally.
|
||||
|
||||
@input Per Object:
|
||||
- `Enabled`: Set material parameter specific to this object. Global parameter will be ignored.
|
||||
- `Disabled`: Set parameter globally, including this object.
|
||||
|
||||
@input Material: Material whose parameter to be set.
|
||||
|
||||
@input Node: Name of the parameter.
|
||||
|
||||
@output Float: float value.
|
||||
"""
|
||||
bl_idname = 'LNGetMaterialValueParamNode'
|
||||
bl_label = 'Get Material Value Param'
|
||||
lnx_section = 'params'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxBoolSocket', 'Per Object')
|
||||
self.add_input('LnxDynamicSocket', 'Material')
|
||||
self.add_input('LnxStringSocket', 'Node')
|
||||
|
||||
self.add_output('LnxFloatSocket', 'Float')
|
||||
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetMaterialsNode(LnxLogicTreeNode):
|
||||
"""TO DO."""
|
||||
bl_idname = 'LNSetMaterialsNode'
|
||||
bl_label = 'Set Object Materials'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketArray', 'Materials')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
16
leenkx/blender/lnx/logicnode/math/LN_colors_mix.py
Normal file
16
leenkx/blender/lnx/logicnode/math/LN_colors_mix.py
Normal file
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ColorsMixNode(LnxLogicTreeNode):
|
||||
"""
|
||||
@see https://github.com/rvanwijnen/spectral.js 2023 Ronald van Wijnen.
|
||||
"""
|
||||
|
||||
bl_idname = 'LNColorsMixNode'
|
||||
bl_label = 'Colors Mix'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketArray', 'Colors')
|
||||
self.add_input('LnxNodeSocketArray', 'Factors')
|
||||
|
||||
self.add_output('LnxColorSocket', 'Color')
|
||||
@ -38,7 +38,10 @@ class MathNode(LnxLogicTreeNode):
|
||||
'Modulo': 2,
|
||||
'Less Than': 2,
|
||||
'Greater Than': 2,
|
||||
'Ping-Pong': 2
|
||||
'Ping-Pong': 2,
|
||||
'Hyperbolic Sine': 1,
|
||||
'Hyperbolic Cosine': 1,
|
||||
'Hyperbolic Tangent': 1
|
||||
}.get(operation_name, 0)
|
||||
|
||||
def get_enum(self):
|
||||
@ -97,7 +100,10 @@ class MathNode(LnxLogicTreeNode):
|
||||
('Fract', 'Fract', 'Fract'),
|
||||
('Square Root', 'Square Root', 'Square Root'),
|
||||
('Exponent', 'Exponent', 'Exponent'),
|
||||
('Ping-Pong', 'Ping-Pong', 'The output value is moved between 0.0 and the Scale based on the input value')],
|
||||
('Ping-Pong', 'Ping-Pong', 'The output value is moved between 0.0 and the Scale based on the input value'),
|
||||
('Hyperbolic Sine', 'Hyperbolic Sine', 'Hyperbolic Sine'),
|
||||
('Hyperbolic Cosine', 'Hyperbolic Cosine', 'Hyperbolic Cosine'),
|
||||
('Hyperbolic Tangent', 'Hyperbolic Tangent', 'Hyperbolic Tangent')],
|
||||
name='', default='Add', set=set_enum, get=get_enum)
|
||||
|
||||
property1: HaxeBoolProperty('property1', name='Clamp', default=False)
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class MatrixMathNode(LnxLogicTreeNode):
|
||||
"""Multiplies matrices."""
|
||||
bl_idname = 'LNMatrixMathNode'
|
||||
bl_label = 'Matrix Math'
|
||||
lnx_section = 'matrix'
|
||||
lnx_version = 1
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Multiply', 'Multiply', 'Multiply')],
|
||||
name='', default='Multiply')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxDynamicSocket', 'Matrix 1')
|
||||
self.add_input('LnxDynamicSocket', 'Matrix 2')
|
||||
|
||||
self.add_output('LnxDynamicSocket', 'Result')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
54
leenkx/blender/lnx/logicnode/math/LN_poisson_disk.py
Normal file
54
leenkx/blender/lnx/logicnode/math/LN_poisson_disk.py
Normal file
@ -0,0 +1,54 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class PoissonDiskNode(LnxLogicTreeNode):
|
||||
"""
|
||||
Generates an array of points with a poisson distribution.
|
||||
|
||||
SampleCube (Sample Rectangle):
|
||||
topLeft: Minimum bounding corner position.
|
||||
lowerRight: Maximum bounding corner position.
|
||||
minimumDistance: Minimum required spatial distance between points.
|
||||
pointsPerIteration: Candidate sample attempts per active point before rejection.
|
||||
|
||||
SampleSphere (Sample Circle):
|
||||
center: Sphere center position vector.
|
||||
radius: Bounding sphere radius.
|
||||
minimumDistance: Minimum required spatial distance between points.
|
||||
pointsPerIteration: Candidate sample attempts per active point before rejection.
|
||||
"""
|
||||
bl_idname = 'LNPoissonDiskNode'
|
||||
bl_label = 'Poisson Disk Sampling'
|
||||
lnx_section = 'generator'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 3:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 in ('Sample Cube', 'Sample Rectangle'):
|
||||
self.add_input('LnxVectorSocket', 'Top Left')
|
||||
self.add_input('LnxVectorSocket', 'Lower Right')
|
||||
else:
|
||||
self.add_input('LnxVectorSocket', 'Center')
|
||||
self.add_input('LnxFloatSocket', 'Radius')
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Sample Cube', 'Sample Cube', 'Sample Cube'),
|
||||
('Sample Sphere', 'Sample Sphere', 'Sample Sphere'),
|
||||
('Sample Rectangle', 'Sample Rectangle', 'Sample Rectangle'),
|
||||
('Sample Circle', 'Sample Circle', 'Sample Circle')],
|
||||
name='', default='Sample Cube', update=remove_extra_inputs)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxIntSocket', 'Points Per Iteration')
|
||||
self.add_input('LnxFloatSocket', 'Minimum Distance')
|
||||
self.add_input('LnxVectorSocket', 'Top Left')
|
||||
self.add_input('LnxVectorSocket', 'Lower Right')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketArray', 'Points')
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
71
leenkx/blender/lnx/logicnode/math/LN_procedural_noise.py
Normal file
71
leenkx/blender/lnx/logicnode/math/LN_procedural_noise.py
Normal file
@ -0,0 +1,71 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ProceduralNoiseNode(LnxLogicTreeNode):
|
||||
"""
|
||||
Generates different kind of noises values.
|
||||
|
||||
repeat: Periodicity interval for seamless tiling. -1 disables repeating.
|
||||
|
||||
Perlin:
|
||||
x: Spatial X coordinate.
|
||||
y: Spatial Y coordinate.
|
||||
z: Spatial Z coordinate.
|
||||
|
||||
OctavePerlin:
|
||||
x, y, z: Spatial coordinates.
|
||||
octaves: Number of noise layers combined.
|
||||
persistence: Amplitude multiplier per octave (decay factor).
|
||||
frequency: Base spatial scaling factor.
|
||||
|
||||
DiamondSquare:
|
||||
width: Total grid width.
|
||||
height: Total grid height.
|
||||
featureSize: Initial step size for grid subdivision.
|
||||
scale: Random offset amplitude scale factor.
|
||||
randFunc: Random number generator function returning a Float.
|
||||
"""
|
||||
bl_idname = 'LNProceduralNoiseNode'
|
||||
bl_label = 'Procedural Noise'
|
||||
lnx_section = 'generator'
|
||||
lnx_version = 1
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 1:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
if self.property0 in ('Perlin', 'Octave Perlin'):
|
||||
self.add_input('LnxFloatSocket', 'X')
|
||||
self.add_input('LnxFloatSocket', 'Y')
|
||||
self.add_input('LnxFloatSocket', 'Z')
|
||||
self.add_input('LnxIntSocket', 'Repeat', default_value = -1)
|
||||
if self.property0 == 'Octave Perlin':
|
||||
self.add_input('LnxIntSocket', 'Octaves', default_value = 4)
|
||||
self.add_input('LnxFloatSocket', 'Persistence', default_value = 0.5)
|
||||
self.add_input('LnxFloatSocket', 'Frequency', default_value = 1.0)
|
||||
if self.property0 == 'Diamond Square':
|
||||
self.add_input('LnxIntSocket', 'X')
|
||||
self.add_input('LnxIntSocket', 'Y')
|
||||
self.add_input('LnxIntSocket', 'Width', default_value = 3)
|
||||
self.add_input('LnxIntSocket', 'Height', default_value = 3)
|
||||
self.add_input('LnxIntSocket', 'Feature Size', default_value = 2)
|
||||
self.add_input('LnxFloatSocket', 'Scale', default_value = 1.0)
|
||||
self.add_input('LnxFloatSocket', 'Offset', default_value = 0.5)
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Perlin', 'Perlin', 'Perlin 3D'),
|
||||
('Octave Perlin', 'Octave Perlin', 'Octave Perlin 3D'),
|
||||
('Diamond Square', 'Diamond Square', 'Diamond Square 2D')],
|
||||
name='', default='Perlin', update=remove_extra_inputs)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxFloatSocket', 'X')
|
||||
self.add_input('LnxFloatSocket', 'Y')
|
||||
self.add_input('LnxFloatSocket', 'Z')
|
||||
self.add_input('LnxIntSocket', 'Repeat', default_value = -1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxFloatSocket', 'Value')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
@ -45,7 +45,13 @@ class TweenFloatNode(LnxLogicTreeNode):
|
||||
('CircInOut', 'CircInOut', 'CircInOut'),
|
||||
('BackIn', 'BackIn', 'BackIn'),
|
||||
('BackOut', 'BackOut', 'BackOut'),
|
||||
('BackInOut', 'BackInOut', 'BackInOut')],
|
||||
('BackInOut', 'BackInOut', 'BackInOut'),
|
||||
('BounceIn', 'BounceIn', 'BounceIn'),
|
||||
('BounceOut', 'BounceOut', 'BounceOut'),
|
||||
('BounceInOut', 'BounceInOut', 'BounceInOut'),
|
||||
('ElasticIn', 'ElasticIn', 'ElasticIn'),
|
||||
('ElasticOut', 'ElasticOut', 'ElasticOut'),
|
||||
('ElasticInOut', 'ElasticInOut', 'ElasticInOut')],
|
||||
name='', default='Linear')
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -45,7 +45,13 @@ class TweenFloatNode(LnxLogicTreeNode):
|
||||
('CircInOut', 'CircInOut', 'CircInOut'),
|
||||
('BackIn', 'BackIn', 'BackIn'),
|
||||
('BackOut', 'BackOut', 'BackOut'),
|
||||
('BackInOut', 'BackInOut', 'BackInOut')],
|
||||
('BackInOut', 'BackInOut', 'BackInOut'),
|
||||
('BounceIn', 'BounceIn', 'BounceIn'),
|
||||
('BounceOut', 'BounceOut', 'BounceOut'),
|
||||
('BounceInOut', 'BounceInOut', 'BounceInOut'),
|
||||
('ElasticIn', 'ElasticIn', 'ElasticIn'),
|
||||
('ElasticOut', 'ElasticOut', 'ElasticOut'),
|
||||
('ElasticInOut', 'ElasticInOut', 'ElasticInOut')],
|
||||
name='', default='Linear')
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -45,7 +45,13 @@ class TweenTransformNode(LnxLogicTreeNode):
|
||||
('CircInOut', 'CircInOut', 'CircInOut'),
|
||||
('BackIn', 'BackIn', 'BackIn'),
|
||||
('BackOut', 'BackOut', 'BackOut'),
|
||||
('BackInOut', 'BackInOut', 'BackInOut')],
|
||||
('BackInOut', 'BackInOut', 'BackInOut'),
|
||||
('BounceIn', 'BounceIn', 'BounceIn'),
|
||||
('BounceOut', 'BounceOut', 'BounceOut'),
|
||||
('BounceInOut', 'BounceInOut', 'BounceInOut'),
|
||||
('ElasticIn', 'ElasticIn', 'ElasticIn'),
|
||||
('ElasticOut', 'ElasticOut', 'ElasticOut'),
|
||||
('ElasticInOut', 'ElasticInOut', 'ElasticInOut')],
|
||||
name='', default='Linear')
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -45,7 +45,13 @@ class TweenVectorNode(LnxLogicTreeNode):
|
||||
('CircInOut', 'CircInOut', 'CircInOut'),
|
||||
('BackIn', 'BackIn', 'BackIn'),
|
||||
('BackOut', 'BackOut', 'BackOut'),
|
||||
('BackInOut', 'BackInOut', 'BackInOut')],
|
||||
('BackInOut', 'BackInOut', 'BackInOut'),
|
||||
('BounceIn', 'BounceIn', 'BounceIn'),
|
||||
('BounceOut', 'BounceOut', 'BounceOut'),
|
||||
('BounceInOut', 'BounceInOut', 'BounceInOut'),
|
||||
('ElasticIn', 'ElasticIn', 'ElasticIn'),
|
||||
('ElasticOut', 'ElasticOut', 'ElasticOut'),
|
||||
('ElasticInOut', 'ElasticInOut', 'ElasticInOut')],
|
||||
name='', default='Linear')
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -6,7 +6,7 @@ class WorldToScreenSpaceNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNWorldToScreenSpaceNode'
|
||||
bl_label = 'World to Screen Space'
|
||||
lnx_section = 'matrix'
|
||||
lnx_version = 2
|
||||
lnx_version = 3
|
||||
|
||||
def remove_extra_inputs(self, context):
|
||||
while len(self.inputs) > 1:
|
||||
@ -24,12 +24,14 @@ class WorldToScreenSpaceNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxVectorSocket', 'World')
|
||||
|
||||
self.add_output('LnxVectorSocket', 'Screen')
|
||||
self.add_output('LnxIntSocket', 'X')
|
||||
self.add_output('LnxIntSocket', 'Y')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
if self.lnx_version not in (0, 1, 2):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
||||
|
||||
@ -5,3 +5,4 @@ add_node_section(name='angle', category='Math')
|
||||
add_node_section(name='matrix', category='Math')
|
||||
add_node_section(name='color', category='Math')
|
||||
add_node_section(name='vector', category='Math')
|
||||
add_node_section(name='generator', category='Math')
|
||||
|
||||
@ -4,8 +4,17 @@ class TimeNode(LnxLogicTreeNode):
|
||||
"""Returns the application execution time and the delta time."""
|
||||
bl_idname = 'LNTimeNode'
|
||||
bl_label = 'Get Application Time'
|
||||
lnx_version = 1
|
||||
lnx_section = 'time'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxFloatSocket', 'Time')
|
||||
self.add_output('LnxFloatSocket', 'Delta')
|
||||
self.add_output('LnxFloatSocket', 'RealTime')
|
||||
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
raise LookupError()
|
||||
|
||||
return NodeReplacement.Identity(self)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class GetDebugConsoleSettings(LnxLogicTreeNode):
|
||||
class GetDebugConsoleSettingsNode(LnxLogicTreeNode):
|
||||
"""Return properties of the debug console.
|
||||
|
||||
@output Enabled: Whether the debug console is enabled.
|
||||
@ -17,6 +17,7 @@ class GetDebugConsoleSettings(LnxLogicTreeNode):
|
||||
"""
|
||||
bl_idname = 'LNGetDebugConsoleSettings'
|
||||
bl_label = 'Get Debug Console Settings'
|
||||
lnx_section = 'debug'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetDebugConsoleSettings(LnxLogicTreeNode):
|
||||
class SetDebugConsoleSettingsNode(LnxLogicTreeNode):
|
||||
"""Sets the debug console settings."""
|
||||
bl_idname = 'LNSetDebugConsoleSettings'
|
||||
bl_label = 'Set Debug Console Settings'
|
||||
lnx_section = 'debug'
|
||||
lnx_version = 1
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
|
||||
@ -4,6 +4,7 @@ class SetTimeScaleNode(LnxLogicTreeNode):
|
||||
"""Sets the global time scale."""
|
||||
bl_idname = 'LNSetTimeScaleNode'
|
||||
bl_label = 'Set Time Scale'
|
||||
lnx_section = 'time'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -5,6 +5,7 @@ class SleepNode(LnxLogicTreeNode):
|
||||
through the incoming signal."""
|
||||
bl_idname = 'LNSleepNode'
|
||||
bl_label = 'Sleep'
|
||||
lnx_section = 'time'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -24,6 +24,7 @@ class TimerNode(LnxLogicTreeNode):
|
||||
"""
|
||||
bl_idname = 'LNTimerNode'
|
||||
bl_label = 'Timer'
|
||||
lnx_section = 'time'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
11
leenkx/blender/lnx/logicnode/native/LN_get_assets.py
Normal file
11
leenkx/blender/lnx/logicnode/native/LN_get_assets.py
Normal file
@ -0,0 +1,11 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetAssetsNode(LnxLogicTreeNode):
|
||||
""""""
|
||||
bl_idname = 'LNGetAssetsNode'
|
||||
bl_label = 'Get Assets'
|
||||
lnx_section = 'Assets'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxNodeSocketArray', 'Assets')
|
||||
43
leenkx/blender/lnx/logicnode/native/LN_write_gif.py
Normal file
43
leenkx/blender/lnx/logicnode/native/LN_write_gif.py
Normal file
@ -0,0 +1,43 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class WriteGifNode(LnxLogicTreeNode):
|
||||
"""Writes the given image to the given file. If the image
|
||||
already exists, the existing content of the image is overwritten.
|
||||
|
||||
Aspect ratio must match display resolution ratio.
|
||||
|
||||
Render2D flag to include render draws.
|
||||
|
||||
@input Image File: the name of the image
|
||||
@input Camera: the render target image of the camera to write to the image file.
|
||||
@input Width: width of the image file.
|
||||
@input Height: heigth of the image file.
|
||||
@input sX: sub position of first x pixel of the sub image (0 for start).
|
||||
@input sY: sub position of first y pixel of the sub image (0 for start).
|
||||
@input sWidth: width of the sub image.
|
||||
@input sHeight: height of the sub image.
|
||||
@input Render2D: include Render 2D draws.
|
||||
|
||||
@seeNode Read File
|
||||
"""
|
||||
bl_idname = 'LNWriteGifNode'
|
||||
bl_label = 'Write Gif'
|
||||
lnx_section = 'file'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'Start')
|
||||
self.add_input('LnxNodeSocketAction', 'Stop')
|
||||
self.add_input('LnxStringSocket', 'Image File')
|
||||
self.add_input('LnxNodeSocketObject', 'Camera')
|
||||
self.add_input('LnxIntSocket', 'Width')
|
||||
self.add_input('LnxIntSocket', 'Height')
|
||||
self.add_input('LnxIntSocket', 'sX')
|
||||
self.add_input('LnxIntSocket', 'sY')
|
||||
self.add_input('LnxIntSocket', 'sWidth')
|
||||
self.add_input('LnxIntSocket', 'sHeight')
|
||||
self.add_input('LnxBoolSocket', 'Render2D')
|
||||
self.add_input('LnxFloatSocket', 'Frame duration')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AroundNavigableLocationNode(LnxLogicTreeNode):
|
||||
"""A random around a navigable location in the navmesh."""
|
||||
bl_idname = 'LNAroundNavigableLocationNode'
|
||||
bl_label = 'Around NavMesh Location'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxStringSocket', 'NavMeshId', default_value = 'NavMesh')
|
||||
self.add_input('LnxVectorSocket', 'Position')
|
||||
self.add_input('LnxFloatSocket', 'Radius')
|
||||
|
||||
self.add_output('LnxVectorSocket', 'Location')
|
||||
@ -4,17 +4,26 @@ class GoToLocationNode(LnxLogicTreeNode):
|
||||
"""Makes a NavCrowd agent go to location.
|
||||
|
||||
@input In: Start navigation.
|
||||
@input NavMeshId: The ID of the NavMesh to use.
|
||||
@input Object: The object to navigate. Object must have `NavCrowd` trait applied.
|
||||
@input Location: Closest point on the navmesh to navigate to.
|
||||
@input Max Speed: Maximum speed of the crowd agent.
|
||||
@input Max Accelaration: Maximum acceleration of the agent.
|
||||
@input Turn Speed: Turn rate in range (0, 1).
|
||||
"""
|
||||
bl_idname = 'LNCrowdGoToLocationNode'
|
||||
bl_label = 'Crowd Go to Location'
|
||||
lnx_section = 'crowd'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxStringSocket', 'NavMeshId', default_value = 'NavMesh')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxVectorSocket', 'Location')
|
||||
self.add_input('LnxFloatSocket', 'Max Speed', 5.0)
|
||||
self.add_input('LnxFloatSocket', 'Max Accelaration', 100)
|
||||
self.add_input('LnxFloatSocket', 'Turn Speed', 0.1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class CrowdSetLocationNode(LnxLogicTreeNode):
|
||||
"""Makes a NavCrowd agent go to location.
|
||||
|
||||
@input In: Start teleport.
|
||||
@input Object: The object to navigate. Object must have `NavCrowd` trait applied.
|
||||
@input Location: Closest point on the navmesh to navigate to.
|
||||
"""
|
||||
bl_idname = 'LNCrowdSetLocationNode'
|
||||
bl_label = 'Crowd Set Location'
|
||||
lnx_section = 'crowd'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxStringSocket', 'NavMeshId', default_value = 'NavMesh')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxVectorSocket', 'Location')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
@ -4,10 +4,13 @@ class GetAgentDataNode(LnxLogicTreeNode):
|
||||
"""Gets the speed and turn duration of the agent"""
|
||||
bl_idname = 'LNGetAgentDataNode'
|
||||
bl_label = 'Get Agent Data'
|
||||
lnx_version = 1
|
||||
lnx_section = 'agent'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxStringSocket', 'NavMesh ID')
|
||||
self.add_output('LnxFloatSocket', 'Speed')
|
||||
self.add_output('LnxFloatSocket', 'Turn Duration')
|
||||
self.add_output('LnxFloatSocket', 'Turn Duration')
|
||||
self.add_output('LnxNodeSocketArray', 'Path')
|
||||
21
leenkx/blender/lnx/logicnode/navmesh/LN_get_crowd_data.py
Normal file
21
leenkx/blender/lnx/logicnode/navmesh/LN_get_crowd_data.py
Normal file
@ -0,0 +1,21 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetCrowdDataNode(LnxLogicTreeNode):
|
||||
"""Gets the speed and position of the crowd"""
|
||||
bl_idname = 'LNGetCrowdDataNode'
|
||||
bl_label = 'Get Crowd Data'
|
||||
lnx_section = 'crowd'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxStringSocket', 'NavMeshId')
|
||||
self.add_output('LnxVectorSocket', 'Speed')
|
||||
self.add_output('LnxFloatSocket', 'Max Speed')
|
||||
self.add_output('LnxFloatSocket', 'Max Acceleration')
|
||||
self.add_output('LnxFloatSocket', 'Turn Speed')
|
||||
self.add_output('LnxVectorSocket', 'Location')
|
||||
self.add_output('LnxVectorSocket', 'Target Location')
|
||||
self.add_output('LnxIntSocket', 'Id')
|
||||
self.add_output('LnxNodeSocketArray', 'Path')
|
||||
@ -4,37 +4,28 @@ class GoToLocationNode(LnxLogicTreeNode):
|
||||
"""Makes a NavMesh agent go to location.
|
||||
|
||||
@input In: Start navigation.
|
||||
@input NavMeshId: The ID of the NavMesh to use.
|
||||
@input Object: The object to navigate. Object must have `NavAgent` trait applied.
|
||||
@input Location: Closest point on the navmesh to navigate to.
|
||||
@input Speed: Rate of movement.
|
||||
@input Turn Duration: Rate of turn.
|
||||
@input Height Offset: Height of the object from the navmesh.
|
||||
@input Use Raycast: Use physics ray cast to get more precise z positioning.
|
||||
@input Ray Cast Depth: Depth of ray cast from the object origin.
|
||||
@input Ray Cast Mask: Ray cast mask for collision detection.
|
||||
|
||||
@output Out: Executed immidiately after start of the navigation.
|
||||
@output Tick Position: Executed at every step of navigation translation.
|
||||
@output Tick Rotation: Executed at every step of navigation rotation.
|
||||
"""
|
||||
bl_idname = 'LNGoToLocationNode'
|
||||
bl_label = 'Go to Location'
|
||||
bl_label = 'Agent Go to Location'
|
||||
lnx_section = 'agent'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxStringSocket', 'NavMeshId', default_value = 'NavMesh')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxVectorSocket', 'Location')
|
||||
self.add_input('LnxFloatSocket', 'Speed', 5.0)
|
||||
self.add_input('LnxFloatSocket', 'Turn Duration', 0.4)
|
||||
self.add_input('LnxFloatSocket', 'Height Offset', 0.0)
|
||||
self.add_input('LnxBoolSocket','Use Raycast')
|
||||
self.add_input('LnxFloatSocket', 'Ray Cast Depth', -5.0)
|
||||
self.add_input('LnxIntSocket', 'Ray Cast Mask', 1)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketAction', 'Tick Position')
|
||||
self.add_output('LnxNodeSocketAction', 'Tick Rotation')
|
||||
|
||||
def get_replacement_node(self, node_tree: bpy.types.NodeTree):
|
||||
if self.lnx_version not in (0, 1):
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class NavigableLocationNode(LnxLogicTreeNode):
|
||||
"""TO DO."""
|
||||
"""A random navigable location in the navmesh."""
|
||||
bl_idname = 'LNNavigableLocationNode'
|
||||
bl_label = 'Navigable Location'
|
||||
lnx_version = 1
|
||||
bl_label = 'Random NavMesh Location'
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_output('LnxDynamicSocket', 'Location')
|
||||
self.add_input('LnxNodeSocketObject', 'NavMesh')
|
||||
|
||||
self.add_output('LnxVectorSocket', 'Location')
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class PickLocationNode(LnxLogicTreeNode):
|
||||
"""Pick a location coordinates in the given NavMesh."""
|
||||
"""Pick a location on the given NavMesh using screen coordinates."""
|
||||
bl_idname = 'LNPickLocationNode'
|
||||
bl_label = 'Pick NavMesh Location'
|
||||
lnx_version = 1
|
||||
lnx_version = 2
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'NavMesh')
|
||||
self.add_input('LnxVectorSocket', 'Screen Coords')
|
||||
self.add_input('LnxIntSocket', 'X')
|
||||
self.add_input('LnxIntSocket', 'Y')
|
||||
|
||||
self.add_output('LnxVectorSocket', 'Location')
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ReconstructNavMeshNode(LnxLogicTreeNode):
|
||||
"""Reconstruct a given NavMesh."""
|
||||
bl_idname = 'LNReconstructNavMeshNode'
|
||||
bl_label = 'Reconstruct NavMesh'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxStringSocket', 'NavMeshId', default_value = 'NavMesh')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
@ -4,6 +4,7 @@ class StopAgentNode(LnxLogicTreeNode):
|
||||
"""Stops the given NavMesh agent."""
|
||||
bl_idname = 'LNStopAgentNode'
|
||||
bl_label = 'Stop Agent'
|
||||
lnx_section = 'agent'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
14
leenkx/blender/lnx/logicnode/navmesh/LN_stop_crowd.py
Normal file
14
leenkx/blender/lnx/logicnode/navmesh/LN_stop_crowd.py
Normal file
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class StopCrowdNode(LnxLogicTreeNode):
|
||||
"""Stops the given NavMesh agent."""
|
||||
bl_idname = 'LNStopCrowdNode'
|
||||
bl_label = 'Stop Crowd'
|
||||
lnx_section = 'crowd'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
39
leenkx/blender/lnx/logicnode/object/LN_convex_break.py
Normal file
39
leenkx/blender/lnx/logicnode/object/LN_convex_break.py
Normal file
@ -0,0 +1,39 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class ConvexBreakNode(LnxLogicTreeNode):
|
||||
"""Breaks a convex object."""
|
||||
|
||||
bl_idname = 'LNConvexBreakNode'
|
||||
bl_label = 'Convex Break'
|
||||
lnx_version = 1
|
||||
|
||||
def update_sockets(self, context):
|
||||
while len(self.inputs) > 2:
|
||||
self.inputs.remove(self.inputs[-1])
|
||||
|
||||
if self.property0 == 'Impact':
|
||||
self.add_input('LnxVectorSocket', 'Impact Point')
|
||||
self.add_input('LnxVectorSocket', 'Impact Normal')
|
||||
else:
|
||||
self.add_input('LnxBoolSocket', 'Random Plane')
|
||||
self.add_input('LnxVectorSocket', 'Plane')
|
||||
self.add_input('LnxFloatSocket', 'Scale UV')
|
||||
self.add_input('LnxBoolSocket', 'Flat Shading', default_value = True)
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Impact', 'Subdivide by Impact', 'Subdivide by Impact'),
|
||||
('Plane', 'Subdivide by Plane', 'Subdivide by Plane')],
|
||||
name='', default='Impact', update=update_sockets)
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketAction', 'True')
|
||||
self.add_output('LnxNodeSocketAction', 'False')
|
||||
self.add_output('LnxNodeSocketArray', 'Array')
|
||||
self.update_sockets(context)
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetObjectCameraDataNode(LnxLogicTreeNode):
|
||||
"""Returns the camera data of the given object."""
|
||||
bl_idname = 'LNGetObjectCameraDataNode'
|
||||
bl_label = 'Get Object Camera Data'
|
||||
lnx_section = 'props'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxFloatSocket', 'Camera Distance')
|
||||
self.add_output('LnxFloatSocket', 'Screen Size')
|
||||
@ -1,26 +1,42 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetChildNode(LnxLogicTreeNode):
|
||||
"""Returns the child of the given object by the child object's name."""
|
||||
"""Returns the child of the given object by name or by a specific type."""
|
||||
bl_idname = 'LNGetChildNode'
|
||||
bl_label = 'Get Object Child'
|
||||
lnx_section = 'relations'
|
||||
lnx_version = 1
|
||||
|
||||
def sw_update(self, context):
|
||||
self.inputs[1].hide = (self.property0 == 'By Type')
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('By Name', 'By Name', 'By Name'),
|
||||
('Contains', 'Contains', 'Contains'),
|
||||
('Starts With', 'Starts With', 'Starts With'),
|
||||
('Ends With', 'Ends With', 'Ends With'),
|
||||
],
|
||||
name='', default='By Name')
|
||||
('By Type', 'By Type', 'By Type')],
|
||||
name='Method', default='By Name', update=sw_update)
|
||||
|
||||
property1: HaxeEnumProperty(
|
||||
'property1',
|
||||
items = [('MeshObject', 'Mesh', 'MeshObject'),
|
||||
('CameraObject', 'Camera', 'CameraObject'),
|
||||
('LightObject', 'Light', 'LightObject'),
|
||||
('SpeakerObject', 'Speaker', 'SpeakerObject'),
|
||||
('DecalObject', 'Decal', 'DecalObject'),
|
||||
('ProbeObject', 'Probe', 'ProbeObject'),
|
||||
('CurveObject', 'Curve', 'CurveObject')],
|
||||
name='Type', default='MeshObject')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Parent')
|
||||
self.add_input('LnxStringSocket', 'Child Name')
|
||||
|
||||
self.add_output('LnxNodeSocketObject', 'Child')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
if self.property0 == 'By Type':
|
||||
layout.prop(self, 'property1')
|
||||
|
||||
@ -11,3 +11,4 @@ class GetChildrenNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxNodeSocketObject', 'Parent')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Children')
|
||||
self.add_output('LnxIntSocket', 'Length')
|
||||
|
||||
@ -16,10 +16,16 @@ class GetObjectGeomNode(LnxLogicTreeNode):
|
||||
"""
|
||||
|
||||
bl_idname = 'LNGetObjectGeomNode'
|
||||
bl_label = 'Get Object Geometry Node'
|
||||
bl_label = 'Get Object Geometry'
|
||||
lnx_section = 'relations'
|
||||
lnx_version = 1
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('Local', 'Local', 'Local'),
|
||||
('Global', 'Global', 'Global')],
|
||||
name='', default='Local', update='')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
@ -28,5 +34,8 @@ class GetObjectGeomNode(LnxLogicTreeNode):
|
||||
self.add_output('LnxNodeSocketArray', 'Vertices Indices')
|
||||
self.add_output('LnxNodeSocketArray', 'Vertices Material Indices')
|
||||
self.add_output('LnxNodeSocketArray', 'Vertices Face Indices')
|
||||
self.add_output('LnxDynamicSocket', 'Vertex Groups Maps')
|
||||
self.add_output('LnxNodeSocketArray', 'Vertex Groups Names')
|
||||
self.add_output('LnxDynamicSocket', 'Vertex Groups Map')
|
||||
self.add_output('LnxNodeSocketArray', 'Vertex Groups Names')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetObjectInstancedNode(LnxLogicTreeNode):
|
||||
"""Gets the object instanced from an array of LOC, ROT and SCL."""
|
||||
bl_idname = 'LNGetObjectInstancedNode'
|
||||
bl_label = 'Get Object Instanced'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
|
||||
self.add_output('LnxBoolSocket', 'Instanced', default_value=True)
|
||||
self.add_output('LnxIntSocket', 'Type')
|
||||
self.add_output('LnxIntSocket', 'Count')
|
||||
self.add_output('LnxIntSocket', 'Stride')
|
||||
self.add_output('LnxNodeSocketArray', 'Array Instanced')
|
||||
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetObjectShapeKeyNode(LnxLogicTreeNode):
|
||||
"""Gets shape key value of the object"""
|
||||
bl_idname = 'LNGetObjectShapeKeyNode'
|
||||
bl_label = 'Get Object Shape Key'
|
||||
lnx_section = 'props'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxStringSocket', 'Shape Key')
|
||||
|
||||
self.add_output('LnxFloatSocket', 'Value')
|
||||
@ -0,0 +1,16 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
|
||||
class SampleObjectPointsNode(LnxLogicTreeNode):
|
||||
"""
|
||||
Samples points and surface normals across a mesh object using a low-discrepancy distribution.
|
||||
"""
|
||||
bl_idname = 'LNSampleObjectPointsNode'
|
||||
bl_label = 'Sample Object Points'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Sample')
|
||||
|
||||
self.add_output('LnxNodeSocketArray', 'Point/Normal')
|
||||
@ -0,0 +1,27 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetObjectInstancedNode(LnxLogicTreeNode):
|
||||
"""Sets the object instanced from an array of LOC, ROT and SCL."""
|
||||
bl_idname = 'LNSetObjectInstancedNode'
|
||||
bl_label = 'Set Object Instanced'
|
||||
lnx_version = 1
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('1', 'Loc', 'Instances use their unique position (ipos)'),
|
||||
('2', 'Loc + Rot', 'Instances use their unique position and rotation (ipos and irot)'),
|
||||
('3', 'Loc + Scale', 'Instances use their unique position and scale (ipos and iscl)'),
|
||||
('4', 'Loc + Rot + Scale', 'Instances use their unique position, rotation and scale (ipos, irot, iscl)')],
|
||||
name='', default='1', update='')
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketArray', 'Array Instanced')
|
||||
self.add_input('LnxBoolSocket', 'Include original', default_value=False)
|
||||
self.add_input('LnxBoolSocket', 'Dynamic Usage', default_value=False)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
@ -18,7 +18,7 @@ class SetParentNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Parent')
|
||||
self.add_input('LnxBoolSocket', 'Keep Transform', default_value = True)
|
||||
self.add_input('LnxBoolSocket', 'Parent Inverse')
|
||||
self.add_input('LnxBoolSocket', 'Parent Inverse', default_value = True)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ class SetVisibleNode(LnxLogicTreeNode):
|
||||
|
||||
property0: HaxeEnumProperty(
|
||||
'property0',
|
||||
items = [('object', 'Object', 'All object componenets visibility'),
|
||||
items = [('object', 'Object', 'All object components visibility'),
|
||||
('mesh', 'Mesh', 'Mesh visibility only'),
|
||||
('shadow', 'Shadow', 'Shadow visibility only'),
|
||||
],
|
||||
|
||||
17
leenkx/blender/lnx/logicnode/particle/LN_curve_guide.py
Normal file
17
leenkx/blender/lnx/logicnode/particle/LN_curve_guide.py
Normal file
@ -0,0 +1,17 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class CurveGuideNode(LnxLogicTreeNode):
|
||||
"""Sets the curves guide of the given particle source."""
|
||||
bl_idname = 'LNCurveGuideNode'
|
||||
bl_label = 'Curve Guide'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxIntSocket', 'Slot')
|
||||
self.add_input('LnxNodeSocketArray', 'Curve Array')
|
||||
self.add_input('LnxFloatSocket', 'Strengh', default_value = 1.0)
|
||||
self.add_input('LnxFloatSocket', 'Speed', default_value = 1.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
@ -3,7 +3,7 @@ from lnx.logicnode.lnx_nodes import *
|
||||
class GetParticleNode(LnxLogicTreeNode):
|
||||
"""Returns the Particle Systems of an object."""
|
||||
bl_idname = 'LNGetParticleNode'
|
||||
bl_label = 'Get Particle'
|
||||
bl_label = 'Get Particle Systems'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
|
||||
@ -32,3 +32,4 @@ class GetParticleDataNode(LnxLogicTreeNode):
|
||||
self.outputs.new('LnxFloatSocket', 'Lap')
|
||||
self.outputs.new('LnxFloatSocket', 'Lap Time')
|
||||
self.outputs.new('LnxIntSocket', 'Count')
|
||||
self.outputs.new('LnxNodeSocketObject', 'Particle')
|
||||
|
||||
@ -15,7 +15,7 @@ class AddRigidBodyNode(LnxLogicTreeNode):
|
||||
|
||||
@input Animated: Rigid body follows animation and will affect other active non-animated rigid bodies.
|
||||
|
||||
@input Trigger: Rigid body behaves as a trigger and detects collision. However, rigd body does not contribute to or receive collissions.
|
||||
@input Trigger: Rigid body behaves as a trigger and detects collision. However, rigid body does not contribute to or receive collissions.
|
||||
|
||||
@input Friction: Surface friction of the rigid body. Minimum value = 0, Preferred max value = 1.
|
||||
|
||||
@ -77,7 +77,8 @@ class AddRigidBodyNode(LnxLogicTreeNode):
|
||||
('Cone', 'Cone', 'Cone'),
|
||||
('Cylinder', 'Cylinder', 'Cylinder'),
|
||||
('Convex Hull', 'Convex Hull', 'Convex Hull'),
|
||||
('Mesh', 'Mesh', 'Mesh')],
|
||||
('Mesh', 'Mesh', 'Mesh'),
|
||||
('Compound Parent', 'Compound Parent', 'Compound Parent')],
|
||||
name='Shape', default='Box')
|
||||
|
||||
def lnx_init(self, context):
|
||||
@ -114,7 +115,7 @@ class AddRigidBodyNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxFloatSocket', 'Linear Damping', 0.04)
|
||||
self.add_input('LnxFloatSocket', 'Angular Damping', 0.1)
|
||||
self.add_input('LnxFloatSocket', 'Angular Friction', 0.1)
|
||||
self.add_input('LnxBoolSocket', 'Use Deacivation')
|
||||
self.add_input('LnxBoolSocket', 'Use Deactivation')
|
||||
self.add_input('LnxFloatSocket', 'Linear Velocity Threshold', 0.4)
|
||||
self.add_input('LnxFloatSocket', 'Angular Velocity Threshold', 0.5)
|
||||
self.add_input('LnxIntSocket', 'Collision Group', 1)
|
||||
|
||||
14
leenkx/blender/lnx/logicnode/physics/LN_add_physics_hook.py
Normal file
14
leenkx/blender/lnx/logicnode/physics/LN_add_physics_hook.py
Normal file
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AddPhysicsHookNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAddPhysicsHookNode'
|
||||
bl_label = 'Add Physics Hook'
|
||||
lnx_section = 'add'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'Hook')
|
||||
self.add_input('LnxNodeSocketArray', 'Vertices')
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
23
leenkx/blender/lnx/logicnode/physics/LN_add_soft_body.py
Normal file
23
leenkx/blender/lnx/logicnode/physics/LN_add_soft_body.py
Normal file
@ -0,0 +1,23 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class AddSoftBodyNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNAddSoftBodyNode'
|
||||
bl_label = 'Add Soft Body'
|
||||
lnx_section = 'softbody'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
# 0: Cloth, 1: Volume
|
||||
self.add_input('LnxIntSocket', 'Shape', default_value=0)
|
||||
self.add_input('LnxFloatSocket', 'Bend', default_value=0.5)
|
||||
self.add_input('LnxFloatSocket', 'Mass', default_value=1.0)
|
||||
self.add_input('LnxFloatSocket', 'Margin', default_value=0.04)
|
||||
self.add_input('LnxFloatSocket', 'Friction', default_value=0.5)
|
||||
self.add_input('LnxFloatSocket', 'Damping', default_value=0.01)
|
||||
self.add_input('LnxFloatSocket', 'Linear Stiffness', default_value=0.9)
|
||||
self.add_input('LnxFloatSocket', 'Angular Stiffness', default_value=0.9)
|
||||
self.add_input('LnxFloatSocket', 'Pressure', default_value=0.0)
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
@ -8,19 +8,21 @@ class GetRigidBodyDataNode(LnxLogicTreeNode):
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.inputs.new('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxNodeSocketObject', 'RB')
|
||||
|
||||
self.outputs.new('LnxBoolSocket', 'Is RB')
|
||||
self.outputs.new('LnxIntSocket', 'Collision Group')
|
||||
self.outputs.new('LnxIntSocket', 'Collision Mask')
|
||||
self.outputs.new('LnxBoolSocket', 'Is Animated')
|
||||
self.outputs.new('LnxBoolSocket', 'Is Static')
|
||||
self.outputs.new('LnxFloatSocket', 'Angular Damping')
|
||||
self.outputs.new('LnxFloatSocket', 'Linear Damping')
|
||||
self.outputs.new('LnxFloatSocket', 'Friction')
|
||||
self.outputs.new('LnxFloatSocket', 'Mass')
|
||||
#self.outputs.new('LnxStringSocket', 'Collision Shape')
|
||||
#self.outputs.new('LnxIntSocket', 'Activation State')
|
||||
#self.outputs.new('LnxBoolSocket', 'Is Gravity Enabled')
|
||||
#self.outputs.new(LnxVectorSocket', Angular Factor')
|
||||
#self.outputs.new('LnxVectorSocket', Linear Factor')
|
||||
self.add_output('LnxBoolSocket', 'Is RB')
|
||||
self.add_output('LnxIntSocket', 'Collision Group')
|
||||
self.add_output('LnxIntSocket', 'Collision Mask')
|
||||
self.add_output('LnxBoolSocket', 'Is Animated')
|
||||
self.add_output('LnxBoolSocket', 'Is Static')
|
||||
self.add_output('LnxFloatSocket', 'Linear Damping')
|
||||
self.add_output('LnxFloatSocket', 'Angular Damping')
|
||||
self.add_output('LnxFloatSocket', 'Friction')
|
||||
self.add_output('LnxFloatSocket', 'Angular Friction')
|
||||
self.add_output('LnxFloatSocket', 'Mass')
|
||||
self.add_output('LnxBoolSocket', 'Is Trigger')
|
||||
self.add_output('LnxFloatSocket', 'Bounciness')
|
||||
self.add_output('LnxBoolSocket', 'Gravity Enabled')
|
||||
self.add_output('LnxVectorSocket', 'Gravity')
|
||||
self.add_output('LnxVectorSocket', 'Linear Factor')
|
||||
self.add_output('LnxVectorSocket', 'Angular Factor')
|
||||
|
||||
14
leenkx/blender/lnx/logicnode/physics/LN_get_rb_dynamics.py
Normal file
14
leenkx/blender/lnx/logicnode/physics/LN_get_rb_dynamics.py
Normal file
@ -0,0 +1,14 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class SetRigidBodyDynamicsNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNSetRigidBodyDynamicsNode'
|
||||
bl_label = 'Set RB Dynamics'
|
||||
lnx_section = 'props'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Object')
|
||||
self.add_input('LnxBoolSocket', 'Is Static', default_value=False)
|
||||
self.add_input('LnxFloatSocket', 'Mass', default_value=1.0)
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
@ -3,11 +3,11 @@ from lnx.logicnode.lnx_nodes import *
|
||||
class GetPointVelocityNode(LnxLogicTreeNode):
|
||||
"""Returns the world velocity of the given point along the rigid body."""
|
||||
bl_idname = 'LNGetPointVelocityNode'
|
||||
bl_label = 'Get RB Point Velocity'
|
||||
bl_label = 'Get RB Velocity at Location'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'RB')
|
||||
self.add_input('LnxVectorSocket', 'Point')
|
||||
self.add_input('LnxVectorSocket', 'Location')
|
||||
|
||||
self.add_output('LnxVectorSocket', 'Velocity')
|
||||
|
||||
22
leenkx/blender/lnx/logicnode/physics/LN_get_sb_data.py
Normal file
22
leenkx/blender/lnx/logicnode/physics/LN_get_sb_data.py
Normal file
@ -0,0 +1,22 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class GetSoftBodyDataNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNGetSoftBodyDataNode'
|
||||
bl_label = 'Get SB Data'
|
||||
lnx_section = 'softbody'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketObject', 'SB')
|
||||
|
||||
self.add_output('LnxBoolSocket', 'Has SB')
|
||||
self.add_output('LnxFloatSocket', 'Mass')
|
||||
self.add_output('LnxFloatSocket', 'Bend')
|
||||
self.add_output('LnxIntSocket', 'Shape')
|
||||
self.add_output('LnxFloatSocket', 'Margin')
|
||||
self.add_output('LnxVectorSocket', 'World Center')
|
||||
self.add_output('LnxFloatSocket', 'Friction')
|
||||
self.add_output('LnxFloatSocket', 'Damping')
|
||||
self.add_output('LnxFloatSocket', 'Pressure')
|
||||
self.add_output('LnxFloatSocket', 'Linear Stiffness')
|
||||
self.add_output('LnxFloatSocket', 'Angular Stiffness')
|
||||
@ -19,6 +19,8 @@ class OnContactArrayNode(LnxLogicTreeNode):
|
||||
self.add_input('LnxNodeSocketArray', 'RBs')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
self.add_output('LnxNodeSocketArray', 'RBs')
|
||||
self.add_output('LnxNodeSocketObject', 'RB')
|
||||
|
||||
def draw_buttons(self, context, layout):
|
||||
layout.prop(self, 'property0')
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
from lnx.logicnode.lnx_nodes import *
|
||||
|
||||
class RemovePhysicsConstraintNode(LnxLogicTreeNode):
|
||||
bl_idname = 'LNRemovePhysicsConstraintNode'
|
||||
bl_label = 'Remove Physics Constraint'
|
||||
lnx_section = 'props'
|
||||
lnx_version = 1
|
||||
|
||||
def lnx_init(self, context):
|
||||
self.add_input('LnxNodeSocketAction', 'In')
|
||||
self.add_input('LnxNodeSocketObject', 'Pivot Object')
|
||||
|
||||
self.add_output('LnxNodeSocketAction', 'Out')
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user