Exemple #1
0
class SceneGraph(WrapperModel):
    unknown0 = _attribute()
    children = _attribute(_list(SceneGraphNode.create_node))

    def all_nodes(self):
        for child in self.children:
            yield child
            yield from child.all_descendants()
Exemple #2
0
class Shape(WrapperModel):

    transformation_type = _attribute()
    batches = _attribute()
    attribute_descriptors = _attribute()

    @property
    def attributes(self):
        for descriptor in self.attribute_descriptors:
            yield descriptor.attribute

    @property
    def primitives(self):
        for batch in self.batches:
            yield from batch.primitives

    def gl_init(self, array_table):
        self.gl_hide = False

        self.gl_vertex_array = self.gl_create_resource(gl.VertexArray)
        glBindVertexArray(self.gl_vertex_array)

        self.gl_vertex_buffer = self.gl_create_resource(gl.Buffer)
        glBindBuffer(GL_ARRAY_BUFFER, self.gl_vertex_buffer)

        self.gl_element_count = 3 * gl_count_triangles(self)
        self.gl_element_buffer = self.gl_create_resource(gl.Buffer)
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, self.gl_element_buffer)

        vertex_type = numpy.dtype(
            [array_table[attribute].field() for attribute in self.attributes])
        vertex_count = sum(
            len(primitive.vertices) for primitive in self.primitives)
        vertex_array = numpy.empty(vertex_count, vertex_type)

        for attribute in self.attributes:
            array_table[attribute].load(self, vertex_array)

        vertex_array, element_map = numpy.unique(vertex_array,
                                                 return_inverse=True)
        element_array = gl_create_element_array(self, element_map,
                                                self.gl_element_count)

        glBufferData(GL_ARRAY_BUFFER, vertex_array.nbytes, vertex_array,
                     GL_STATIC_DRAW)
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, element_array.nbytes,
                     element_array, GL_STATIC_DRAW)

    def gl_bind(self):
        glBindVertexArray(self.gl_vertex_array)

    def gl_draw(self):
        glDrawElements(GL_TRIANGLES, self.gl_element_count, GL_UNSIGNED_SHORT,
                       None)
Exemple #3
0
class TevMode(WrapperModel):
    a = _attribute()
    b = _attribute()
    c = _attribute()
    d = _attribute()
    function = _attribute()
    bias = _attribute()
    scale = _attribute()
    clamp = _attribute()
    output = _attribute()
Exemple #4
0
class LightingMode(WrapperModel):
    material_source = _attribute()
    ambient_source = _attribute()
    diffuse_function = _attribute()
    attenuation_function = _attribute()
    light_enable = _attribute()
    use_light = _attribute(UseLightProxy, source_path=+_p)
