Skip to content

Commit

Permalink
Add option to weld verts back and some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
marekzajac97 committed Jun 29, 2024
1 parent 5dd69b8 commit cccaafd
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 44 deletions.
2 changes: 1 addition & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"author" : "Marek Zajac",
"description" : "Import and export asset files for DICE's Refractor 2 engine",
"blender" : (4, 1, 1),
"version" : (0, 7, 6),
"version" : (0, 7, 7),
"location": "File -> Import/Export -> BF2",
"warning" : "",
"doc_url": "https://github.com/marekzajac97/bf2-blender/blob/main/docs/README.md",
Expand Down
49 changes: 32 additions & 17 deletions core/mesh.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ def _export_mesh(mesh_obj, mesh_file, mesh_type, **kwargs):

class MeshImporter:
def __init__(self, context, mesh_file, mesh_type='', reload=False,
texture_path='', geom_to_ske=None, merge_materials=True, reporter=DEFAULT_REPORTER):
texture_path='', geom_to_ske=None, merge_materials=True,
reporter=DEFAULT_REPORTER):
self.context = context
self.is_vegitation = 'vegitation' in mesh_file.lower() # yeah this is legit how BF2 detects it lmao
if mesh_type:
Expand Down Expand Up @@ -425,19 +426,25 @@ def _cleanup_old_materials(self):
bpy.data.materials.remove(material, do_unlink=True)

def _get_unique_material_index(self, other_bf2_mat):
merge_materials = self.merge_materials
material_index = lod_index = geom_index = -1
bone_count = 0
if merge_materials and isinstance(self.bf2_mesh, BF2SkinnedMesh):
for geom in self.bf2_mesh.geoms:
for lod in geom.lods:
try:
material_index = lod.materials.index(other_bf2_mat)
rig = lod.rigs[material_index]
bone_count = len(rig.bones)
except ValueError:
pass

if merge_materials:
if self.merge_materials:
if isinstance(self.bf2_mesh, BF2SkinnedMesh):
for geom_idx, geom in enumerate(self.bf2_mesh.geoms):
if material_index != -1:
break
for lod_idx, lod in enumerate(geom.lods):
try:
material_index = lod.materials.index(other_bf2_mat)
rig = lod.rigs[material_index]
bone_count = len(rig.bones)
geom_index = geom_idx
lod_index = lod_idx
break
except ValueError:
pass

for mat_idx, mat_data in enumerate(self.mesh_materials):
bf2_mat = mat_data['bf2_mat']
if type(bf2_mat) != type(other_bf2_mat):
Expand All @@ -458,14 +465,20 @@ def _get_unique_material_index(self, other_bf2_mat):
if (isinstance(bf2_mat, MaterialWithTransparency) and
bf2_mat.alpha_mode != other_bf2_mat.alpha_mode):
continue
if mat_data['bone_count'] + bone_count > MAX_BONE_LIMIT:
self.reporter.warning("Cannot merge material, bone limit has been reached")

material_bone_count = mat_data['geom_to_bone_count'].setdefault(geom_index, 0)
if material_bone_count + bone_count > MAX_BONE_LIMIT:
self.reporter.warning(f"Geom{geom_index} Lod{lod_index}: cannot merge material {material_index}, bone limit has been reached")
break
mat_data['bone_count'] += bone_count
mat_data['geom_to_bone_count'][geom_index] += bone_count

# self.reporter.warning(f"Geom{geom_index} Lod{lod_index}: material {material_index} has been merged")
return mat_idx

mat_idx = len(self.mesh_materials)
mat_data = {'bf2_mat': other_bf2_mat, 'bone_count': bone_count}
geom_to_bone_count = dict()
geom_to_bone_count[geom_index] = bone_count
mat_data = {'bf2_mat': other_bf2_mat, 'geom_to_bone_count': geom_to_bone_count}
self.mesh_materials.append(mat_data)
return mat_idx

Expand Down Expand Up @@ -908,7 +921,9 @@ def _can_merge_vert(self, this, other, uv_count):
return False
for uv_chan in range(uv_count):
uv_attr = f'texcoord{uv_chan}'
if getattr(this, uv_attr) != getattr(other, uv_attr):
this_uv = getattr(this, uv_attr)
other_uv = getattr(other, uv_attr)
if any([abs(this_uv[i] - other_uv[i]) > 0.0001 for i in (0, 1)]):
return False
return True

Expand Down
50 changes: 43 additions & 7 deletions core/object_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ def __init__(self, part_id, obj) -> None:
self.matrix_local = obj.matrix_local.copy()
self.children = []

