def _export_textures_and_materials(blender_objects, saved_mod): textures = get_textures_from_blender_objects(blender_objects) blender_materials = get_materials_from_blender_objects(blender_objects) textures_array = ((ctypes.c_char * 64) * len(textures))() materials_data_array = (MaterialData * len(blender_materials))() for i, texture in enumerate(textures): file_name = os.path.basename(texture.image.filepath) try: file_path = ntpath.join(texture.albam_imported_texture_folder, file_name) except AttributeError: raise ExportError('Texture {0} was not imported from an Arc file'.format(texture.name)) try: file_path, _ = ntpath.splitext(file_path) textures_array[i] = (ctypes.c_char * 64)(*file_path.encode('ascii')) except UnicodeEncodeError: raise ExportError('Texture path {} is not in ascii'.format(file_path)) if len(file_path) > 64: # TODO: what if relative path are used? raise ExportError('File path to texture {} is longer than 64 characters' .format(file_path)) for i, mat in enumerate(blender_materials): material_data = MaterialData() try: # TODO: Should use data from actual blender material saved_mat = saved_mod.materials_data_array[i] except IndexError: raise ExportError('Exporting models with more materials than the original not supported yet') material_data.unk_01 = saved_mat.unk_01 material_data.unk_02 = saved_mat.unk_02 material_data.unk_03 = saved_mat.unk_03 material_data.unk_04 = saved_mat.unk_04 material_data.unk_05 = saved_mat.unk_05 material_data.unk_06 = saved_mat.unk_06 material_data.unk_07 = saved_mat.unk_07 for texture_slot in mat.texture_slots: if not texture_slot: continue texture = texture_slot.texture if not texture: # ? continue # texture_indices expects index-1 based try: texture_index = textures.index(texture) + 1 except ValueError: # TODO: logging print('error in textures') material_data.texture_indices[texture.albam_imported_texture_type] = texture_index materials_data_array[i] = material_data return textures_array, materials_data_array
def _export_textures_and_materials(blender_objects, saved_mod): textures = get_textures_from_blender_objects(blender_objects) blender_materials = get_materials_from_blender_objects(blender_objects) textures_array = ((ctypes.c_char * 64) * len(textures))() materials_data_array = (MaterialData * len(blender_materials))() for i, texture in enumerate(textures): file_name = os.path.basename(texture.image.filepath) try: file_path = ntpath.join(texture.albam_imported_texture_folder, file_name) except AttributeError: raise ExportError( 'Texture {0} was not imported from an Arc file'.format( texture.name)) try: file_path, _ = ntpath.splitext(file_path) textures_array[i] = (ctypes.c_char * 64)(*file_path.encode('ascii')) except UnicodeEncodeError: raise ExportError( 'Texture path {} is not in ascii'.format(file_path)) if len(file_path) > 64: # TODO: what if relative path are used? raise ExportError( 'File path to texture {} is longer than 64 characters'.format( file_path)) for i, mat in enumerate(blender_materials): material_data = MaterialData() try: # TODO: Should use data from actual blender material saved_mat = saved_mod.materials_data_array[i] except IndexError: raise ExportError( 'Exporting models with more materials than the original not supported yet' ) material_data.unk_01 = saved_mat.unk_01 material_data.unk_02 = saved_mat.unk_02 material_data.unk_03 = saved_mat.unk_03 material_data.unk_04 = saved_mat.unk_04 material_data.unk_05 = saved_mat.unk_05 material_data.unk_06 = saved_mat.unk_06 material_data.unk_07 = saved_mat.unk_07 for texture_slot in mat.texture_slots: if not texture_slot: continue texture = texture_slot.texture if not texture: # ? continue # texture_indices expects index-1 based try: texture_index = textures.index(texture) + 1 except ValueError: # TODO: logging print('error in textures') material_data.texture_indices[ texture.albam_imported_texture_type] = texture_index materials_data_array[i] = material_data return textures_array, materials_data_array
def export_mod156(parent_blender_object): '''The blender_object provided should have meshes as children''' try: saved_mod = Mod156( file_path=BytesIO(parent_blender_object.albam_imported_item.data)) except AttributeError: raise ExportError( "Can't export '{0}' to Mod156, the model to be exported " "wasn't imported using Albam".format(parent_blender_object.name)) children_objects = [child for child in parent_blender_object.children] empty_children = [c for c in children_objects if c.type == 'EMPTY'] meshes_children = [c for c in children_objects if c.type == 'MESH'] bounding_box = get_bounding_box_positions_from_blender_objects( children_objects) if len(meshes_children) < len(saved_mod.meshes_array) and empty_children: # There were failed meshes that were replaced as empties in the import # We need to remove the extra weight groups (or whaterver they are), # before exporting failed_indices = { i for i, obj in enumerate(parent_blender_object.children) if obj.type == 'EMPTY' } new_bytes = [] current_position = 0 for i, mesh in enumerate(saved_mod.meshes_array): size = 144 * mesh.vertex_group_count data = saved_mod.meshes_array_2[current_position:current_position + size] current_position = current_position + size if i in failed_indices: continue else: new_bytes.extend(data) # the misterious extra 4 bytes for mod.156 new_bytes.extend(saved_mod.meshes_array_2[-4:]) meshes_array_2 = (ctypes.c_ubyte * len(new_bytes))(*new_bytes) elif len(meshes_children) != len( saved_mod.meshes_array) and not empty_children: raise ExportError( "Can't import {0}, different meshes quantity ({1} vs {2}) " "Support for this will come soon".format( parent_blender_object.name, len(saved_mod.meshes_array), len(children_objects))) else: meshes_array_2 = saved_mod.meshes_array_2 textures_array, materials_array = _export_textures_and_materials( children_objects, saved_mod) meshes_array, vertex_buffer, index_buffer = _export_meshes( children_objects, bounding_box, saved_mod) bone_count = get_bone_count_from_blender_objects([parent_blender_object]) if not bone_count: bones_array_offset = 0 elif bone_count and saved_mod.unk_08: bones_array_offset = 176 + len(saved_mod.unk_12) else: bones_array_offset = 176 mod = Mod156( id_magic=b'MOD', version=156, version_rev=1, bone_count=bone_count, mesh_count=get_mesh_count_from_blender_objects(children_objects), material_count=len(materials_array), vertex_count=get_vertex_count_from_blender_objects(children_objects), face_count=(ctypes.sizeof(index_buffer) // 2) + 1, edge_count=0, # TODO: add edge_count vertex_buffer_size=ctypes.sizeof(vertex_buffer), vertex_buffer_2_size=len(saved_mod.vertex_buffer_2), texture_count=len(textures_array), group_count=saved_mod.group_count, bones_array_offset=bones_array_offset, group_data_array=saved_mod.group_data_array, bone_palette_count=saved_mod.bone_palette_count, sphere_x=saved_mod.sphere_x, sphere_y=saved_mod.sphere_y, sphere_z=saved_mod.sphere_z, sphere_w=saved_mod.sphere_w, box_min_x=saved_mod.box_min_x, box_min_y=saved_mod.box_min_y, box_min_z=saved_mod.box_min_z, box_min_w=saved_mod.box_min_w, box_max_x=saved_mod.box_max_x, box_max_y=saved_mod.box_max_y, box_max_z=saved_mod.box_max_z, box_max_w=saved_mod.box_max_w, unk_01=saved_mod.unk_01, unk_02=saved_mod.unk_02, unk_03=saved_mod.unk_03, unk_04=saved_mod.unk_04, unk_05=saved_mod.unk_05, unk_06=saved_mod.unk_06, unk_07=saved_mod.unk_07, unk_08=saved_mod.unk_08, unk_09=saved_mod.unk_09, unk_10=saved_mod.unk_10, unk_11=saved_mod.unk_11, unk_12=saved_mod.unk_12, bones_array=saved_mod.bones_array, bones_unk_matrix_array=saved_mod.bones_unk_matrix_array, bones_world_transform_matrix_array=saved_mod. bones_world_transform_matrix_array, unk_13=saved_mod.unk_13, bone_palette_array=saved_mod.bone_palette_array, textures_array=textures_array, materials_data_array=materials_array, meshes_array=meshes_array, meshes_array_2=meshes_array_2, vertex_buffer=vertex_buffer, vertex_buffer_2=saved_mod.vertex_buffer_2, index_buffer=index_buffer) mod.bones_array_offset = get_offset(mod, 'bones_array') if mod.bone_count else 0 mod.group_offset = get_offset(mod, 'group_data_array') mod.textures_array_offset = get_offset(mod, 'textures_array') mod.meshes_array_offset = get_offset(mod, 'meshes_array') mod.vertex_buffer_offset = get_offset(mod, 'vertex_buffer') mod.vertex_buffer_2_offset = get_offset(mod, 'vertex_buffer_2') mod.index_buffer_offset = get_offset(mod, 'index_buffer') return mod, get_textures_from_blender_objects(children_objects)
def export_mod156(parent_blender_object): '''The blender_object provided should have meshes as children''' try: saved_mod = Mod156(file_path=BytesIO(parent_blender_object.albam_imported_item.data)) except AttributeError: raise ExportError("Can't export '{0}' to Mod156, the model to be exported " "wasn't imported using Albam" .format(parent_blender_object.name)) children_objects = [child for child in parent_blender_object.children] empty_children = [c for c in children_objects if c.type == 'EMPTY'] meshes_children = [c for c in children_objects if c.type == 'MESH'] bounding_box = get_bounding_box_positions_from_blender_objects(children_objects) if len(meshes_children) < len(saved_mod.meshes_array) and empty_children: # There were failed meshes that were replaced as empties in the import # We need to remove the extra weight groups (or whaterver they are), # before exporting failed_indices = {i for i, obj in enumerate(parent_blender_object.children) if obj.type == 'EMPTY'} new_bytes = [] current_position = 0 for i, mesh in enumerate(saved_mod.meshes_array): size = 144 * mesh.vertex_group_count data = saved_mod.meshes_array_2[current_position:current_position + size] current_position = current_position + size if i in failed_indices: continue else: new_bytes.extend(data) # the misterious extra 4 bytes for mod.156 new_bytes.extend(saved_mod.meshes_array_2[-4:]) meshes_array_2 = (ctypes.c_ubyte * len(new_bytes))(*new_bytes) elif len(meshes_children) != len(saved_mod.meshes_array) and not empty_children: raise ExportError("Can't import {0}, different meshes quantity ({1} vs {2}) " "Support for this will come soon".format(parent_blender_object.name, len(saved_mod.meshes_array), len(children_objects))) else: meshes_array_2 = saved_mod.meshes_array_2 textures_array, materials_array = _export_textures_and_materials(children_objects, saved_mod) meshes_array, vertex_buffer, index_buffer = _export_meshes(children_objects, bounding_box, saved_mod) bone_count = get_bone_count_from_blender_objects([parent_blender_object]) if not bone_count: bones_array_offset = 0 elif bone_count and saved_mod.unk_08: bones_array_offset = 176 + len(saved_mod.unk_12) else: bones_array_offset = 176 mod = Mod156(id_magic=b'MOD', version=156, version_rev=1, bone_count=bone_count, mesh_count=get_mesh_count_from_blender_objects(children_objects), material_count=len(materials_array), vertex_count=get_vertex_count_from_blender_objects(children_objects), face_count=(ctypes.sizeof(index_buffer) // 2) + 1, edge_count=0, # TODO: add edge_count vertex_buffer_size=ctypes.sizeof(vertex_buffer), vertex_buffer_2_size=len(saved_mod.vertex_buffer_2), texture_count=len(textures_array), group_count=saved_mod.group_count, bones_array_offset=bones_array_offset, group_data_array=saved_mod.group_data_array, bone_palette_count=saved_mod.bone_palette_count, sphere_x=saved_mod.sphere_x, sphere_y=saved_mod.sphere_y, sphere_z=saved_mod.sphere_z, sphere_w=saved_mod.sphere_w, box_min_x=saved_mod.box_min_x, box_min_y=saved_mod.box_min_y, box_min_z=saved_mod.box_min_z, box_min_w=saved_mod.box_min_w, box_max_x=saved_mod.box_max_x, box_max_y=saved_mod.box_max_y, box_max_z=saved_mod.box_max_z, box_max_w=saved_mod.box_max_w, unk_01=saved_mod.unk_01, unk_02=saved_mod.unk_02, unk_03=saved_mod.unk_03, unk_04=saved_mod.unk_04, unk_05=saved_mod.unk_05, unk_06=saved_mod.unk_06, unk_07=saved_mod.unk_07, unk_08=saved_mod.unk_08, unk_09=saved_mod.unk_09, unk_10=saved_mod.unk_10, unk_11=saved_mod.unk_11, unk_12=saved_mod.unk_12, bones_array=saved_mod.bones_array, bones_unk_matrix_array=saved_mod.bones_unk_matrix_array, bones_world_transform_matrix_array=saved_mod.bones_world_transform_matrix_array, unk_13=saved_mod.unk_13, bone_palette_array=saved_mod.bone_palette_array, textures_array=textures_array, materials_data_array=materials_array, meshes_array=meshes_array, meshes_array_2=meshes_array_2, vertex_buffer=vertex_buffer, vertex_buffer_2=saved_mod.vertex_buffer_2, index_buffer=index_buffer ) mod.bones_array_offset = get_offset(mod, 'bones_array') if mod.bone_count else 0 mod.group_offset = get_offset(mod, 'group_data_array') mod.textures_array_offset = get_offset(mod, 'textures_array') mod.meshes_array_offset = get_offset(mod, 'meshes_array') mod.vertex_buffer_offset = get_offset(mod, 'vertex_buffer') mod.vertex_buffer_2_offset = get_offset(mod, 'vertex_buffer_2') mod.index_buffer_offset = get_offset(mod, 'index_buffer') return mod, get_textures_from_blender_objects(children_objects)