Exemple #5
0
class Material(WrapperModel):

    block_info = BlockInfo()
    shader_info = ShaderInfo()

    def __init__(self, wrapped_object):
        super().__init__(wrapped_object)
        self.gl_program_table = {}

    name = _attribute()
    unknown0 = _attribute()
    cull_mode = _attribute()

    channel_count = _attribute()
    channels = _attribute(_list(Channel))

    texcoord_generator_count = _attribute()
    texcoord_generators = _attribute(_list(TexCoordGenerator))
    texture_matrices = _attribute(_list(TextureMatrix))
    textures = ReferenceAttribute()

    tev_stage_count = _attribute()
    tev_stages = _attribute(_list(TevStage))
    tev_colors = _attribute(_list())
    tev_color_previous = _attribute()
    kcolors = _attribute(_list())
    swap_tables = _attribute(_list(SwapTable))

    indirect_stage_count = _attribute()
    indirect_stages = _attribute(_list(IndirectStage))
    indirect_matrices = _attribute(_list(IndirectMatrix))

    alpha_test = _attribute(AlphaTest)
    fog = _attribute()
    depth_test_early = _attribute()
    depth_mode = _attribute(DepthMode)
    blend_mode = _attribute(BlendMode)
    dither = _attribute()

    @property
    def enabled_channels(self):
        for i in range(self.channel_count):
            yield self.channels[i]

    @property
    def enabled_texcoord_generators(self):
        for i in range(self.texcoord_generator_count):
            yield self.texcoord_generators[i]

    @property
    def enabled_tev_stages(self):
        for i in range(self.tev_stage_count):
            yield self.tev_stages[i]

    @property
    def enabled_indirect_stages(self):
        for i in range(self.indirect_stage_count):
            yield self.indirect_stages[i]

    def handle_event(self, event, path):
        if isinstance(event, ValueChangedEvent):
            if path in self.block_info.trigger_table:
                block_property = self.block_info.trigger_table[path]
                block_property.update_block(self.gl_block, self)
            if path in self.shader_info.triggers:
                self.gl_shader_invalidate()
        super().handle_event(event, path)

    @LazyProperty
    def gl_block(self):
        block = self.gl_create_resource(self.block_info.block_type,
                                        GL_DYNAMIC_DRAW)
        for block_property in self.block_info.properties:
            block_property.update_block(block, self)
        return block

    def gl_program(self, transformation_type):
        if transformation_type in self.gl_program_table:
            return self.gl_program_table[transformation_type]

        vertex_shader_string = models.vertex_shader.create_shader_string(
            self, transformation_type)
        fragment_shader_string = models.fragment_shader.create_shader_string(
            self)
        vertex_shader = self.gl_create_resource(gl.Shader, GL_VERTEX_SHADER,
                                                vertex_shader_string)
        fragment_shader = self.gl_create_resource(gl.Shader,
                                                  GL_FRAGMENT_SHADER,
                                                  fragment_shader_string)
        program = self.gl_create_resource(gl.Program, vertex_shader,
                                          fragment_shader)
        self.gl_delete_resource(vertex_shader)
        self.gl_delete_resource(fragment_shader)

        glUseProgram(program)

        matrix_block_index = glGetUniformBlockIndex(program, b'MatrixBlock')
        glUniformBlockBinding(program, matrix_block_index,
                              MATRIX_BLOCK_BINDING_POINT)

        material_block_index = glGetUniformBlockIndex(program,
                                                      b'MaterialBlock')
        if material_block_index != GL_INVALID_INDEX:
            glUniformBlockBinding(program, material_block_index,
                                  MATERIAL_BLOCK_BINDING_POINT)

        program.matrix_index_location = glGetUniformLocation(
            program, 'matrix_index')  #<-?

        matrix_table_location = glGetUniformLocation(program, 'matrix_table')
        if matrix_table_location != -1:
            glUniform1i(matrix_table_location, MATRIX_TABLE_TEXTURE_UNIT)

        for i in range(8):
            location = glGetUniformLocation(program, 'texmap{}'.format(i))
            if location == -1: continue
            glUniform1i(location, TEXTURE_UNITS[i])

        self.gl_program_table[transformation_type] = program
        return program

    def gl_shader_invalidate(self):
        for program in self.gl_program_table.values():
            self.gl_delete_resource(program)
        self.gl_program_table.clear()

    @property
    def gl_cull_mode(self):
        if self.cull_mode == gx.CULL_FRONT:
            return GL_FRONT
        if self.cull_mode == gx.CULL_BACK:
            return GL_BACK
        if self.cull_mode == gx.CULL_ALL:
            return GL_FRONT_AND_BACK
        raise ValueError('Invalid cull mode: {}'.format(self.cull_mode))

    @property
    def gl_depth_function(self):
        if self.depth_mode.function == gx.NEVER:
            return GL_NEVER
        if self.depth_mode.function == gx.LESS:
            return GL_LESS
        if self.depth_mode.function == gx.EQUAL:
            return GL_EQUAL
        if self.depth_mode.function == gx.LEQUAL:
            return GL_LEQUAL
        if self.depth_mode.function == gx.GREATER:
            return GL_GREATER
        if self.depth_mode.function == gx.NEQUAL:
            return GL_NOTEQUAL
        if self.depth_mode.function == gx.GEQUAL:
            return GL_GEQUAL
        if self.depth_mode.function == gx.ALWAYS:
            return GL_ALWAYS
        raise ValueError('Invalid compare function: {}'.format(
            self.depth_mode.function))

    @property
    def gl_blend_source_factor(self):
        if self.blend_mode.source_factor == gx.BL_ZERO:
            return GL_ZERO
        if self.blend_mode.source_factor == gx.BL_ONE:
            return GL_ONE
        if self.blend_mode.source_factor == gx.BL_SRCALPHA:
            return GL_SRC_ALPHA
        if self.blend_mode.source_factor == gx.BL_INVSRCALPHA:
            return GL_ONE_MINUS_SRC_ALPHA
        if self.blend_mode.source_factor == gx.BL_DSTALPHA:
            return GL_DST_ALPHA
        if self.blend_mode.source_factor == gx.BL_INVDSTALPHA:
            return GL_ONE_MINUS_DST_ALPHA
        if self.blend_mode.source_factor == gx.BL_DSTCLR:
            return GL_DST_COLOR
        if self.blend_mode.source_factor == gx.BL_INVDSTCLR:
            return GL_ONE_MINUS_DST_COLOR
        raise ValueError('Invalid blend source factor: {}'.format(
            self.blend_mode.source_factor))

    @property
    def gl_blend_destination_factor(self):
        if self.blend_mode.destination_factor == gx.BL_ZERO:
            return GL_ZERO
        if self.blend_mode.destination_factor == gx.BL_ONE:
            return GL_ONE
        if self.blend_mode.destination_factor == gx.BL_SRCALPHA:
            return GL_SRC_ALPHA
        if self.blend_mode.destination_factor == gx.BL_INVSRCALPHA:
            return GL_ONE_MINUS_SRC_ALPHA
        if self.blend_mode.destination_factor == gx.BL_DSTALPHA:
            return GL_DST_ALPHA
        if self.blend_mode.destination_factor == gx.BL_INVDSTALPHA:
            return GL_ONE_MINUS_DST_ALPHA
        if self.blend_mode.destination_factor == gx.BL_SRCCLR:
            return GL_SRC_COLOR
        if self.blend_mode.destination_factor == gx.BL_INVSRCCLR:
            return GL_ONE_MINUS_SRC_COLOR
        raise ValueError('Invalid blend destination factor: {}'.format(
            self.blend_mode.destination_factor))

    @property
    def gl_blend_logical_operation(self):
        if self.blend_mode.logical_operation == gx.LO_CLEAR:
            return GL_CLEAR
        if self.blend_mode.logical_operation == gx.LO_AND:
            return GL_AND
        if self.blend_mode.logical_operation == gx.LO_REVAND:
            return GL_AND_REVERSE
        if self.blend_mode.logical_operation == gx.LO_COPY:
            return GL_COPY
        if self.blend_mode.logical_operation == gx.LO_INVAND:
            return GL_AND_INVERTED
        if self.blend_mode.logical_operation == gx.LO_NOOP:
            return GL_NOOP
        if self.blend_mode.logical_operation == gx.LO_XOR:
            return GL_XOR
        if self.blend_mode.logical_operation == gx.LO_OR:
            return GL_OR
        if self.blend_mode.logical_operation == gx.LO_NOR:
            return GL_NOR
        if self.blend_mode.logical_operation == gx.LO_EQUIV:
            return GL_EQUIV
        if self.blend_mode.logical_operation == gx.LO_INV:
            return GL_INVERT
        if self.blend_mode.logical_operation == gx.LO_REVOR:
            return GL_OR_INVERTED
        if self.blend_mode.logical_operation == gx.LO_INVCOPY:
            return GL_COPY_INVERTED
        if self.blend_mode.logical_operation == gx.LO_INVOR:
            return GL_OR_INVERTED
        if self.blend_mode.logical_operation == gx.LO_INVNAND:
            return GL_NAND
        if self.blend_mode.logical_operation == gx.LO_SET:
            return GL_SET
        raise ValueError('Invalid logical operation: {}'.format(
            self.blend_mode.logical_operation))

    def gl_bind(self, shape):
        self.gl_block.bind(MATERIAL_BLOCK_BINDING_POINT)

        for i, texture in enumerate(self.textures):
            if texture is None:
                continue
            texture.gl_bind(TEXTURE_UNITS[i])

        if self.cull_mode != gx.CULL_NONE:
            glEnable(GL_CULL_FACE)
            glCullFace(self.gl_cull_mode)
        else:
            glDisable(GL_CULL_FACE)

        if self.depth_mode.enable:
            glEnable(GL_DEPTH_TEST)
            glDepthFunc(self.gl_depth_function)
            glDepthMask(self.depth_mode.update_enable)
        else:
            glDisable(GL_DEPTH_TEST)

        if self.blend_mode.function == gx.BM_BLEND:
            glEnable(GL_BLEND)
            glBlendEquation(GL_FUNC_ADD)
            glBlendFunc(self.gl_blend_source_factor,
                        self.gl_blend_destination_factor)
        elif self.blend_mode.function == gx.BM_SUBTRACT:
            glEnable(GL_BLEND)
            glBlendEquation(GL_FUNC_REVERSE_SUBTRACT)
            glBlendFunc(GL_ONE, GL_ONE)
        else:
            glDisable(GL_BLEND)

        if self.blend_mode.function == gx.BM_LOGIC:
            glEnable(GL_COLOR_LOGIC_OP)
            glLogicOp(self.gl_blend_logical_operation)
        else:
            glDisable(GL_COLOR_LOGIC_OP)

        if self.dither:
            glEnable(GL_DITHER)
        else:
            glDisable(GL_DITHER)

        program = self.gl_program(shape.transformation_type)

        glUseProgram(program)

        if shape.transformation_type == 0:
            glUniform1i(program.matrix_index_location,
                        shape.batches[0].matrix_table[0])

    def gl_delete(self):
        super().gl_delete()
        try:
            del self.gl_block
        except AttributeError:
            pass
        self.gl_program_table.clear()
