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

Last change on this file since 380 was 367, checked in by epyon, 10 years ago
  • fixed compilation and warnings on gcc
  • slowly removing/merging external includes
File size: 6.8 KB
Line 
1// Copyright (C) 2011-2014 ChaosForge Ltd
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gfx/skeletal_mesh.hh"
6
7#include "nv/interface/context.hh"
8#include "nv/interface/device.hh"
9
10nv::skeletal_mesh_cpu::skeletal_mesh_cpu( context* a_context, const mesh_data* a_mesh_data, const mesh_nodes_data* bones )
11        : skeletal_mesh( a_context )
12        , m_data( a_mesh_data )
13{
14        const mesh_raw_channel* pnt_chan = a_mesh_data->get_channel<md5_vtx_pnt>();
15        m_pntdata.assign( (const md5_vtx_pnt*)pnt_chan->data, pnt_chan->count );
16        m_bone_offset.resize( bones->get_count() );
17        m_transform.resize( bones->get_count() );
18
19        for ( uint32 i = 0; i < bones->get_count(); ++i )
20        {
21                m_bone_offset[i] = transform( bones->get_node(i)->transform );
22        }
23        m_vtx_data  = a_mesh_data->get_channel_data<md5_vtx_pntiw>();
24        m_indices   = a_mesh_data->get_count();
25        m_va        = a_context->create_vertex_array( a_mesh_data,
26STREAM_DRAW );
27        m_pbuffer   = a_context->find_buffer( m_va, slot::POSITION );
28}
29
30void nv::skeletal_mesh_cpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
31{
32        if ( a_anim )
33        {
34                skeletal_animation_entry_cpu * anim = (skeletal_animation_entry_cpu*)a_anim;
35                anim->update_skeleton( m_transform.data(), (float)a_anim_time );
36                {
37                        size_t skeleton_size = m_bone_offset.size();
38                        size_t vertex_count  = m_pntdata.size();
39                        m_pos_offset.resize( skeleton_size );
40                        for ( unsigned int i = 0; i < skeleton_size; ++i )
41                        {
42                                m_pos_offset[i] = m_transform[i] * m_bone_offset[i];
43                        }
44
45                        std::fill( m_pntdata.raw_data(), m_pntdata.raw_data() + m_pntdata.raw_size(), 0 );
46                        for ( unsigned int i = 0; i < vertex_count; ++i )
47                        {
48                                const md5_vtx_pntiw& vert = m_vtx_data[i];
49
50                                for ( size_t j = 0; j < 4; ++j )
51                                {
52                                        unsigned index = (unsigned)vert.boneindex[j];
53                                        float weight   = vert.boneweight[j];
54                                        const quat& orient      = m_transform[index].get_orientation();
55                                        const transform& offset = m_pos_offset[index];
56                                        m_pntdata[i].position += offset.transformed( vert.position )        * weight;
57                                        m_pntdata[i].normal   += ( orient * vert.normal  ) * weight;
58                                        m_pntdata[i].tangent  += ( orient * vert.tangent ) * weight;
59                                }
60                        }
61                }
62
63                m_context->update( m_pbuffer, m_pntdata.data(), 0, m_pntdata.raw_size() );
64        }
65}
66
67
68void nv::skeletal_animation_entry_cpu::update_skeleton( transform* skeleton, float time ) const
69{
70        float frame_duration = 1000.f / (float)m_node_data->get_frame_rate();
71        float anim_duration = frame_duration * m_node_data->get_duration();
72        float new_time = fmodf( time, anim_duration ) * 0.001f;
73
74        float frame_num = new_time * m_node_data->get_frame_rate();
75        for ( size_t i = 0; i < m_node_data->get_count(); ++i )
76        {
77                skeleton[i] = m_node_data->get_node(i)->data->get_transform( frame_num );
78        }
79}
80
81void nv::skeletal_animation_entry_gpu::initialize()
82{
83        m_prepared  = false;
84        m_children  = nullptr;
85        m_offsets   = nullptr;
86        uint32 node_count = m_node_data->get_count();
87        m_bone_ids  = new sint16[ node_count ];
88
89        if ( !m_node_data->is_flat() )
90        {
91                m_children = new std::vector< uint32 >[ node_count ];
92                for ( uint32 n = 0; n < node_count; ++n )
93                {
94                        const mesh_node_data* node = m_node_data->get_node(n);
95                        if ( node->parent_id != -1 )
96                        {
97                                m_children[ node->parent_id ].push_back( n );
98                        }
99                }
100        }
101}
102
103void nv::skeletal_animation_entry_gpu::update_skeleton( mat4* data, uint32 time ) const
104{
105        float tick_time = ( time * 0.001f ) * m_frame_rate;
106        float anim_time = m_start;
107        if ( m_duration > 0.0f ) anim_time += fmodf( tick_time, m_duration );
108
109        if ( !m_node_data->is_flat() )
110        {
111                animate_rec( data, anim_time, 0, mat4() );
112                return;
113        }
114
115        for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
116                if ( m_bone_ids[n] >= 0 )
117                {
118                        const mesh_node_data* node = m_node_data->get_node(n);
119                        nv::mat4 node_mat( node->transform );
120
121                        if ( node->data )
122                        {
123                                node_mat = node->data->get_matrix( anim_time );
124                        }
125
126                        sint16 bone_id = m_bone_ids[n];
127                        data[ bone_id ] = node_mat * m_offsets[ bone_id ];
128                }
129}
130
131void nv::skeletal_animation_entry_gpu::prepare( const mesh_nodes_data* bones )
132{
133        if ( m_prepared ) return;
134        std::unordered_map< std::string, nv::uint16 > bone_names;
135        m_offsets = new mat4[ bones->get_count() ];
136        for ( nv::uint16 bi = 0; bi < bones->get_count(); ++bi )
137        {
138                const mesh_node_data* bone = bones->get_node(bi);
139                bone_names[ bone->name ] = bi;
140                m_offsets[bi] = bone->transform;
141        }
142
143        for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
144        {
145                const mesh_node_data* node = m_node_data->get_node(n);
146                sint16 bone_id = -1;
147
148                auto bi = bone_names.find( node->name );
149                if ( bi != bone_names.end() )
150                {
151                        bone_id = (sint16)bi->second;
152                }
153                m_bone_ids[n] = bone_id;
154        }
155        m_prepared = true;
156}
157
158void nv::skeletal_animation_entry_gpu::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
159{
160        // TODO: fix transforms, which are now embedded,
161        //       see note in assimp_loader.cc:load_node
162        const mesh_node_data* node = m_node_data->get_node( node_id );
163        mat4 node_mat( node->transform );
164
165        if ( node->data )
166        {
167                node_mat = node->data->get_matrix( time );
168        }
169
170        mat4 global_mat = parent_mat * node_mat;
171
172        sint16 bone_id = m_bone_ids[ node_id ];
173        if ( bone_id >= 0 )
174        {
175                data[ bone_id ] = global_mat * m_offsets[ bone_id ];
176        }
177
178        for ( auto child : m_children[ node_id ] )
179        {
180                animate_rec( data, time, child, global_mat );
181        }
182}
183
184nv::skeletal_animation_entry_gpu::~skeletal_animation_entry_gpu()
185{
186        delete[] m_offsets;
187        delete[] m_children;
188        delete[] m_bone_ids;
189}
190
191nv::skeletal_mesh_gpu::skeletal_mesh_gpu( context* a_context, const mesh_data* a_mesh, const mesh_nodes_data* a_bone_data )
192        : skeletal_mesh( a_context ), m_bone_data( a_bone_data ), m_transform( nullptr )
193{
194        m_va          = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
195        m_index_count = a_mesh->get_count();
196        if ( m_bone_data )
197        {
198                m_transform = new mat4[ m_bone_data->get_count() ];
199        }
200}
201
202void nv::skeletal_mesh_gpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
203{
204        if ( m_bone_data && a_anim )
205        {
206                skeletal_animation_entry_gpu * anim = (skeletal_animation_entry_gpu*)a_anim;
207                anim->prepare( m_bone_data );
208                anim->update_skeleton( m_transform, a_anim_time );
209        }
210}
211
212void nv::skeletal_mesh_gpu::update( program a_program )
213{
214        if ( m_bone_data )
215                m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->get_count() );
216}
217
218nv::transform nv::skeletal_mesh_gpu::get_node_transform( uint32 node_id ) const
219{
220        if ( node_id == 0 ) return transform();
221        return transform( m_transform[ node_id ] );
222}
223
224nv::mat4 nv::skeletal_mesh_gpu::get_node_matrix( uint32 node_id ) const
225{
226        return m_transform[ node_id ];
227}
Note: See TracBrowser for help on using the repository browser.