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

Last change on this file since 467 was 467, checked in by epyon, 10 years ago
  • wx_canvas - color logging
  • string - _sh64/_sh32 literal support
  • skeletal_mesh - removed obsolete CPU support
File size: 4.7 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{
[287]15        m_prepared  = false;
16        m_children  = nullptr;
17        m_offsets   = nullptr;
[428]18        m_bone_ids  = new sint16[m_node_data->size()];
[287]19
[419]20        NV_ASSERT( m_node_data, "node data empty!" );
21
[287]22        if ( !m_node_data->is_flat() )
23        {
[428]24                m_children = new vector< uint32 >[m_node_data->size()];
25                for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]26                {
[427]27                        const data_channel_set* node = (*m_node_data)[n];
28                        if ( node->get_parent_id() != -1 )
[287]29                        {
[427]30                                m_children[ node->get_parent_id()].push_back( n );
[287]31                        }
32                }
33        }
[283]34}
35
[467]36void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 time ) const
[283]37{
[290]38        float tick_time = ( time * 0.001f ) * m_frame_rate;
39        float anim_time = m_start;
40        if ( m_duration > 0.0f ) anim_time += fmodf( tick_time, m_duration );
[287]41
42        if ( !m_node_data->is_flat() )
43        {
44                animate_rec( data, anim_time, 0, mat4() );
45                return;
46        }
47
[428]48        for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]49                if ( m_bone_ids[n] >= 0 )
50                {
[428]51                        const data_channel_set* node = (*m_node_data)[n];
[427]52                        nv::mat4 node_mat( node->get_transform() );
[287]53
[427]54                        if ( node->size() > 0 )
[287]55                        {
[427]56                                raw_channel_interpolator interpolator( node, m_interpolation_key );
[419]57                                node_mat = interpolator.get< mat4 >( anim_time );
[287]58                        }
59
60                        sint16 bone_id = m_bone_ids[n];
61                        data[ bone_id ] = node_mat * m_offsets[ bone_id ];
62                }
[283]63}
64
[467]65void nv::skeletal_animation_entry::prepare( const mesh_nodes_data* bones )
[283]66{
[287]67        if ( m_prepared ) return;
[420]68        unordered_map< uint64, uint16 > bone_names;
[428]69        m_offsets = new mat4[ bones->size() ];
70        for ( nv::uint16 bi = 0; bi < bones->size(); ++bi )
[287]71        {
[428]72                const data_channel_set* bone = (*bones)[ bi ];
[431]73                bone_names[ bone->get_name().value() ] = bi;
[427]74                m_offsets[bi] = bone->get_transform();
[287]75        }
76
[428]77        for ( uint32 n = 0; n < m_node_data->size(); ++n )
[287]78        {
[428]79                const data_channel_set* node = (*m_node_data)[ n ];
[287]80                sint16 bone_id = -1;
81
[431]82                auto bi = bone_names.find( node->get_name().value() );
[287]83                if ( bi != bone_names.end() )
84                {
[406]85                        bone_id = sint16( bi->second );
[287]86                }
87                m_bone_ids[n] = bone_id;
[419]88
[427]89                if ( m_interpolation_key.size() == 0 && node->size() > 0 )
90                        m_interpolation_key = node->get_interpolation_key();
[419]91
[287]92        }
93        m_prepared = true;
[283]94}
95
[467]96void nv::skeletal_animation_entry::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
[287]97{
98        // TODO: fix transforms, which are now embedded,
99        //       see note in assimp_loader.cc:load_node
[428]100        const data_channel_set* node = ( *m_node_data )[ node_id ];
[427]101        mat4 node_mat( node->get_transform() );
[287]102
[427]103        if ( node->size() > 0 )
[287]104        {
[427]105                raw_channel_interpolator interpolator( node, m_interpolation_key );
[419]106                node_mat = interpolator.get< mat4 >( time );
[287]107        }
108
109        mat4 global_mat = parent_mat * node_mat;
110
111        sint16 bone_id = m_bone_ids[ node_id ];
112        if ( bone_id >= 0 )
113        {
114                data[ bone_id ] = global_mat * m_offsets[ bone_id ];
115        }
116
117        for ( auto child : m_children[ node_id ] )
118        {
119                animate_rec( data, time, child, global_mat );
120        }
121}
122
[467]123nv::skeletal_animation_entry::~skeletal_animation_entry()
[287]124{
125        delete[] m_offsets;
126        delete[] m_children;
127        delete[] m_bone_ids;
128}
129
[467]130nv::skeletal_mesh::skeletal_mesh( context* a_context, const data_channel_set* a_mesh, const mesh_nodes_data* a_bone_data )
131        : m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr )
[287]132{
[458]133        if ( a_mesh )
134        {
135                m_va = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
136                m_index_count = a_mesh->get_channel_size( slot::INDEX );
137        }
[287]138        if ( m_bone_data )
139        {
[428]140                m_transform = new mat4[ m_bone_data->size() ];
[287]141        }
142}
143
[467]144void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
[283]145{
[287]146        if ( m_bone_data && a_anim )
[283]147        {
[467]148                skeletal_animation_entry * anim = static_cast<skeletal_animation_entry*>( a_anim );
[296]149                anim->prepare( m_bone_data );
[287]150                anim->update_skeleton( m_transform, a_anim_time );
[283]151        }
152}
153
[467]154void nv::skeletal_mesh::update( program a_program )
[283]155{
[287]156        if ( m_bone_data )
[428]157                m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->size() );
[287]158}
159
[467]160nv::transform nv::skeletal_mesh::get_node_transform( uint32 node_id ) const
[287]161{
[290]162        if ( node_id == 0 ) return transform();
[458]163        if ( node_id == uint32(-1) ) return transform( m_transform[0] );
[287]164        return transform( m_transform[ node_id ] );
165}
166
[467]167nv::mat4 nv::skeletal_mesh::get_node_matrix( uint32 node_id ) const
[287]168{
169        return m_transform[ node_id ];
170}
Note: See TracBrowser for help on using the repository browser.