Exemple #6
0
class BlendMode(WrapperModel):
    function = _attribute()
    source_factor = _attribute()
    destination_factor = _attribute()
    logical_operation = _attribute()
Exemple #7
0
class DepthMode(WrapperModel):
    enable = _attribute()
    function = _attribute()
    update_enable = _attribute()
Exemple #8
0
class AlphaTest(WrapperModel):
    function0 = _attribute()
    reference0 = _attribute()
    function1 = _attribute()
    reference1 = _attribute()
    operator = _attribute()
Exemple #9
0
class ShapeNode(SceneGraphNode):
    node_type = _attribute()
    index = _attribute()
    children = _attribute(_list(SceneGraphNode.create_node))
Exemple #10
0
class TextureMatrix(WrapperModel):
    shape = _attribute()
    matrix_type = _attribute()
    center_s = _attribute()
    center_t = _attribute()
    unknown0 = _attribute()
    scale_s = _attribute()
    scale_t = _attribute()
    rotation = _attribute()
    translation_s = _attribute()
    translation_t = _attribute()
    projection_matrix = _attribute()

    def create_matrix(self):
        return self.wrapped_object.create_matrix()
Exemple #11
0
class SwapTable(WrapperModel):
    r = _attribute()
    g = _attribute()
    b = _attribute()
    a = _attribute()
