Esempio n. 1
0
def test_unpack_pack_half_float():
    # FIXME: Research half float and find out if these are actual limitations or
    # a bug in the function.
    # if it's not an actual limitation, raise an exception
    # https://en.wikipedia.org/wiki/Half-precision_floating-point_format
    expected_fail = 0
    for short_input in range(0, 65535):
        if (short_input in range(31745, 33792)
                or short_input in range(1, 1024)
                or short_input in range(64512, 65535)):
            expected_fail += 1
        else:
            float_output = unpack_half_float(short_input)
            short_again = pack_half_float(float_output)
            assert short_input == short_again
    assert expected_fail == 4093
Esempio n. 2
0
def test_unpack_pack_half_float():
    # FIXME: Research half float and find out if these are actual limitations or
    # a bug in the function.
    # if it's not an actual limitation, raise an exception
    # https://en.wikipedia.org/wiki/Half-precision_floating-point_format
    expected_fail = 0
    for short_input in range(0, 65535):
        if (short_input in range(31745, 33792) or
                short_input in range(1, 1024) or
                short_input in range(64512, 65535)):
            expected_fail += 1
        else:
            float_output = unpack_half_float(short_input)
            short_again = pack_half_float(float_output)
            assert short_input == short_again
    assert expected_fail == 4093
Esempio n. 3
0
def _export_vertices(blender_mesh_object, bounding_box, saved_mod, mesh_index):
    saved_mesh = saved_mod.meshes_array[mesh_index]
    if saved_mod.bone_palette_array:
        bone_palette = saved_mod.bone_palette_array[
            saved_mesh.bone_palette_index].values[:]
    else:
        bone_palette = []
    blender_mesh = blender_mesh_object.data
    vertex_count = len(blender_mesh.vertices)
    weights_per_vertex = get_bone_indices_and_weights_per_vertex(
        blender_mesh_object)
    # TODO: check the number of uv layers
    uvs_per_vertex = get_uvs_per_vertex(blender_mesh_object.data,
                                        blender_mesh_object.data.uv_layers[0])

    VF = VERTEX_FORMATS_TO_CLASSES[saved_mesh.vertex_format]
    '''
    # Unfortunately this fails in some cases and could crash the game; until some mesh unknowns are figured out,
    # relying on saved_mesh data
    # e.g. pl0000.mod from uPl00ChrisNormal.arc, meshes_array[30] has max bones per vertex = 4, but the
    # original file has 5
    if weights_per_vertex:
        max_bones_per_vertex = max({len(data) for data in weights_per_vertex.values()})
        if max_bones_per_vertex > 8:
            raise RuntimeError("The mesh '{}' contains some vertex that are weighted by "
                               "more than 8 bones, which is not supported. Fix it and try again"
                               .format(blender_mesh.name))
        VF = VERTEX_FORMATS_TO_CLASSES[max_bones_per_vertex]
    '''

    for vertex_index, (uv_x, uv_y) in uvs_per_vertex.items():
        # flipping for dds textures
        uv_y *= -1
        uv_x = pack_half_float(uv_x)
        uv_y = pack_half_float(uv_y)
        uvs_per_vertex[vertex_index] = (uv_x, uv_y)

    if uvs_per_vertex and len(uvs_per_vertex) != vertex_count:
        # TODO: logging
        print('There are some vertices with no uvs in mesh in {}.'
              'Vertex count: {} UVs per vertex: {}'.format(
                  blender_mesh.name, vertex_count, len(uvs_per_vertex)))

    box_width = abs(bounding_box.min_x * 100) + abs(bounding_box.max_x * 100)
    box_height = abs(bounding_box.min_y * 100) + abs(bounding_box.max_y * 100)
    box_length = abs(bounding_box.min_z * 100) + abs(bounding_box.max_z * 100)

    vertices_array = (VF * vertex_count)()
    has_bones = hasattr(VF, 'bone_indices')
    has_tangents = hasattr(VF, 'tangent_x')
    has_second_uv_layer = hasattr(VF, 'uv2_x')
    original_vertices_array = get_vertices_array(
        saved_mod, saved_mod.meshes_array[mesh_index])
    for vertex_index, vertex in enumerate(blender_mesh.vertices):
        vertex_struct = vertices_array[vertex_index]
        original_vertex_struct = original_vertices_array[vertex_index]
        if weights_per_vertex:
            weights_data = weights_per_vertex[
                vertex_index]  # list of (bone_index, value)
            bone_indices = [
                bone_palette.index(bone_index)
                for bone_index, _ in weights_data
            ]
            weight_values = [
                round(weight_value * 255) for _, weight_value in weights_data
            ]
        else:
            bone_indices = []
            weight_values = []

        xyz = (vertex.co[0] * 100, vertex.co[1] * 100, vertex.co[2] * 100)
        xyz = z_up_to_y_up(xyz)
        if has_bones:
            # applying bounding box constraints
            xyz = vertices_export_locations(xyz, box_width, box_length,
                                            box_height)
        vertex_struct.position_x = xyz[0]
        vertex_struct.position_y = xyz[1]
        vertex_struct.position_z = xyz[2]
        vertex_struct.position_w = 32767
        if has_bones:
            array_size = ctypes.sizeof(vertex_struct.bone_indices)
            vertex_struct.bone_indices = (ctypes.c_ubyte *
                                          array_size)(*bone_indices)
            vertex_struct.weight_values = (ctypes.c_ubyte *
                                           array_size)(*weight_values)
        '''
        vertex_struct.normal_x = round(vertex.normal[0] * 127)
        vertex_struct.normal_y = round(vertex.normal[2] * 127) * -1
        vertex_struct.normal_z = round(vertex.normal[1] * 127)
        vertex_struct.normal_w = -1
        '''
        # XXX quick hack until normals can be exported ok in blender (gotta check fbx export or ask Bastien Montagne)
        vertex_struct.normal_x = original_vertex_struct.normal_x
        vertex_struct.normal_y = original_vertex_struct.normal_y
        vertex_struct.normal_z = original_vertex_struct.normal_z
        vertex_struct.normal_w = original_vertex_struct.normal_w
        if has_tangents:
            vertex_struct.tangent_x = original_vertex_struct.tangent_x
            vertex_struct.tangent_y = original_vertex_struct.tangent_x
            vertex_struct.tangent_z = original_vertex_struct.tangent_x
            vertex_struct.tangent_w = original_vertex_struct.tangent_x
            '''
            vertex_struct.tangent_x = -1
            vertex_struct.tangent_y = -1
            vertex_struct.tangent_z = -1
            vertex_struct.tangent_w = -1
            '''
        vertex_struct.uv_x = uvs_per_vertex.get(
            vertex_index, (0, 0))[0] if uvs_per_vertex else 0
        vertex_struct.uv_y = uvs_per_vertex.get(
            vertex_index, (0, 0))[1] if uvs_per_vertex else 0
        if has_second_uv_layer:
            vertex_struct.uv2_x = 0
            vertex_struct.uv2_y = 0
    return VF, vertices_array
