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

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