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 |
|
---|
13 | nv::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_channel_size( slot::INDEX );
|
---|
30 | m_va = a_context->create_vertex_array();
|
---|
31 |
|
---|
32 | //array_view< raw_data_channel* > channels = a_mesh_data->get_raw_channels();
|
---|
33 | for ( auto& channel : *a_mesh_data )
|
---|
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, desc );
|
---|
48 | }
|
---|
49 | }
|
---|
50 | }
|
---|
51 |
|
---|
52 | m_pbuffer = a_context->find_buffer( m_va, slot::POSITION );
|
---|
53 | }
|
---|
54 |
|
---|
55 | void 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 |
|
---|
93 | void nv::skeletal_animation_entry_cpu::initialize()
|
---|
94 | {
|
---|
95 | for ( size_t i = 0; i < m_node_data->get_count(); ++i )
|
---|
96 | {
|
---|
97 | if ( m_node_data->get_node( i )->data )
|
---|
98 | {
|
---|
99 | m_interpolation_key = m_node_data->get_node( i )->data->get_interpolation_key();
|
---|
100 | break;
|
---|
101 | }
|
---|
102 | }
|
---|
103 | }
|
---|
104 |
|
---|
105 | void nv::skeletal_animation_entry_cpu::update_skeleton( transform* skeleton, float time ) const
|
---|
106 | {
|
---|
107 | float frame_duration = 1000.f / static_cast<float>( m_node_data->get_frame_rate() );
|
---|
108 | float anim_duration = frame_duration * m_node_data->get_duration();
|
---|
109 | float new_time = fmodf( time, anim_duration ) * 0.001f;
|
---|
110 |
|
---|
111 | float frame_num = new_time * m_node_data->get_frame_rate();
|
---|
112 | for ( size_t i = 0; i < m_node_data->get_count(); ++i )
|
---|
113 | {
|
---|
114 | raw_channel_interpolator interpolator( m_node_data->get_node( i )->data, m_interpolation_key );
|
---|
115 | skeleton[i] = interpolator.get< transform >( frame_num );
|
---|
116 | }
|
---|
117 | }
|
---|
118 |
|
---|
119 | void nv::skeletal_animation_entry_gpu::initialize()
|
---|
120 | {
|
---|
121 | m_prepared = false;
|
---|
122 | m_children = nullptr;
|
---|
123 | m_offsets = nullptr;
|
---|
124 | uint32 node_count = m_node_data->get_count();
|
---|
125 | m_bone_ids = new sint16[ node_count ];
|
---|
126 |
|
---|
127 | NV_ASSERT( m_node_data, "node data empty!" );
|
---|
128 |
|
---|
129 | if ( !m_node_data->is_flat() )
|
---|
130 | {
|
---|
131 | m_children = new vector< uint32 >[ node_count ];
|
---|
132 | for ( uint32 n = 0; n < node_count; ++n )
|
---|
133 | {
|
---|
134 | const mesh_node_data* node = m_node_data->get_node(n);
|
---|
135 | if ( node->parent_id != -1 )
|
---|
136 | {
|
---|
137 | m_children[ node->parent_id ].push_back( n );
|
---|
138 | }
|
---|
139 | }
|
---|
140 | }
|
---|
141 | }
|
---|
142 |
|
---|
143 | void nv::skeletal_animation_entry_gpu::update_skeleton( mat4* data, uint32 time ) const
|
---|
144 | {
|
---|
145 | float tick_time = ( time * 0.001f ) * m_frame_rate;
|
---|
146 | float anim_time = m_start;
|
---|
147 | if ( m_duration > 0.0f ) anim_time += fmodf( tick_time, m_duration );
|
---|
148 |
|
---|
149 | if ( !m_node_data->is_flat() )
|
---|
150 | {
|
---|
151 | animate_rec( data, anim_time, 0, mat4() );
|
---|
152 | return;
|
---|
153 | }
|
---|
154 |
|
---|
155 | for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
|
---|
156 | if ( m_bone_ids[n] >= 0 )
|
---|
157 | {
|
---|
158 | const mesh_node_data* node = m_node_data->get_node(n);
|
---|
159 | nv::mat4 node_mat( node->transform );
|
---|
160 |
|
---|
161 | if ( node->data )
|
---|
162 | {
|
---|
163 | raw_channel_interpolator interpolator( node->data, m_interpolation_key );
|
---|
164 | node_mat = interpolator.get< mat4 >( anim_time );
|
---|
165 | }
|
---|
166 |
|
---|
167 | sint16 bone_id = m_bone_ids[n];
|
---|
168 | data[ bone_id ] = node_mat * m_offsets[ bone_id ];
|
---|
169 | }
|
---|
170 | }
|
---|
171 |
|
---|
172 | void nv::skeletal_animation_entry_gpu::prepare( const mesh_nodes_data* bones )
|
---|
173 | {
|
---|
174 | if ( m_prepared ) return;
|
---|
175 | unordered_map< std::string, nv::uint16 > bone_names;
|
---|
176 | m_offsets = new mat4[ bones->get_count() ];
|
---|
177 | for ( nv::uint16 bi = 0; bi < bones->get_count(); ++bi )
|
---|
178 | {
|
---|
179 | const mesh_node_data* bone = bones->get_node(bi);
|
---|
180 | bone_names[ bone->name ] = bi;
|
---|
181 | m_offsets[bi] = bone->transform;
|
---|
182 | }
|
---|
183 |
|
---|
184 | for ( uint32 n = 0; n < m_node_data->get_count(); ++n )
|
---|
185 | {
|
---|
186 | const mesh_node_data* node = m_node_data->get_node(n);
|
---|
187 | sint16 bone_id = -1;
|
---|
188 |
|
---|
189 | auto bi = bone_names.find( node->name );
|
---|
190 | if ( bi != bone_names.end() )
|
---|
191 | {
|
---|
192 | bone_id = sint16( bi->second );
|
---|
193 | }
|
---|
194 | m_bone_ids[n] = bone_id;
|
---|
195 |
|
---|
196 | if ( m_interpolation_key.size() == 0 && node->data )
|
---|
197 | m_interpolation_key = node->data->get_interpolation_key();
|
---|
198 |
|
---|
199 | }
|
---|
200 | m_prepared = true;
|
---|
201 | }
|
---|
202 |
|
---|
203 | void nv::skeletal_animation_entry_gpu::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
|
---|
204 | {
|
---|
205 | // TODO: fix transforms, which are now embedded,
|
---|
206 | // see note in assimp_loader.cc:load_node
|
---|
207 | const mesh_node_data* node = m_node_data->get_node( node_id );
|
---|
208 | mat4 node_mat( node->transform );
|
---|
209 |
|
---|
210 | if ( node->data )
|
---|
211 | {
|
---|
212 | raw_channel_interpolator interpolator( node->data, m_interpolation_key );
|
---|
213 | node_mat = interpolator.get< mat4 >( time );
|
---|
214 | }
|
---|
215 |
|
---|
216 | mat4 global_mat = parent_mat * node_mat;
|
---|
217 |
|
---|
218 | sint16 bone_id = m_bone_ids[ node_id ];
|
---|
219 | if ( bone_id >= 0 )
|
---|
220 | {
|
---|
221 | data[ bone_id ] = global_mat * m_offsets[ bone_id ];
|
---|
222 | }
|
---|
223 |
|
---|
224 | for ( auto child : m_children[ node_id ] )
|
---|
225 | {
|
---|
226 | animate_rec( data, time, child, global_mat );
|
---|
227 | }
|
---|
228 | }
|
---|
229 |
|
---|
230 | nv::skeletal_animation_entry_gpu::~skeletal_animation_entry_gpu()
|
---|
231 | {
|
---|
232 | delete[] m_offsets;
|
---|
233 | delete[] m_children;
|
---|
234 | delete[] m_bone_ids;
|
---|
235 | }
|
---|
236 |
|
---|
237 | nv::skeletal_mesh_gpu::skeletal_mesh_gpu( context* a_context, const mesh_data* a_mesh, const mesh_nodes_data* a_bone_data )
|
---|
238 | : skeletal_mesh( a_context ), m_bone_data( a_bone_data ), m_transform( nullptr )
|
---|
239 | {
|
---|
240 | m_va = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
|
---|
241 | m_index_count = a_mesh->get_channel_size( slot::INDEX );
|
---|
242 | if ( m_bone_data )
|
---|
243 | {
|
---|
244 | m_transform = new mat4[ m_bone_data->get_count() ];
|
---|
245 | }
|
---|
246 | }
|
---|
247 |
|
---|
248 | void nv::skeletal_mesh_gpu::update_animation( animation_entry* a_anim, uint32 a_anim_time )
|
---|
249 | {
|
---|
250 | if ( m_bone_data && a_anim )
|
---|
251 | {
|
---|
252 | skeletal_animation_entry_gpu * anim = static_cast<skeletal_animation_entry_gpu*>( a_anim );
|
---|
253 | anim->prepare( m_bone_data );
|
---|
254 | anim->update_skeleton( m_transform, a_anim_time );
|
---|
255 | }
|
---|
256 | }
|
---|
257 |
|
---|
258 | void nv::skeletal_mesh_gpu::update( program a_program )
|
---|
259 | {
|
---|
260 | if ( m_bone_data )
|
---|
261 | m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->get_count() );
|
---|
262 | }
|
---|
263 |
|
---|
264 | nv::transform nv::skeletal_mesh_gpu::get_node_transform( uint32 node_id ) const
|
---|
265 | {
|
---|
266 | if ( node_id == 0 ) return transform();
|
---|
267 | return transform( m_transform[ node_id ] );
|
---|
268 | }
|
---|
269 |
|
---|
270 | nv::mat4 nv::skeletal_mesh_gpu::get_node_matrix( uint32 node_id ) const
|
---|
271 | {
|
---|
272 | return m_transform[ node_id ];
|
---|
273 | }
|
---|