def __init__(self, context, report, version, game_version, apply_modifiers, triangulate_faces, edge_split, use_edge_angle, use_edge_sharp, split_angle, clean_normalize_weights, hidden_geo, custom_scale): global_functions.unhide_all_collections() view_layer = bpy.context.view_layer object_list = list(bpy.context.scene.objects) self.materials = [] self.objects = [] self.instances = [] material_list = [] armature = [] geometry_list = [] original_geometry_list = [] unique_instance_geometry_list = [] unique_instance_geometry_list_2 = [] object_properties = [] object_count = 0 for obj in object_list: object_properties.append([obj.hide_get(), obj.hide_viewport]) if hidden_geo: global_functions.unhide_object(obj) if obj.type == 'MESH': if global_functions.set_ignore(obj) == False or hidden_geo: if clean_normalize_weights: if len(obj.vertex_groups) > 0: view_layer.objects.active = obj bpy.ops.object.mode_set(mode='EDIT') bpy.ops.mesh.select_all(action='SELECT') bpy.ops.object.vertex_group_clean( group_select_mode='ALL', limit=0.0) bpy.ops.object.vertex_group_normalize_all() bpy.ops.object.mode_set(mode='OBJECT') modifier_list = [] if apply_modifiers: for modifier in obj.modifiers: modifier.show_render = True modifier.show_viewport = True modifier.show_in_editmode = True modifier_list.append(modifier.type) if triangulate_faces: if not 'TRIANGULATE' in modifier_list: obj.modifiers.new("Triangulate", type='TRIANGULATE') if edge_split: if not 'EDGE_SPLIT' in modifier_list: edge_split = obj.modifiers.new("EdgeSplit", type='EDGE_SPLIT') edge_split.use_edge_angle = use_edge_angle edge_split.split_angle = split_angle edge_split.use_edge_sharp = use_edge_sharp else: modifier_idx = modifier_list.index('EDGE_SPLIT') obj.modifiers[ modifier_idx].use_edge_angle = use_edge_angle obj.modifiers[modifier_idx].split_angle = split_angle obj.modifiers[ modifier_idx].use_edge_sharp = use_edge_sharp depsgraph = context.evaluated_depsgraph_get() for obj in object_list: if obj.type == 'ARMATURE': if global_functions.set_ignore(obj) == False or hidden_geo: for bone in obj.data.bones: if not bone.name in unique_instance_geometry_list: unique_instance_geometry_list.append(bone.name) geometry_list.append( (bone, 'BONE', bone.name, bone.name)) original_geometry_list.append(bone) object_count += 1 elif obj.type == 'MESH' and len(obj.data.polygons) > 0: if global_functions.set_ignore(obj) == False or hidden_geo: if not obj.data.name in unique_instance_geometry_list: unique_instance_geometry_list.append(obj.data.name) object_count += 1 if obj.data.ass_jms.Object_Type == 'SPHERE': me = obj.to_mesh(preserve_all_data_layers=True) geometry_list.append( (me, 'SPHERE', obj.name, obj.data.name)) original_geometry_list.append(obj) elif obj.data.ass_jms.Object_Type == 'BOX': me = obj.to_mesh(preserve_all_data_layers=True) geometry_list.append( (me, 'BOX', obj.name, obj.data.name)) original_geometry_list.append(obj) elif obj.data.ass_jms.Object_Type == 'CAPSULES': me = obj.to_mesh(preserve_all_data_layers=True) geometry_list.append( (me, 'PILL', obj.name, obj.data.name)) original_geometry_list.append(obj) elif obj.data.ass_jms.Object_Type == 'CONVEX SHAPES': if apply_modifiers: obj_for_convert = obj.evaluated_get(depsgraph) me = obj_for_convert.to_mesh( preserve_all_data_layers=True, depsgraph=depsgraph) geometry_list.append( (me, 'MESH', obj.name, obj.data.name)) original_geometry_list.append(obj) else: me = obj.to_mesh(preserve_all_data_layers=True) geometry_list.append( (me, 'MESH', obj.name, obj.data.name)) original_geometry_list.append(obj) else: if global_functions.set_ignore(obj) == False or hidden_geo: geometry_list.append( (None, 'EMPTY', obj.name, obj.data.name)) original_geometry_list.append(obj) self.instances.append( ASSScene.Instance(name='Scene Root', local_transform=ASSScene.Transform(), pivot_transform=ASSScene.Transform())) for idx, geometry in enumerate(geometry_list): verts = [] triangles = [] node_index_list = [] original_geo = original_geometry_list[idx] mesh = geometry[0] geo_class = geometry[1] geo_name = geometry[2] mesh_name = geometry[3] object_index = -1 if not geo_class == 'EMPTY': object_index = unique_instance_geometry_list.index(mesh_name) material_index = -1 radius = 2 extents = [1.0, 1.0, 1.0] height = 1 parent_id = 0 inheritance_flag = 0 xref_name = "" is_bone = False if geo_class == 'BONE': armature_name = original_geo.id_data.name armature = bpy.data.objects[armature_name] parent = original_geo.parent is_bone = True else: if armature: parent = original_geo.parent_bone else: parent = original_geo.parent if not parent == None: if not geo_class == 'BONE': if not original_geo.parent.type == 'ARMATURE': parent_id = original_geometry_list.index(parent) + 1 else: parent_id = original_geometry_list.index(parent) + 1 geo_matrix = global_functions.get_matrix( original_geo, original_geo, True, armature, original_geometry_list, is_bone, version, 'ASS', 0) geo_dimensions = global_functions.get_dimensions( geo_matrix, original_geo, None, None, custom_scale, version, None, False, is_bone, armature, 'ASS') rotation = (geo_dimensions.quat_i_a, geo_dimensions.quat_j_a, geo_dimensions.quat_k_a, geo_dimensions.quat_w_a) translation = (geo_dimensions.pos_x_a, geo_dimensions.pos_y_a, geo_dimensions.pos_z_a) if geo_class == 'BONE': scale = armature.pose.bones[original_geo.name].scale else: scale = original_geo.scale local_transform = ASSScene.Transform(rotation, translation, scale) self.instances.append( ASSScene.Instance(geo_name, object_index, idx, parent_id, inheritance_flag, local_transform, pivot_transform=ASSScene.Transform())) if not mesh_name in unique_instance_geometry_list_2 and not object_index == -1: unique_instance_geometry_list_2.append(mesh_name) if geo_class == 'BONE': armature_name = mesh.id_data.name armature = bpy.data.objects[armature_name] xref_path = bpy.path.abspath( armature.data.ass_jms.XREF_path) if xref_path != "": xref_name = armature.name elif geo_class == 'SPHERE': xref_path = bpy.path.abspath( original_geo.data.ass_jms.XREF_path) if xref_path != "": xref_name = original_geo.name radius = geo_dimensions.radius_a face = original_geo.data.polygons[0] material = global_functions.get_material( game_version, original_geo, face, mesh, material_list, 'ASS', None, None, ) if not material == -1: material_list = global_functions.gather_materials( game_version, material, material_list, 'ASS', None, None, None) material_index = material_list.index(material) elif geo_class == 'BOX': xref_path = bpy.path.abspath( original_geo.data.ass_jms.XREF_path) if xref_path != "": xref_name = original_geo.name face = original_geo.data.polygons[0] extents = [ geo_dimensions.dimension_x_a, geo_dimensions.dimension_y_a, geo_dimensions.dimension_z_a ] material = global_functions.get_material( game_version, original_geo, face, mesh, material_list, 'ASS', None, None, ) if not material == -1: material_list = global_functions.gather_materials( game_version, material, material_list, 'ASS', None, None, None) material_index = material_list.index(material) elif geo_class == 'PILL': xref_path = bpy.path.abspath( original_geo.data.ass_jms.XREF_path) if xref_path != "": xref_name = original_geo.name face = original_geo.data.polygons[0] height = (geo_dimensions.pill_z_a) radius = (geo_dimensions.radius_a) material = global_functions.get_material( game_version, original_geo, face, mesh, material_list, 'ASS', None, None, ) if not material == -1: material_list = global_functions.gather_materials( game_version, material, material_list, 'ASS', None, None, None) material_index = material_list.index(material) elif geo_class == 'MESH': xref_path = bpy.path.abspath( original_geo.data.ass_jms.XREF_path) if xref_path != "": xref_name = original_geo.name vertex_groups = original_geo.vertex_groups.keys() for face in mesh.polygons: v0 = len(verts) v1 = len(verts) + 1 v2 = len(verts) + 2 material = global_functions.get_material( game_version, original_geo, face, mesh, material_list, 'ASS', None, None, ) material_index = -1 if not material == -1: material_list = global_functions.gather_materials( game_version, material, material_list, 'ASS', None, None, None) material_index = material_list.index(material) triangles.append( ASSScene.Triangle(material_index, v0, v1, v2)) for loop_index in face.loop_indices: vert = mesh.vertices[ mesh.loops[loop_index].vertex_index] original_geo_matrix = global_functions.get_matrix( original_geo, original_geo, False, armature, original_geometry_list, False, version, 'ASS', 0) translation = vert.co world_translation = original_geo_matrix @ vert.co mesh_dimensions = global_functions.get_dimensions( None, None, None, None, custom_scale, version, translation, True, False, armature, 'ASS') scaled_translation = (mesh_dimensions.pos_x_a, mesh_dimensions.pos_y_a, mesh_dimensions.pos_z_a) normal = (vert.normal).normalized() uv_set = [] for uv_index in range(len(mesh.uv_layers)): mesh.uv_layers.active = mesh.uv_layers[ uv_index] uv = mesh.uv_layers.active.data[ mesh.loops[loop_index].index].uv uv_set.append(uv) uv = uv_set node_influence_count = 0 node_set = [] if len(vert.groups) != 0: object_vert_group_list = [] vertex_vert_group_list = [] for group_index in range(len(vert.groups)): vert_group = vert.groups[group_index].group object_vertex_group = vertex_groups[ vert_group] if armature: if object_vertex_group in armature.data.bones: vertex_vert_group_list.append( group_index) if armature.data.bones[ object_vertex_group] in original_geometry_list: object_vert_group_list.append( vert_group) else: if object_vertex_group in bpy.data.objects: vertex_vert_group_list.append( group_index) if bpy.data.objects[ object_vertex_group] in original_geometry_list: object_vert_group_list.append( vert_group) value = len(object_vert_group_list) if value > 4: value = 4 node_influence_count = int(value) if len(object_vert_group_list) != 0: for idx, group_index in enumerate( object_vert_group_list): vert_index = int( vertex_vert_group_list[idx]) vert_group = vert.groups[ vert_index].group object_vertex_group = vertex_groups[ vert_group] if armature: node_obj = armature.data.bones[ object_vertex_group] else: node_obj = bpy.data.objects[ object_vertex_group] node_index = int( original_geometry_list.index( node_obj)) if not node_index in node_index_list: node_index_list.append(node_index) node_weight = float( vert.groups[vert_index].weight) node_set.append( [node_index, node_weight]) verts.append( ASSScene.Vertex( node_influence_count, node_set, scaled_translation, normal, uv_set, )) original_geo.to_mesh_clear() self.objects.append( ASSScene.Object( geo_class, xref_path, xref_name, material_index, radius, extents, height, verts, triangles, node_index_list, )) for material in material_list: self.materials.append( ASSScene.Material( material.name, material.ass_jms.material_effect, )) for idx, obj in enumerate(object_list): property_value = object_properties[idx] obj.hide_set(property_value[0]) obj.hide_viewport = property_value[1]
def __init__(self, context, report, version, game_version, extension, custom_scale, biped_controller): global_functions.unhide_all_collections() scene = bpy.context.scene view_layer = bpy.context.view_layer object_properties = [] object_list = list(scene.objects) object_count = len(object_list) node_list = [] armature = [] armature_count = 0 first_frame = scene.frame_start last_frame = scene.frame_end + 1 total_frame_count = scene.frame_end - first_frame + 1 for obj in object_list: object_properties.append([obj.hide_get(), obj.hide_viewport]) if obj.type == 'ARMATURE': global_functions.unhide_object(obj) armature_count += 1 armature = obj view_layer.objects.active = obj obj.select_set(True) node_list = list(obj.data.bones) self.transform_count = total_frame_count #actor related items are hardcoded due to them being an unused feature in tool. Do not attempt to do anything to write this out as it is a waste of time and will get you nothing. self.actor_names = ['unnamedActor'] self.node_count = len(node_list) self.transforms = [] self.biped_controller_transforms = [] self.nodes = [] root_node_count = global_functions.count_root_nodes(node_list) h2_extension_list = ['JRMX', 'JMH'] sorted_list = global_functions.sort_list(node_list, armature, game_version, version, False) joined_list = sorted_list[0] reversed_joined_list = sorted_list[1] if self.node_count == 0: #JMSv2 files can have JMS files without a node for physics. raise global_functions.SceneParseError( "No nodes in scene. Add an armature or object mesh named frame." ) return {'CANCELLED'} elif armature_count >= 2: raise global_functions.SceneParseError( "More than one armature object. Please delete all but one.") return {'CANCELLED'} elif root_node_count >= 2: raise global_functions.SceneParseError( "More than one root node. Please remove or rename objects until you only have one root frame object." ) return {'CANCELLED'} elif len(object_list) == 0: raise global_functions.SceneParseError("No objects in scene.") return {'CANCELLED'} elif extension in h2_extension_list and game_version == 'haloce': raise global_functions.SceneParseError( "This extension is not used in Halo CE.") return {'CANCELLED'} elif version >= 16393 and game_version == 'haloce': raise global_functions.SceneParseError( "This version is not supported for Halo CE. Choose from 16390-16392 if you wish to export for Halo CE." ) return {'CANCELLED'} elif game_version == 'haloce' and self.node_count > 64: raise global_functions.SceneParseError( "This model has more nodes than Halo CE supports. Please limit your node count to 64 nodes" ) return {'CANCELLED'} elif game_version == 'halo2' and self.node_count > 255: raise global_functions.SceneParseError( "This model has more nodes than Halo 2 supports. Please limit your node count to 255 nodes" ) return {'CANCELLED'} self.node_checksum = 0 for node in joined_list: name = node.name find_child_node = global_functions.get_child( node, reversed_joined_list) find_sibling_node = global_functions.get_sibling( armature, node, reversed_joined_list) first_child_node = -1 first_sibling_node = -1 parent_node = -1 if not find_child_node == None: first_child_node = joined_list.index(find_child_node) if not find_sibling_node == None: first_sibling_node = joined_list.index(find_sibling_node) if not node.parent == None: parent_node = joined_list.index(node.parent) self.nodes.append( JMAScene.Node(name, parent_node, first_child_node, first_sibling_node)) self.node_checksum = global_functions.node_hierarchy_checksum( self.nodes, self.nodes[0], self.node_checksum) for frame in range(first_frame, last_frame): transforms_for_frame = [] for node in joined_list: bpy.context.scene.frame_set(frame) is_bone = False if armature: is_bone = True bone_matrix = global_functions.get_matrix( node, node, True, armature, joined_list, True, version, 'JMA', 0) mesh_dimensions = global_functions.get_dimensions( bone_matrix, node, None, None, custom_scale, version, None, False, is_bone, armature, 'JMA') vector = (mesh_dimensions.pos_x_a, mesh_dimensions.pos_y_a, mesh_dimensions.pos_z_a) rotation = (mesh_dimensions.quat_i_a, mesh_dimensions.quat_j_a, mesh_dimensions.quat_k_a, mesh_dimensions.quat_w_a) scale = (mesh_dimensions.scale_x_a) transforms_for_frame.append( JMAScene.Transform(vector, rotation, scale)) self.transforms.append(transforms_for_frame) #H2 specific biped controller data bool value. if version > 16394 and biped_controller: for frame in range(self.transform_count): bpy.context.scene.frame_set(frame) armature_matrix = global_functions.get_matrix( armature, armature, True, None, joined_list, False, version, 'JMA', 0) mesh_dimensions = global_functions.get_dimensions( armature_matrix, armature, None, None, custom_scale, version, None, False, False, armature, 'JMA') vector = (mesh_dimensions.pos_x_a, mesh_dimensions.pos_y_a, mesh_dimensions.pos_z_a) rotation = (mesh_dimensions.quat_i_a, mesh_dimensions.quat_j_a, mesh_dimensions.quat_k_a, mesh_dimensions.quat_w_a) scale = (mesh_dimensions.scale_x_a) self.biped_controller_transforms.append( JMAScene.Transform(vector, rotation, scale)) scene.frame_set(1) for idx, obj in enumerate(object_list): property_value = object_properties[idx] obj.hide_set(property_value[0]) obj.hide_viewport = property_value[1]