Esempio n. 4
0
def _export_vertices(blender_mesh_object, bounding_box, saved_mod, mesh_index):
    saved_mesh = saved_mod.meshes_array[mesh_index]
    if saved_mod.bone_palette_array:
        bone_palette = saved_mod.bone_palette_array[saved_mesh.bone_palette_index].values[:]
    else:
        bone_palette = []
    blender_mesh = blender_mesh_object.data
    vertex_count = len(blender_mesh.vertices)
    weights_per_vertex = get_bone_indices_and_weights_per_vertex(blender_mesh_object)
    # TODO: check the number of uv layers
    uvs_per_vertex = get_uvs_per_vertex(blender_mesh_object.data, blender_mesh_object.data.uv_layers[0])

    VF = VERTEX_FORMATS_TO_CLASSES[saved_mesh.vertex_format]

    '''
    # Unfortunately this fails in some cases and could crash the game; until some mesh unknowns are figured out,
    # relying on saved_mesh data
    # e.g. pl0000.mod from uPl00ChrisNormal.arc, meshes_array[30] has max bones per vertex = 4, but the
    # original file has 5
    if weights_per_vertex:
        max_bones_per_vertex = max({len(data) for data in weights_per_vertex.values()})
        if max_bones_per_vertex > 8:
            raise RuntimeError("The mesh '{}' contains some vertex that are weighted by "
                               "more than 8 bones, which is not supported. Fix it and try again"
                               .format(blender_mesh.name))
        VF = VERTEX_FORMATS_TO_CLASSES[max_bones_per_vertex]
    '''

    for vertex_index, (uv_x, uv_y) in uvs_per_vertex.items():
        # flipping for dds textures
        uv_y *= -1
        uv_x = pack_half_float(uv_x)
        uv_y = pack_half_float(uv_y)
        uvs_per_vertex[vertex_index] = (uv_x, uv_y)

    if uvs_per_vertex and len(uvs_per_vertex) != vertex_count:
        # TODO: logging
        print('There are some vertices with no uvs in mesh in {}.'
              'Vertex count: {} UVs per vertex: {}'.format(blender_mesh.name, vertex_count,
                                                           len(uvs_per_vertex)))

    box_width = abs(bounding_box.min_x * 100) + abs(bounding_box.max_x * 100)
    box_height = abs(bounding_box.min_y * 100) + abs(bounding_box.max_y * 100)
    box_length = abs(bounding_box.min_z * 100) + abs(bounding_box.max_z * 100)

    vertices_array = (VF * vertex_count)()
    has_bones = hasattr(VF, 'bone_indices')
    has_tangents = hasattr(VF, 'tangent_x')
    has_second_uv_layer = hasattr(VF, 'uv2_x')
    original_vertices_array = get_vertices_array(saved_mod, saved_mod.meshes_array[mesh_index])
    for vertex_index, vertex in enumerate(blender_mesh.vertices):
        vertex_struct = vertices_array[vertex_index]
        original_vertex_struct = original_vertices_array[vertex_index]
        if weights_per_vertex:
            weights_data = weights_per_vertex[vertex_index]   # list of (bone_index, value)
            bone_indices = [bone_palette.index(bone_index) for bone_index, _ in weights_data]
            weight_values = [round(weight_value * 255) for _, weight_value in weights_data]
        else:
            bone_indices = []
            weight_values = []

        xyz = (vertex.co[0] * 100, vertex.co[1] * 100, vertex.co[2] * 100)
        xyz = z_up_to_y_up(xyz)
        if has_bones:
            # applying bounding box constraints
            xyz = vertices_export_locations(xyz, box_width, box_length, box_height)
        vertex_struct.position_x = xyz[0]
        vertex_struct.position_y = xyz[1]
        vertex_struct.position_z = xyz[2]
        vertex_struct.position_w = 32767
        if has_bones:
            array_size = ctypes.sizeof(vertex_struct.bone_indices)
            vertex_struct.bone_indices = (ctypes.c_ubyte * array_size)(*bone_indices)
            vertex_struct.weight_values = (ctypes.c_ubyte * array_size)(*weight_values)
        '''
        vertex_struct.normal_x = round(vertex.normal[0] * 127)
        vertex_struct.normal_y = round(vertex.normal[2] * 127) * -1
        vertex_struct.normal_z = round(vertex.normal[1] * 127)
        vertex_struct.normal_w = -1
        '''
        # XXX quick hack until normals can be exported ok in blender (gotta check fbx export or ask Bastien Montagne)
        vertex_struct.normal_x = original_vertex_struct.normal_x
        vertex_struct.normal_y = original_vertex_struct.normal_y
        vertex_struct.normal_z = original_vertex_struct.normal_z
        vertex_struct.normal_w = original_vertex_struct.normal_w
        if has_tangents:
            vertex_struct.tangent_x = original_vertex_struct.tangent_x
            vertex_struct.tangent_y = original_vertex_struct.tangent_x
            vertex_struct.tangent_z = original_vertex_struct.tangent_x
            vertex_struct.tangent_w = original_vertex_struct.tangent_x
            '''
            vertex_struct.tangent_x = -1
            vertex_struct.tangent_y = -1
            vertex_struct.tangent_z = -1
            vertex_struct.tangent_w = -1
            '''
        vertex_struct.uv_x = uvs_per_vertex.get(vertex_index, (0, 0))[0] if uvs_per_vertex else 0
        vertex_struct.uv_y = uvs_per_vertex.get(vertex_index, (0, 0))[1] if uvs_per_vertex else 0
        if has_second_uv_layer:
            vertex_struct.uv2_x = 0
            vertex_struct.uv2_y = 0
    return VF, vertices_array