Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mvr: Improved scene reset if mvr imported again #207

Merged
merged 6 commits into from
Jul 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 74 additions & 33 deletions mvr.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ def create_mvr_props(mvr_obj, cls, name="", uid=False, ref=None):
mvr_obj['UUID'] = uid


def create_transform_property(obj):
mtx_copy = obj.matrix_world.copy()
translate = mtx_copy.to_translation()
rotate = mtx_copy.transposed().to_3x3()
trans_mtx = rotate[0][:] + rotate[1][:] + rotate[2][:] + translate[:]
obj['Transform'] = trans_mtx


def get_matrix(obj, mtx):
mtx_data = obj.matrix.matrix
obj_mtx = Matrix(mtx_data).transposed()
Expand All @@ -50,6 +58,25 @@ def get_matrix(obj, mtx):
return global_matrix


def trans_matrix(trans_mtx):
mtx = list(trans_mtx)
trans_matrix = Matrix((mtx[:3]+[0], mtx[3:6]+[0], mtx[6:9]+[0], mtx[9:]+[1])).transposed()
return trans_matrix


def check_existing(node, collection):
cls_name = node.__class__.__name__
existing = any(col.get('UUID') == node.uuid for col in collection.children)
if existing:
for collect in collection.children:
if collect.get('MVR Class') == cls_name:
for obj in collect.all_objects:
transform = obj.get('Transform')
if transform is not None:
obj.matrix_world = trans_matrix(transform)
return existing


def get_child_list(dmx, mscale, mvr_scene, child_list, layer_index, folder_path,
extracted, layer_collection, fixture_group=None):