def import_object(context, con_filepath, import_collmesh=False, import_rig=('AUTO', None), reload=False, reporter=DEFAULT_REPORTER, **kwargs):
def import_object(context, con_filepath, import_collmesh=False, import_rig=('AUTO', None),
reload=False, weld_verts=False, reporter=DEFAULT_REPORTER, **kwargs):
BF2Engine().shutdown() # clear previous state
obj_template_manager = BF2Engine().get_manager(ObjectTemplate)
geom_template_manager = BF2Engine().get_manager(GeometryTemplate)
Expand All @@ -47,18 +48,27 @@ def import_object(context, con_filepath, import_collmesh=False, import_rig=('AUT
if root_template is None:
root_template = object_template
else:
raise ImportException(f"{con_filepath}: found multiple root objects: {root_template}, {object_template}, which one to import?")
raise ImportException(f"{con_filepath}: found multiple root objects: {root_template.name}, {object_template.name}, which one to import?")
if root_template is None:
raise ImportException(f"{con_filepath}: root object not found!")

if not root_template.geom:
ImportException(f"The imported object '{root_template.name}' has no geometry set")

geometry_template = geom_template_manager.templates[root_template.geom.lower()]

_verify_template(root_template)

geometry_template_name = root_template.geom.lower()
if geometry_template_name not in geom_template_manager.templates:
raise ImportException(f"Geometry '{collmesh_template_name}' is not defined")

geometry_template = geom_template_manager.templates[geometry_template_name]

collmesh_template = None
if root_template.collmesh:
collmesh_template = col_template_manager.templates[root_template.collmesh.lower()]
collmesh_template_name = root_template.collmesh.lower()
if collmesh_template_name not in col_template_manager.templates:
raise ImportException(f"Collision mesh '{collmesh_template_name}' is not defined")
collmesh_template = col_template_manager.templates[collmesh_template_name]

con_dir = os.path.dirname(con_filepath)
geometry_type = geometry_template.geometry_type
Expand Down Expand Up @@ -90,6 +100,11 @@ def import_object(context, con_filepath, import_collmesh=False, import_rig=('AUT
geom_parts = {'mesh1': lod_obj} # XXX hack
else:
geom_parts = _split_mesh_by_vertex_groups(context, lod_obj)

if weld_verts:
for geom_part_obj in geom_parts.values():
_weld_verts(geom_part_obj)

new_lod = _apply_mesh_data_to_lod(context, root_template, geom_parts, coll_parts, geom_idx, lod_idx)
new_lod.parent = geom_obj
_fix_unassigned_parts(geom_obj, new_lod)
Expand Down Expand Up @@ -376,7 +391,7 @@ def _strip_prefix(s):
for char_idx, _ in enumerate(s):
if s[char_idx:].startswith('__'):
return s[char_idx+2:]
return ExportException(f"'{s}' has no GxLx__ prefix!")
raise ExportException(f"'{s}' has no GxLx__ prefix!")

def _object_hierarchy_has_any_meshes(obj, parent_bones):
if obj.data and isinstance(obj.data, Mesh) and len(obj.data.vertices):
Expand Down Expand Up @@ -838,6 +853,17 @@ def _triangulate(obj):
bpy.ops.object.mode_set(mode='OBJECT')
obj.hide_set(hide)

def _weld_verts(obj):
bpy.ops.object.select_all(action='DESELECT')
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_mode(type='VERT')
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.remove_doubles(threshold=0.0001)
bpy.ops.object.mode_set(mode='OBJECT')

def _get_nr_of_animted_uvs(mesh_geoms):
matrix_set = set()
for geom_obj in mesh_geoms:
Expand Down Expand Up @@ -919,4 +945,14 @@ def put_rig_safe(geom_idx, ske_name):
geom_to_ske[geom_idx] = rigs[ske_name]
else:
raise ImportException(f'Unhandled import_rig_mode {import_rig_mode}')
return geom_to_ske
return geom_to_ske

def _verify_template(root_obj_template):
part_id_to_obj_template = dict()
def _check_geom_part_unique(obj_template):
if obj_template.geom_part in part_id_to_obj_template:
raise ImportException(f"'{obj_template.name}' has the same ObjectTemplate.geometryPart index as '{part_id_to_obj_template[obj_template.geom_part].name}'")
part_id_to_obj_template[obj_template.geom_part] = obj_template
for child in obj_template.children:
_check_geom_part_unique(child.template)
_check_geom_part_unique(root_obj_template)
Loading

0 comments on commit cccaafd

Please sign in to comment.