source: trunk/src/gfx/skeletal_mesh.cc @ 471

Last change on this file since 471 was 471, checked in by epyon, 10 years ago
  • full math library
  • GLM dependency removed
File size: 5.5 KB
RevLine 
[395]1// Copyright (C) 2011-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
[227]6
7#include "nv/gfx/skeletal_mesh.hh"
8
9#include "nv/interface/context.hh"
10#include "nv/interface/device.hh"
[392]11#include "nv/stl/unordered_map.hh"
[227]12
[467]13void nv::skeletal_animation_entry::initialize()
[227]14{
[470]15        m_root      = uint32(-1);
[287]16        m_prepared  = false;
17        m_children  = nullptr;
18        m_offsets   = nullptr;
[428]19        m_bone_ids  = new sint16[m_node_data->size()];
[287]20
[419]21        NV_ASSERT( m_node_data, "node data empty!" );
22
[287]23        if ( !m_node_data->is_flat() )
24        {
[428]25                m_children = new vector< uint32 >[m_node_data->size()];
26                for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]27                {
[427]28                        const data_channel_set* node = (*m_node_data)[n];
29                        if ( node->get_parent_id() != -1 )
[287]30                        {
[427]31                                m_children[ node->get_parent_id()].push_back( n );
[287]32                        }
[470]33                        else
34                        {
35                                if ( m_root >= 0 )
36                                {
37                                        m_root = uint32( -2 );
38                                }
39                                else
40                                        m_root = n;
41                        }
[287]42                }
[470]43                NV_ASSERT( m_root != uint32( -1 ), "Animation without root!" );
[287]44        }
[283]45}
46
[470]47void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 a_ms_time ) const
[283]48{
[470]49        float  fframe   = ( a_ms_time * 0.001f ) * m_fps;
[471]50        uint32 frame    = uint32( math::floor( fframe ) );
[470]51        float  reminder = fframe - static_cast<float>( frame );
52        uint32 duration = get_frame_count();
53        if ( duration == 0 )
54        {
55                frame  = get_start_frame();
56                fframe = static_cast<float>( frame );
57        }
58        else if ( frame >= duration )
59        {
60                if ( is_looping() )
61                {
62                        frame  = frame % duration;
63                        fframe = static_cast<float>( frame ) + reminder;
64                }
65                else
66                {
67                        frame  = get_end_frame();
68                        fframe = static_cast<float>( frame );
69                }
70        }
[287]71
72        if ( !m_node_data->is_flat() )
73        {
[470]74                if ( m_root == uint32( -2 ) ) // multi-root
75                {
76                        for ( uint32 n = 0; n < m_node_data->size(); ++n )
77                                if ( ( *m_node_data )[n]->get_parent_id() == -1 )
78                                        animate_rec( data, fframe, n, mat4() );
79                }
80                else
81                        animate_rec( data, fframe, m_root, mat4() );
[287]82                return;
83        }
84
[428]85        for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]86                if ( m_bone_ids[n] >= 0 )
87                {
[428]88                        const data_channel_set* node = (*m_node_data)[n];
[427]89                        nv::mat4 node_mat( node->get_transform() );
[287]90
[427]91                        if ( node->size() > 0 )
[287]92                        {
[427]93                                raw_channel_interpolator interpolator( node, m_interpolation_key );
[470]94                                node_mat = interpolator.get< mat4 >( fframe );
[287]95                        }
96
97                        sint16 bone_id = m_bone_ids[n];
98                        data[ bone_id ] = node_mat * m_offsets[ bone_id ];
99                }
[283]100}
101
[467]102void nv::skeletal_animation_entry::prepare( const mesh_nodes_data* bones )
[283]103{
[287]104        if ( m_prepared ) return;
[470]105        nv::hash_store< shash64, uint16 > bone_names;
[428]106        m_offsets = new mat4[ bones->size() ];
107        for ( nv::uint16 bi = 0; bi < bones->size(); ++bi )
[287]108        {
[428]109                const data_channel_set* bone = (*bones)[ bi ];
[470]110                bone_names[ bone->get_name() ] = bi;
[427]111                m_offsets[bi] = bone->get_transform();
[287]112        }
113
[428]114        for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]115        {
[428]116                const data_channel_set* node = (*m_node_data)[ n ];
[287]117                sint16 bone_id = -1;
118
[470]119                auto bi = bone_names.find( node->get_name() );
[287]120                if ( bi != bone_names.end() )
121                {
[406]122                        bone_id = sint16( bi->second );
[287]123                }
124                m_bone_ids[n] = bone_id;
[419]125
[427]126                if ( m_interpolation_key.size() == 0 && node->size() > 0 )
127                        m_interpolation_key = node->get_interpolation_key();
[419]128
[287]129        }
130        m_prepared = true;
[283]131}
132
[467]133void nv::skeletal_animation_entry::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
[287]134{
135        // TODO: fix transforms, which are now embedded,
136        //       see note in assimp_loader.cc:load_node
[428]137        const data_channel_set* node = ( *m_node_data )[ node_id ];
[427]138        mat4 node_mat( node->get_transform() );
[287]139
[427]140        if ( node->size() > 0 )
[287]141        {
[427]142                raw_channel_interpolator interpolator( node, m_interpolation_key );
[419]143                node_mat = interpolator.get< mat4 >( time );
[287]144        }
145
146        mat4 global_mat = parent_mat * node_mat;
147
148        sint16 bone_id = m_bone_ids[ node_id ];
149        if ( bone_id >= 0 )
150        {
151                data[ bone_id ] = global_mat * m_offsets[ bone_id ];
152        }
153
154        for ( auto child : m_children[ node_id ] )
155        {
156                animate_rec( data, time, child, global_mat );
157        }
158}
159
[467]160nv::skeletal_animation_entry::~skeletal_animation_entry()
[287]161{
162        delete[] m_offsets;
163        delete[] m_children;
164        delete[] m_bone_ids;
165}
166
[467]167nv::skeletal_mesh::skeletal_mesh( context* a_context, const data_channel_set* a_mesh, const mesh_nodes_data* a_bone_data )
[470]168        : m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr ), m_parent_id(-1)
[287]169{
[458]170        if ( a_mesh )
171        {
172                m_va = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
173                m_index_count = a_mesh->get_channel_size( slot::INDEX );
[470]174                m_parent_id = a_mesh->get_parent_id();
[458]175        }
[287]176        if ( m_bone_data )
177        {
[428]178                m_transform = new mat4[ m_bone_data->size() ];
[287]179        }
180}
181
[467]182void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
[283]183{
[287]184        if ( m_bone_data && a_anim )
[283]185        {
[467]186                skeletal_animation_entry * anim = static_cast<skeletal_animation_entry*>( a_anim );
[296]187                anim->prepare( m_bone_data );
[287]188                anim->update_skeleton( m_transform, a_anim_time );
[283]189        }
190}
191
[467]192void nv::skeletal_mesh::update( program a_program )
[283]193{
[287]194        if ( m_bone_data )
[428]195                m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->size() );
[287]196}
197
[467]198nv::transform nv::skeletal_mesh::get_node_transform( uint32 node_id ) const
[287]199{
[290]200        if ( node_id == 0 ) return transform();
[458]201        if ( node_id == uint32(-1) ) return transform( m_transform[0] );
[287]202        return transform( m_transform[ node_id ] );
203}
204
[467]205nv::mat4 nv::skeletal_mesh::get_node_matrix( uint32 node_id ) const
[287]206{
207        return m_transform[ node_id ];
208}
Note: See TracBrowser for help on using the repository browser.