Expand All @@ -60,24 +87,27 @@ def get_child_list(dmx, mscale, mvr_scene, child_list, layer_index, folder_path,
viewlayer.active_layer_collection = viewport

for truss_idx, truss_obj in enumerate(child_list.trusses):
print("creating Truss... %s" % truss_obj.name)
existing = check_existing(truss_obj, layer_collection)

if fixture_group is None:
group_name = truss_obj.name or "Truss"
group_name = '%s %d' % (group_name, truss_idx) if scene_idx >= 1 else group_name
fixture_group = FixtureGroup(group_name, truss_obj.uuid)

process_mvr_object(context, mvr_scene, truss_obj, truss_idx,
mscale, extracted, layer_collection)
if not existing:
process_mvr_object(context, mvr_scene, truss_obj, truss_idx,
mscale, extracted, layer_collection)

if hasattr(truss_obj, "child_list") and truss_obj.child_list:
get_child_list(dmx, mscale, mvr_scene, truss_obj.child_list, layer_index,
folder_path, extracted, layer_collection, fixture_group)

for scene_idx, scene_obj in enumerate(child_list.scene_objects):
existing = check_existing(scene_obj, layer_collection)

process_mvr_object(context, mvr_scene, scene_obj, scene_idx,
mscale, extracted, layer_collection)
if not existing:
process_mvr_object(context, mvr_scene, scene_obj, scene_idx,
mscale, extracted, layer_collection)

if hasattr(scene_obj, "child_list") and scene_obj.child_list:
get_child_list(dmx, mscale, mvr_scene, scene_obj.child_list, layer_index,
Expand Down Expand Up @@ -124,35 +154,33 @@ def process_mvr_object(context, mvr_scene, mvr_object, mvr_idx, mscale, extracte
symdef_id = isinstance(mvr_object, pymvr.Symdef)
current_path = os.path.dirname(os.path.realpath(__file__))
folder = os.path.join(current_path, "assets", "models", "mvr")
print("creating %s... %s" % (class_name, name))
DMX_Log.log.info(f"creating {class_name}... {name}")

def add_mvr_object(idx, node, mtx, collect, file=""):
node_type = node.__class__.__name__
imported_objects = []
item_name = Path(file).name
mesh_name = Path(file).stem
mesh_data = bpy.data.meshes
imported_objects = []
if not symdef_id:
collect['Reference'] = mesh_name
reference = collect.get('Reference')
node_type = node.__class__.__name__
gltf = file.split('.')[-1] == 'glb'
scale_factor = 0.001 if file.split('.')[-1] == '3ds' else 1.0
mesh_exist = next((msh for msh in mesh_data if msh.name == mesh_name), False)
exist = any(ob.data and ob.data.name == mesh_name for ob in collect.objects)
world_matrix = mtx @ Matrix.Scale(scale_factor, 4)
print("adding %s... %s" % (node_type, mesh_name))
DMX_Log.log.info(f"adding {node_type}... {mesh_name}")

if not exist:
if mesh_exist:
mesh_id = mesh_exist.get('MVR Name')
mesh_id = mesh_exist.get('MVR Name', mesh_name)
new_object = object_data.new(mesh_id, mesh_exist)
imported_objects.append(new_object)
else:
file_name = os.path.join(folder, file)
if os.path.isfile(file_name):
if file.split('.')[-1] == 'glb':
if gltf:
bpy.ops.import_scene.gltf(filepath=file_name)
else:
load_3ds(file_name, bpy.context, KEYFRAME=False, APPLY_MATRIX=False)
load_3ds(file_name, context, KEYFRAME=False, APPLY_MATRIX=False)
imported_objects.extend(list(viewlayer.objects.selected))
for ob in imported_objects:
ob.rotation_mode = 'XYZ'
Expand All @@ -165,8 +193,9 @@ def add_mvr_object(idx, node, mtx, collect, file=""):
ob.users_collection[0].objects.unlink(ob)
elif ob.name in layer_collect.collection.objects:
active_layer.collection.objects.unlink(ob)
if ob.parent is None:
ob.matrix_world = world_matrix @ ob.matrix_world.copy()
if ob.data is not None: # only gltf files can be pre transformed
ob.matrix_world = world_matrix @ ob.matrix_world.copy() if gltf else world_matrix
create_transform_property(ob)
if ob.name not in collect.objects:
collect.objects.link(ob)
objectData.setdefault(uid, collect)
Expand All @@ -190,6 +219,7 @@ def add_mvr_object(idx, node, mtx, collect, file=""):
for obj in child.objects:
bpy.data.objects.remove(obj)
break

if previous_mvr_object:
dmx_mvr_object = previous_mvr_object
else:
Expand Down Expand Up @@ -225,7 +255,7 @@ def add_mvr_object(idx, node, mtx, collect, file=""):
obj_name = '%s - %s %d' % (class_name, mvr_object.name, mvr_idx)
else:
obj_name = '%s %d' % (class_name, mvr_idx) if mvr_idx >= 1 else class_name
print("creating extra collection", obj_name)
DMX_Log.log.info(f"creating extra collection {obj_name}")
active_collect = bpy.data.collections.new(obj_name)
create_mvr_props(active_collect, class_name, name, uid)
group_collect.children.link(active_collect)
Expand All @@ -234,15 +264,16 @@ def add_mvr_object(idx, node, mtx, collect, file=""):
if active_collect is None:
active_collect = next((col for col in data_collect if col.get('UUID') == uid), False)
if not active_collect and not len(symbols):
reference = collection.get('UUID')
active_collect = data_collect.new(name)
create_mvr_props(active_collect, class_name, name, uid)
create_mvr_props(active_collect, class_name, name, uid, reference)

for idx, geometry in enumerate(geometrys):
file = geometry.file_name
obj_mtx = get_matrix(geometry, mscale)
extract_mvr_object(file, mvr_scene, folder, extracted)
object_collect = add_mvr_object(idx, geometry, obj_mtx, active_collect, file)
if object_collect and object_collect.name not in collection.children:
if object_collect and object_collect.name not in collection.children and object_collect != collection:
collection.children.link(object_collect)

for idx, symbol in enumerate(symbols):
Expand All @@ -257,7 +288,8 @@ def add_mvr_object(idx, node, mtx, collect, file=""):
symbol_object = object_data.new(name, None)
collection.objects.link(symbol_object)
symbol_object.matrix_world = symbol_mtx
symbol_object.empty_display_size = 0.01
create_transform_property(symbol_object)
symbol_object.empty_display_size = 0.001
symbol_object.empty_display_type = 'ARROWS'
symbol_object.instance_type = 'COLLECTION'
symbol_object.instance_collection = symbol_collect
Expand All @@ -273,6 +305,7 @@ def transform_matrix(mvr):
global_mtx = get_matrix(mvr, mscale)
for obj in obj_collect.objects:
obj.matrix_world = global_mtx @ obj.matrix_world.copy()
create_transform_property(obj)

def collect_objects(childlist):
for truss in childlist.trusses:
Expand Down Expand Up @@ -305,7 +338,7 @@ def extract_mvr_textures(mvr_scene, folder):
mvr_scene._package.extract(name, folder)


def add_mvr_fixture(dmx, mvr_scene, folder_path, fixture, fixture_index, layer_index, focus_point, already_extracted_files, fixture_group=None):
def add_mvr_fixture(dmx, mvr_scene, folder_path, fixture, fixture_idx, layer_idx, focus_point, extracted, fixture_group=None):
"""Add fixture to the scene"""

existing_fixture = None
Expand All @@ -316,20 +349,23 @@ def add_mvr_fixture(dmx, mvr_scene, folder_path, fixture, fixture_index, layer_i
break

if f"{fixture.gdtf_spec}" in mvr_scene._package.namelist():
if fixture.gdtf_spec not in already_extracted_files.keys():
if fixture.gdtf_spec not in extracted.keys():
mvr_scene._package.extract(fixture.gdtf_spec, folder_path)
already_extracted_files[fixture.gdtf_spec] = 0
extracted[fixture.gdtf_spec] = 0
else:
already_extracted_files[fixture.gdtf_spec] += 1
extracted[fixture.gdtf_spec] += 1
else:
# if the file is not in the MVR package, use an RGBW Par64
fixture.gdtf_spec = "BlenderDMX@[email protected]"

dmx.ensureUniverseExists(fixture.addresses[0].universe)

if existing_fixture is not None:
#TODO: we should not rename the fixture on import unless if the user wants it
# but we must ensure that the name is unique in the collection
unique_name = create_unique_fixture_name(fixture.name)
existing_fixture.build(
f"{fixture.name} {layer_index}-{fixture_index}",
unique_name,
fixture.gdtf_spec,
fixture.gdtf_mode,
fixture.addresses[0].universe,
Expand All @@ -346,8 +382,10 @@ def add_mvr_fixture(dmx, mvr_scene, folder_path, fixture, fixture_index, layer_i
unit_number=fixture.unit_number,
)
else:
unique_name = f"{fixture.name} {layer_idx}-{fixture_idx}"
unique_name = create_unique_fixture_name(unique_name)
dmx.addFixture(
f"{fixture.name} {layer_index}-{fixture_index}",
unique_name,
fixture.gdtf_spec,
fixture.addresses[0].universe,
fixture.addresses[0].address,
Expand Down Expand Up @@ -446,18 +484,18 @@ def load_mvr(dmx, file_name):
create_mvr_props(aux_directory, aux_type)
layer_collect.children.link(aux_directory)
for uid, auxcollect in auxData.items():
aux = data_collect.get(auxcollect.name)
if aux and aux.name not in aux_directory.children:
aux_directory.children.link(aux)
if auxcollect.name not in aux_directory.children:
aux_directory.children.link(auxcollect)
sym_collect = data_collect.get(uid)
if sym_collect:
sym_name = sym_collect.get('MVR Name')
if sym_collect.name in layer_collect.children:
layer_collect.children.unlink(sym_collect)
elif sym_collect.name not in auxcollect.children:
auxcollect.children.link(sym_collect)
if sym_name in (None, 'None'):
sym_name = 'None Layer'
auxcollect.children.link(sym_collect)
sym_collect.name = sym_collect.get('MVR Name')
sym_collect.name = sym_name

for laycollect in layer_collect.children:
if laycollect.get('MVR Class') is not None:
Expand All @@ -474,6 +512,9 @@ def load_mvr(dmx, file_name):
for obid, obj in enumerate(collect.all_objects):
obj_name = obj.name.split('.')[0]
if obj.is_instancer:
transform = obj.get('Transform')
if transform:
obj.matrix_world = trans_matrix(transform)
insta_name = '%s %d' % (obj_name, idx) if idx >= 1 else obj_name
obj.name = '%s_%d' % (insta_name.split('_')[0], obid)
elif obj.name[-3:].isdigit() and obj.name[-4] == '.':
Expand All @@ -489,4 +530,4 @@ def load_mvr(dmx, file_name):
objectData.clear()
viewlayer.update()
imported_layers.clear()
print("INFO", "MVR scene loaded in %.4f sec." % (time.time() - start_time))
DMX_Log.log.info(f"MVR scene loaded in {time.time() - start_time}.4f sec.")
Loading