Exemple #12
0
class TevStage(WrapperModel):
    texcoord = _attribute()
    texture = _attribute()
    color = _attribute()
    color_mode = _attribute(TevMode)
    alpha_mode = _attribute(TevMode)
    constant_color = _attribute()
    constant_alpha = _attribute()
    color_swap_table = _attribute()
    texture_swap_table = _attribute()
    indirect_stage = _attribute()
    indirect_format = _attribute()
    indirect_bias_components = _attribute()
    indirect_matrix = _attribute()
    wrap_s = _attribute()
    wrap_t = _attribute()
    add_previous_texcoord = _attribute()
    use_original_lod = _attribute()
    bump_alpha = _attribute()
    unknown0 = _attribute()
    unknown1 = _attribute()
Exemple #13
0
class Texture(WrapperModel):

    name = _attribute()
    wrap_s = SamplerInvalidatingAttribute()
    wrap_t = SamplerInvalidatingAttribute()
    minification_filter = SamplerInvalidatingAttribute()
    magnification_filter = SamplerInvalidatingAttribute()
    minimum_lod = SamplerInvalidatingAttribute()
    maximum_lod = SamplerInvalidatingAttribute()
    lod_bias = SamplerInvalidatingAttribute()
    unknown0 = _attribute()
    unknown1 = _attribute()
    unknown2 = _attribute()
    palette = _attribute()
    images = _attribute()

    @property
    def width(self):
        return self.images[0].width

    @property
    def height(self):
        return self.images[0].height

    @property
    def image_format(self):
        return self.images[0].image_format

    @property
    def palette_format(self):
        return self.palette.palette_format

    @property
    def gl_wrap_s(self):
        if self.wrap_s == gx.CLAMP:
            return GL_CLAMP_TO_EDGE
        if self.wrap_s == gx.REPEAT:
            return GL_REPEAT
        if self.wrap_s == gx.MIRROR:
            return GL_MIRRORED_REPEAT
        raise ValueError('Invalid wrap: {}'.format(self.wrap_s))

    @property
    def gl_wrap_t(self):
        if self.wrap_t == gx.CLAMP:
            return GL_CLAMP_TO_EDGE
        if self.wrap_t == gx.REPEAT:
            return GL_REPEAT
        if self.wrap_t == gx.MIRROR:
            return GL_MIRRORED_REPEAT
        raise ValueError('Invalid wrap: {}'.format(self.wrap_t))

    @property
    def gl_minification_filter(self):
        if self.minification_filter == gx.NEAR:
            return GL_LINEAR
        if self.minification_filter == gx.LINEAR:
            return GL_LINEAR
        if self.minification_filter == gx.NEAR_MIP_NEAR:
            return GL_NEAREST_MIPMAP_NEAREST
        if self.minification_filter == gx.LIN_MIP_NEAR:
            return GL_LINEAR_MIPMAP_NEAREST
        if self.minification_filter == gx.NEAR_MIP_LIN:
            return GL_NEAREST_MIPMAP_LINEAR
        if self.minification_filter == gx.LIN_MIP_LIN:
            return GL_LINEAR_MIPMAP_LINEAR
        raise ValueError('Invalid minification filter: {}'.format(
            self.minification_filter))

    @property
    def gl_magnification_filter(self):
        if self.magnification_filter == gx.NEAR:
            return GL_LINEAR
        if self.magnification_filter == gx.LINEAR:
            return GL_LINEAR
        raise ValueError('Invalid magnification filter: {}'.format(
            self.magnification_filter))

    @LazyProperty
    def _gl_sampler(self):
        return self.gl_create_resource(gl.Sampler)

    @LazyProperty
    def gl_sampler(self):
        glSamplerParameteri(self._gl_sampler, GL_TEXTURE_WRAP_S,
                            self.gl_wrap_s)
        glSamplerParameteri(self._gl_sampler, GL_TEXTURE_WRAP_T,
                            self.gl_wrap_t)
        glSamplerParameteri(self._gl_sampler, GL_TEXTURE_MIN_FILTER,
                            self.gl_minification_filter)
        glSamplerParameteri(self._gl_sampler, GL_TEXTURE_MAG_FILTER,
                            self.gl_magnification_filter)
        glSamplerParameterf(self._gl_sampler, GL_TEXTURE_MIN_LOD,
                            self.minimum_lod)
        glSamplerParameterf(self._gl_sampler, GL_TEXTURE_MAX_LOD,
                            self.maximum_lod)
        glSamplerParameterf(self._gl_sampler, GL_TEXTURE_LOD_BIAS,
                            self.lod_bias)
        return self._gl_sampler

    def gl_sampler_invalidate(self):
        try:
            del self.gl_sampler
        except AttributeError:
            pass

    @LazyProperty
    def _gl_texture(self):
        return self.gl_create_resource(gl.Texture)

    @LazyProperty
    def gl_texture(self):
        if self.image_format in {gx.TF_I4, gx.TF_I8}:
            image_format = GL_UNSIGNED_BYTE
            component_count = GL_RED
            swizzle = [GL_RED, GL_RED, GL_RED, GL_RED]
            convert = lambda image: image.decode_to_i8()
        elif self.image_format in {gx.TF_IA4, gx.TF_IA8}:
            image_format = GL_UNSIGNED_BYTE
            component_count = GL_RG
            swizzle = [GL_RED, GL_RED, GL_RED, GL_GREEN]
            convert = lambda image: image.decode_to_ia8()
        elif self.image_format == gx.TF_RGB565:
            image_format = GL_UNSIGNED_SHORT_5_6_5
            component_count = GL_RGB
            swizzle = [GL_RED, GL_GREEN, GL_BLUE, GL_ONE]
            convert = lambda image: image.decode_to_rgb565()
        elif self.image_format in {gx.TF_RGB5A3, gx.TF_RGBA8, gx.TF_CMPR}:
            image_format = GL_UNSIGNED_BYTE
            component_count = GL_RGBA
            swizzle = [GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA]
            convert = lambda image: image.decode_to_rgba8()
        elif self.image_format in {gx.TF_CI4, gx.TF_CI8, gx.TF_CI14}:
            if self.palette_format == gx.TL_IA8:
                image_format = GL_UNSIGNED_BYTE
                component_count = GL_RG
                swizzle = [GL_RED, GL_RED, GL_RED, GL_GREEN]
                palette = self.palette.decode_to_ia8()
            elif self.palette_format == gx.TL_RGB565:
                image_format = GL_UNSIGNED_SHORT_5_6_5
                component_count = GL_RGB
                swizzle = [GL_RED, GL_GREEN, GL_BLUE, GL_ONE]
                palette = self.palette.decode_to_rgb565()
            elif self.palette_format == gx.TL_RGB5A3:
                image_format = GL_UNSIGNED_BYTE
                component_count = GL_RGBA
                swizzle = [GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA]
                palette = self.palette.decode_to_rgba8()
            else:
                raise ValueError('Invalid palette format: {}'.format(
                    self.palette_format))
            convert = lambda image: image.decode_to_direct_color(palette)
        else:
            raise ValueError('Invalid image format: {}'.format(
                self.image_format))

        glBindTexture(GL_TEXTURE_2D, self._gl_texture)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,
                        len(self.images) - 1)
        glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA,
                         numpy.array(swizzle, numpy.int32))

        for level, image in enumerate(self.images):
            glTexImage2D(GL_TEXTURE_2D, level, component_count, image.width,
                         image.height, 0, component_count, image_format,
                         convert(image))

        return self._gl_texture

    def gl_texture_invalidate(self):
        try:
            del self.gl_texture
        except AttributeError:
            pass

    def gl_bind(self, texture_unit):
        glBindSampler(texture_unit, self.gl_sampler)
        glActiveTexture(GL_TEXTURE0 + texture_unit)
        glBindTexture(GL_TEXTURE_2D, self.gl_texture)

    def gl_delete(self):
        super().gl_delete()
        try:
            del self.gl_sampler
        except AttributeError:
            pass
        try:
            del self._gl_sampler
        except AttributeError:
            pass
        try:
            del self.gl_texture
        except AttributeError:
            pass
        try:
            del self._gl_texture
        except AttributeError:
            pass

    @staticmethod
    def load(file_path):
        with open(file_path, 'rb') as stream:
            texture = gx.bti.unpack(stream)
        texture.name = os.path.splitext(os.path.basename(file_path))[0]
        return Texture(texture)

    def save(self, file_path):
        with open(file_path, 'wb') as stream:
            gx.bti.pack(stream, self.viewed_object)
