Пример #1
0
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
Пример #2
0
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
Пример #3
0
def _export_meshes(blender_objects, bounding_box, saved_mod):
    """
    No weird optimization or sharing of offsets in the vertex buffer.
    All the same offsets, different positions like pl0200.mod from
    uPl01ShebaCos1.arc
    No time to investigate why and how those are decided. I suspect it might have to
    do with location of the meshes
    """
    all_blender_meshes_objects = [
        ob for ob in blender_objects if ob.type == 'MESH' or ob.type == 'EMPTY'
    ]
    passed_blender_meshes_objects = [
        ob for ob in all_blender_meshes_objects if ob.type == 'MESH'
    ]
    meshes_156 = (Mesh156 * len(passed_blender_meshes_objects))()
    vertex_buffer = bytearray()
    index_buffer = bytearray()
    materials = get_materials_from_blender_objects(blender_objects)

    vertex_position = 0
    face_position = 0
    failed_count = 0
    for i, blender_mesh_object in enumerate(all_blender_meshes_objects):
        # XXX: if a model with more meshes than the original is exported... boom
        # If somehow indices are changed... boom
        try:
            saved_mesh = saved_mod.meshes_array[i]
        except IndexError:
            raise ExportError(
                'Exporting models with more meshes (parts) than the original not supported yet'
            )
        # Failed meshes are imported as empties, since the only reason they fail is that they have out of bounds
        # array offsets (e.g. uEm41.arc em4000.mod), we can't retrieve any vertices since we'd mess up the vertex buffer
        if blender_mesh_object.type == 'EMPTY':
            failed_count += 1
            continue

        blender_mesh = blender_mesh_object.data

        vertex_format, vertices_array = _export_vertices(
            blender_mesh_object, bounding_box, saved_mod, i)
        vertex_buffer.extend(vertices_array)
        # TODO: is all this format conversion necessary?
        triangle_strips_python = triangles_list_to_triangles_strip(
            blender_mesh)
        # mod156 use global indices for verts, in case one only mesh is needed, probably
        triangle_strips_python = [
            e + vertex_position for e in triangle_strips_python
        ]
        triangle_strips_ctypes = (ctypes.c_ushort *
                                  len(triangle_strips_python))(
                                      *triangle_strips_python)
        index_buffer.extend(triangle_strips_ctypes)

        vertex_count = len(blender_mesh.vertices)
        index_count = len(triangle_strips_python)

        m156 = meshes_156[i - failed_count]
        try:
            m156.material_index = materials.index(blender_mesh.materials[0])
        except IndexError:
            raise ExportError('Mesh {} has no materials'.format(
                blender_mesh.name))
        m156.constant = 1
        m156.level_of_detail = saved_mesh.level_of_detail  # TODO
        m156.vertex_format = CLASSES_TO_VERTEX_FORMATS[vertex_format]
        m156.vertex_stride = 32
        m156.vertex_count = vertex_count
        m156.vertex_index_end = vertex_position + vertex_count - 1
        m156.vertex_index_start_1 = vertex_position
        m156.vertex_offset = 0
        m156.face_position = face_position
        m156.face_count = index_count
        m156.face_offset = 0
        m156.vertex_index_start_2 = vertex_position
        m156.vertex_group_count = saved_mesh.vertex_group_count  # len(blender_mesh_object.vertex_groups)
        # XXX: improve, not guaranteed if the weighting is modified (e.g. replacing a model)
        m156.bone_palette_index = saved_mesh.bone_palette_index

        # TODO: not using saved_mesh since it seems these are optional. Needs research
        m156.group_index = saved_mesh.group_index
        m156.unk_01 = saved_mesh.unk_01
        # m156.unk_02 = saved_mesh.unk_02  # crashes if set to saved_mesh.unk_02 in ChrisNormal
        m156.unk_03 = saved_mesh.unk_03
        m156.unk_04 = saved_mesh.unk_04
        m156.unk_05 = saved_mesh.unk_05
        m156.unk_06 = saved_mesh.unk_06
        m156.unk_07 = saved_mesh.unk_07
        m156.unk_08 = saved_mesh.unk_08
        m156.unk_09 = saved_mesh.unk_09
        m156.unk_10 = saved_mesh.unk_10
        m156.unk_11 = saved_mesh.unk_11

        vertex_position += vertex_count
        face_position += index_count
    vertex_buffer = (ctypes.c_ubyte *
                     len(vertex_buffer)).from_buffer(vertex_buffer)
    index_buffer = (ctypes.c_ushort *
                    (len(index_buffer) // 2)).from_buffer(index_buffer)

    return meshes_156, vertex_buffer, index_buffer
Пример #4
0
def _export_meshes(blender_objects, bounding_box, saved_mod):
    """
    No weird optimization or sharing of offsets in the vertex buffer.
    All the same offsets, different positions like pl0200.mod from
    uPl01ShebaCos1.arc
    No time to investigate why and how those are decided. I suspect it might have to
    do with location of the meshes
    """
    all_blender_meshes_objects = [ob for ob in blender_objects if ob.type == 'MESH' or ob.type == 'EMPTY']
    passed_blender_meshes_objects = [ob for ob in all_blender_meshes_objects if ob.type == 'MESH']
    meshes_156 = (Mesh156 * len(passed_blender_meshes_objects))()
    vertex_buffer = bytearray()
    index_buffer = bytearray()
    materials = get_materials_from_blender_objects(blender_objects)

    vertex_position = 0
    face_position = 0
    failed_count = 0
    for i, blender_mesh_object in enumerate(all_blender_meshes_objects):
        # XXX: if a model with more meshes than the original is exported... boom
        # If somehow indices are changed... boom
        try:
            saved_mesh = saved_mod.meshes_array[i]
        except IndexError:
            raise ExportError('Exporting models with more meshes (parts) than the original not supported yet')
        # Failed meshes are imported as empties, since the only reason they fail is that they have out of bounds
        # array offsets (e.g. uEm41.arc em4000.mod), we can't retrieve any vertices since we'd mess up the vertex buffer
        if blender_mesh_object.type == 'EMPTY':
            failed_count += 1
            continue

        blender_mesh = blender_mesh_object.data

        vertex_format, vertices_array = _export_vertices(blender_mesh_object, bounding_box,
                                                         saved_mod, i)
        vertex_buffer.extend(vertices_array)
        # TODO: is all this format conversion necessary?
        triangle_strips_python = triangles_list_to_triangles_strip(blender_mesh)
        # mod156 use global indices for verts, in case one only mesh is needed, probably
        triangle_strips_python = [e + vertex_position for e in triangle_strips_python]
        triangle_strips_ctypes = (ctypes.c_ushort * len(triangle_strips_python))(*triangle_strips_python)
        index_buffer.extend(triangle_strips_ctypes)

        vertex_count = len(blender_mesh.vertices)
        index_count = len(triangle_strips_python)

        m156 = meshes_156[i - failed_count]
        try:
            m156.material_index = materials.index(blender_mesh.materials[0])
        except IndexError:
            raise ExportError('Mesh {} has no materials'.format(blender_mesh.name))
        m156.constant = 1
        m156.level_of_detail = saved_mesh.level_of_detail  # TODO
        m156.vertex_format = CLASSES_TO_VERTEX_FORMATS[vertex_format]
        m156.vertex_stride = 32
        m156.vertex_count = vertex_count
        m156.vertex_index_end = vertex_position + vertex_count - 1
        m156.vertex_index_start_1 = vertex_position
        m156.vertex_offset = 0
        m156.face_position = face_position
        m156.face_count = index_count
        m156.face_offset = 0
        m156.vertex_index_start_2 = vertex_position
        m156.vertex_group_count = saved_mesh.vertex_group_count  # len(blender_mesh_object.vertex_groups)
        # XXX: improve, not guaranteed if the weighting is modified (e.g. replacing a model)
        m156.bone_palette_index = saved_mesh.bone_palette_index

        # TODO: not using saved_mesh since it seems these are optional. Needs research
        m156.group_index = saved_mesh.group_index
        m156.unk_01 = saved_mesh.unk_01
        # m156.unk_02 = saved_mesh.unk_02  # crashes if set to saved_mesh.unk_02 in ChrisNormal
        m156.unk_03 = saved_mesh.unk_03
        m156.unk_04 = saved_mesh.unk_04
        m156.unk_05 = saved_mesh.unk_05
        m156.unk_06 = saved_mesh.unk_06
        m156.unk_07 = saved_mesh.unk_07
        m156.unk_08 = saved_mesh.unk_08
        m156.unk_09 = saved_mesh.unk_09
        m156.unk_10 = saved_mesh.unk_10
        m156.unk_11 = saved_mesh.unk_11

        vertex_position += vertex_count
        face_position += index_count
    vertex_buffer = (ctypes.c_ubyte * len(vertex_buffer)).from_buffer(vertex_buffer)
    index_buffer = (ctypes.c_ushort * (len(index_buffer) // 2)).from_buffer(index_buffer)

    return meshes_156, vertex_buffer, index_buffer