Exemple #14
0
class Model(WrapperModel):
    def __init__(self, wrapped_object):
        super().__init__(wrapped_object)
        self.file_path = None
        self.init_references()

    file_type = _attribute()
    subversion = _attribute()
    scene_graph = _attribute(SceneGraph)
    position_array = _attribute()
    normal_array = _attribute()
    color_arrays = _attribute()
    texcoord_arrays = _attribute()
    influence_groups = _attribute()
    inverse_bind_matrices = _attribute()
    matrix_definitions = _attribute()
    joints = _attribute()
    shapes = _attribute(_list(models.shape.Shape))
    materials = _attribute(_list(models.material.Material))
    textures = _attribute(_list(models.texture.Texture))

    def gl_init(self):
        array_table = {}
        array_table[gx.VA_PTNMTXIDX] = GLMatrixIndexArray()
        array_table.update({
            attribute: GLDirectArray(attribute)
            for attribute in gx.VA_TEXMTXIDX
        })
        array_table[gx.VA_POS] = gl_convert_array(self.position_array)
        array_table[gx.VA_NRM] = gl_convert_array(self.normal_array)
        array_table.update({
            attribute: gl_convert_color_array(array)
            for attribute, array in zip(gx.VA_CLR, self.color_arrays)
        })
        array_table.update({
            attribute: gl_convert_array(array)
            for attribute, array in zip(gx.VA_TEX, self.texcoord_arrays)
        })

        for shape in self.shapes:
            shape.gl_init(array_table)

        self.gl_joints = [copy.copy(joint) for joint in self.joints]
        self.gl_joint_matrices = numpy.empty((len(self.joints), 3, 4),
                                             numpy.float32)
        self.gl_matrix_table = self.gl_create_resource(
            gl.TextureBuffer, GL_DYNAMIC_DRAW, GL_RGBA32F,
            (len(self.matrix_definitions), 3, 4), numpy.float32)
        self.gl_update_matrix_table()

    def gl_update_joint_matrices(self,
                                 node,
                                 parent_joint=None,
                                 parent_joint_matrix=numpy.eye(
                                     3, 4, dtype=numpy.float32)):
        for child in node.children:
            if child.node_type == NodeType.JOINT:
                joint = self.gl_joints[child.index]
                joint_matrix = self.gl_joint_matrices[child.index]
                joint_matrix[:] = joint.create_matrix(parent_joint,
                                                      parent_joint_matrix)
                self.gl_update_joint_matrices(child, joint, joint_matrix)
            else:
                self.gl_update_joint_matrices(child, parent_joint,
                                              parent_joint_matrix)

    def gl_update_matrix_table(self):
        self.gl_update_joint_matrices(self.scene_graph)

        if self.inverse_bind_matrices is not None:
            influence_matrices = matrix3x4_array_multiply(
                self.gl_joint_matrices, self.inverse_bind_matrices)

        for matrix, matrix_definition in zip(self.gl_matrix_table,
                                             self.matrix_definitions):
            if matrix_definition.matrix_type == MatrixType.JOINT:
                matrix[:] = self.gl_joint_matrices[matrix_definition.index]
            elif matrix_definition.matrix_type == MatrixType.INFLUENCE_GROUP:
                influence_group = self.influence_groups[
                    matrix_definition.index]
                matrix[:] = sum(influence.weight *
                                influence_matrices[influence.index]
                                for influence in influence_group)
            else:
                ValueError('invalid matrix type')

    def gl_draw_shape(self, material, shape):
        if shape.gl_hide: return
        material.gl_bind(shape)
        shape.gl_bind()
        shape.gl_draw()

    def gl_draw_node(self, node, parent_material=None):
        for child in node.children:
            if child.node_type == NodeType.SHAPE:
                if parent_material.unknown0 == 1:
                    self.gl_draw_shape(parent_material,
                                       self.shapes[child.index])
                self.gl_draw_node(child, parent_material)
                if parent_material.unknown0 == 4:
                    self.gl_draw_shape(parent_material,
                                       self.shapes[child.index])
            elif child.node_type == NodeType.MATERIAL:
                self.gl_draw_node(child, child.material)
            else:
                self.gl_draw_node(child, parent_material)

    def gl_draw(self):
        self.gl_matrix_table.bind_texture(
            models.material.MATRIX_TABLE_TEXTURE_UNIT)
        self.gl_draw_node(self.scene_graph)

    @staticmethod
    def load(file_path):
        with open(file_path, 'rb') as stream:
            model = j3d.model.unpack(stream)
        model = Model(model)
        model.file_path = file_path
        return model

    def save(self, file_path):
        self.file_path = file_path
        self.sync_reference_indices()
        with open(file_path, 'wb') as stream:
            j3d.model.pack(stream, self.wrapped_object)

    def init_references(self):
        """Initialize references.

        Initialize references into the material and texture lists.
        """
        for node in self.scene_graph.all_nodes():
            if node.node_type == NodeType.MATERIAL:
                node.material = self.materials[node.wrapped_object.index]

        for material in self.materials:
            material.textures = ReferenceList(
                self.
                textures[texture_index] if texture_index is not None else None
                for texture_index in material.wrapped_object.texture_indices)

    def sync_reference_indices(self):
        """Synchronize reference indices.

        Indices used to reference into the material and texture lists are not
        automatically kept in sync. This method needs to be manually called to
        synchronize the reference indices.
        """
        for node in self.scene_graph.all_nodes():
            if node.node_type == NodeType.MATERIAL:
                node.wrapped_object.index = self.materials.index(node.material)

        for material in self.materials:
            for i, texture in enumerate(material.textures):
                texture_index = None
                if texture is not None:
                    texture_index = self.textures.index(texture)
                material.wrapped_object.texture_indices[i] = texture_index

    def get_nodes_using_material(self, material_index):
        """Get scene graph nodes that use a given material.

        :param material_index: Index of the material in the material list.
        :return: List of the scene graph nodes that use the material.
        """
        material = self.materials[material_index]
        nodes = []
        for node in self.scene_graph.all_nodes():
            if node.node_type == NodeType.MATERIAL and node.material == material:
                nodes.append(node)
        return nodes

    def get_materials_using_texture(self, texture_index):
        """Get materials that use a given texture.

        :param texture_index: Index of the texture in the texture list.
        :return: List of the materials that use the texture.
        """
        texture = self.textures[texture_index]
        materials = []
        for material in self.materials:
            if texture in material.textures:
                materials.append(material)
                continue
        return materials
Exemple #15
0
class Channel(WrapperModel):
    color_mode = _attribute(LightingMode)
    alpha_mode = _attribute(LightingMode)
    material_color = _attribute()
    ambient_color = _attribute()
Exemple #16
0
class TexCoordGenerator(WrapperModel):
    function = _attribute()
    source = _attribute()
    matrix = _attribute()
Exemple #17
0
class IndirectStage(WrapperModel):
    texcoord = _attribute()
    texture = _attribute()
    scale_s = _attribute()
    scale_t = _attribute()
Exemple #18
0
class IndirectMatrix(WrapperModel):
    significand_matrix = _attribute()
    scale_exponent = _attribute()
Exemple #19
0
class MaterialNode(SceneGraphNode):
    node_type = _attribute()
    material = ReferenceAttribute()
    children = _attribute(_list(SceneGraphNode.create_node))