1 | // Copyright (C) 2014 ChaosForge / Kornel Kisielewicz
|
---|
2 | // http://chaosforge.org/
|
---|
3 | //
|
---|
4 | // This file is part of NV Libraries.
|
---|
5 | // For conditions of distribution and use, see copyright notice in nv.hh
|
---|
6 |
|
---|
7 | #include "nv/formats/nmd_loader.hh"
|
---|
8 | #include "nv/io/std_stream.hh"
|
---|
9 |
|
---|
10 | using namespace nv;
|
---|
11 |
|
---|
12 | bool nv::nmd_loader::load( stream& source )
|
---|
13 | {
|
---|
14 | // TODO: proper error handling
|
---|
15 | reset();
|
---|
16 | nmd_header root_header;
|
---|
17 | source.read( &root_header, sizeof( root_header ), 1 );
|
---|
18 | for ( uint32 i = 0; i < root_header.elements; ++i )
|
---|
19 | {
|
---|
20 | nmd_element_header element_header;
|
---|
21 | source.read( &element_header, sizeof( element_header ), 1 );
|
---|
22 | switch ( element_header.type )
|
---|
23 | {
|
---|
24 | case nmd_type::MESH : load_mesh( source, element_header.children ); break;
|
---|
25 | case nmd_type::ANIMATION : load_animation( source, element_header.children ); break;
|
---|
26 | case nmd_type::BONE_ARRAY : load_bones( source, element_header.children ); break;
|
---|
27 | case nmd_type::STRING_TABLE : load_strings( source ); break;
|
---|
28 | default: NV_ASSERT( false, "UNKNOWN NMD ELEMENT!" ); break;
|
---|
29 | }
|
---|
30 | }
|
---|
31 | return true;
|
---|
32 | }
|
---|
33 |
|
---|
34 | bool nv::nmd_loader::load_mesh( stream& source, uint32 children )
|
---|
35 | {
|
---|
36 | mesh_data* mesh = new mesh_data();
|
---|
37 | for ( uint32 s = 0; s < children; ++s )
|
---|
38 | {
|
---|
39 | nmd_element_header element_header;
|
---|
40 | source.read( &element_header, sizeof( element_header ), 1 );
|
---|
41 | NV_ASSERT( element_header.type == nmd_type::STREAM, "STREAM expected!" );
|
---|
42 |
|
---|
43 | nmd_stream_header stream_header;
|
---|
44 | source.read( &stream_header, sizeof( stream_header ), 1 );
|
---|
45 | mesh_raw_channel* channel = mesh_raw_channel::create( stream_header.format, stream_header.count );
|
---|
46 | source.read( channel->data, stream_header.format.size, stream_header.count );
|
---|
47 | mesh->add_channel( channel );
|
---|
48 | }
|
---|
49 | m_meshes.push_back( mesh );
|
---|
50 | return true;
|
---|
51 | }
|
---|
52 |
|
---|
53 | mesh_data* nv::nmd_loader::release_mesh_data( size_t index )
|
---|
54 | {
|
---|
55 | mesh_data* result = m_meshes[ index ];
|
---|
56 | m_meshes[ index ] = nullptr;
|
---|
57 | return result;
|
---|
58 | }
|
---|
59 |
|
---|
60 | void nv::nmd_loader::reset()
|
---|
61 | {
|
---|
62 | for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
|
---|
63 | if ( m_animation ) delete m_animation;
|
---|
64 | if ( m_strings ) delete m_strings;
|
---|
65 | if ( m_bone_data ) delete m_bone_data;
|
---|
66 | m_meshes.clear();
|
---|
67 | m_animation = nullptr;
|
---|
68 | m_bone_data = nullptr;
|
---|
69 | m_strings = nullptr;
|
---|
70 | }
|
---|
71 |
|
---|
72 | nv::nmd_loader::~nmd_loader()
|
---|
73 | {
|
---|
74 | reset();
|
---|
75 | }
|
---|
76 |
|
---|
77 | bool nv::nmd_loader::load_strings( stream& source )
|
---|
78 | {
|
---|
79 | NV_ASSERT( m_strings == nullptr, "MULTIPLE STRING ENTRIES!" );
|
---|
80 | m_strings = new string_table( &source );
|
---|
81 | return true;
|
---|
82 | }
|
---|
83 |
|
---|
84 | bool nv::nmd_loader::load_bones( stream& source, uint32 children )
|
---|
85 | {
|
---|
86 | NV_ASSERT( m_bone_data == nullptr, "MULTIPLE BONE ENTRIES!" );
|
---|
87 | m_bone_data = new nmd_bone_data;
|
---|
88 | m_bone_data->bones = new nmd_bone[ children ];
|
---|
89 | m_bone_data->count = (uint16)children;
|
---|
90 | source.read( m_bone_data->bones, sizeof( nmd_bone ), children );
|
---|
91 | return true;
|
---|
92 | }
|
---|
93 |
|
---|
94 | nmd_animation* nv::nmd_loader::release_animation()
|
---|
95 | {
|
---|
96 | nmd_animation* result = m_animation;
|
---|
97 | m_animation = nullptr;
|
---|
98 | return result;
|
---|
99 | }
|
---|
100 |
|
---|
101 | nmd_bone_data* nv::nmd_loader::release_bone_data()
|
---|
102 | {
|
---|
103 | nmd_bone_data* result = m_bone_data;
|
---|
104 | m_bone_data = nullptr;
|
---|
105 | return result;
|
---|
106 | }
|
---|
107 |
|
---|
108 | string_table* nv::nmd_loader::release_string_table()
|
---|
109 | {
|
---|
110 | string_table* result = m_strings;
|
---|
111 | m_strings = nullptr;
|
---|
112 | return result;
|
---|
113 | }
|
---|
114 |
|
---|
115 |
|
---|
116 | bool nv::nmd_loader::load_animation( stream& source, uint32 children )
|
---|
117 | {
|
---|
118 | NV_ASSERT( m_animation == nullptr, "MULTIPLE ANIMATION ENTRIES!" );
|
---|
119 | nmd_animation_header header;
|
---|
120 | source.read( &header, sizeof( header ), 1 );
|
---|
121 | m_animation = new nmd_animation;
|
---|
122 | m_animation->fps = header.fps;
|
---|
123 | m_animation->duration = header.duration;
|
---|
124 | m_animation->flat = header.flat;
|
---|
125 | m_animation->node_count = (uint16)children;
|
---|
126 | m_animation->nodes = new nmd_node[ children ];
|
---|
127 | for ( uint32 i = 0; i < children; ++i )
|
---|
128 | {
|
---|
129 | nmd_element_header element_header;
|
---|
130 | source.read( &element_header, sizeof( element_header ), 1 );
|
---|
131 | NV_ASSERT( element_header.type == nmd_type::ANIMATION_NODE, "ANIMATION_NODE expected!" );
|
---|
132 |
|
---|
133 | uint16 ch_count = element_header.children;
|
---|
134 |
|
---|
135 | nmd_animation_node_header node_header;
|
---|
136 | source.read( &node_header, sizeof( node_header ), 1 );
|
---|
137 | m_animation->nodes[i].name = node_header.name;
|
---|
138 | m_animation->nodes[i].parent_id = node_header.parent_id;
|
---|
139 | m_animation->nodes[i].transform = node_header.transform;
|
---|
140 | m_animation->nodes[i].channel_count = ch_count;
|
---|
141 | m_animation->nodes[i].channels = nullptr;
|
---|
142 | if ( ch_count > 0 )
|
---|
143 | {
|
---|
144 | m_animation->nodes[i].channels = new key_raw_channel* [ch_count];
|
---|
145 | for ( uint32 c = 0; c < ch_count; ++c )
|
---|
146 | {
|
---|
147 | source.read( &element_header, sizeof( element_header ), 1 );
|
---|
148 | NV_ASSERT( element_header.type == nmd_type::ANIMATION_CHANNEL, "ANIMATION_CHANNEL expected!" );
|
---|
149 | nv::nmd_animation_channel_header cheader;
|
---|
150 | source.read( &cheader, sizeof( cheader ), 1 );
|
---|
151 | key_raw_channel* channel = key_raw_channel::create( cheader.format, cheader.count );
|
---|
152 | source.read( channel->data, channel->desc.size, channel->count );
|
---|
153 | m_animation->nodes[i].channels[c] = channel;
|
---|
154 | }
|
---|
155 | }
|
---|
156 | }
|
---|
157 | return true;
|
---|
158 | }
|
---|
159 |
|
---|
160 |
|
---|
161 | // TEMPORARY
|
---|
162 | nv::nmd_temp_animation::nmd_temp_animation( nmd_loader* loader )
|
---|
163 | {
|
---|
164 | m_animation = loader->release_animation();
|
---|
165 | m_strings = loader->release_string_table();
|
---|
166 |
|
---|
167 | for ( uint32 n = 0; n < m_animation->node_count; ++n )
|
---|
168 | {
|
---|
169 | nmd_node& node = m_animation->nodes[n];
|
---|
170 | key_animation_data* keys = nullptr;
|
---|
171 | if ( node.channel_count > 1 )
|
---|
172 | {
|
---|
173 | keys = new nv::key_vectors_prs( node.channels[0], node.channels[1], node.channels[2] );
|
---|
174 | }
|
---|
175 | else if ( node.channel_count == 1 )
|
---|
176 | {
|
---|
177 | keys = new nv::transform_vector( node.channels[0] );
|
---|
178 | node.channels[0] = nullptr;
|
---|
179 | node.channel_count = 0;
|
---|
180 | }
|
---|
181 | m_data.push_back( keys );
|
---|
182 | }
|
---|
183 |
|
---|
184 | if ( !m_animation->flat )
|
---|
185 | {
|
---|
186 | m_children.resize( m_animation->node_count );
|
---|
187 | for ( nv::uint32 n = 0; n < m_animation->node_count; ++n )
|
---|
188 | {
|
---|
189 | const nmd_node& node = m_animation->nodes[n];
|
---|
190 | if ( node.parent_id != -1 )
|
---|
191 | {
|
---|
192 | m_children[ node.parent_id ].push_back( n );
|
---|
193 | }
|
---|
194 | }
|
---|
195 | }
|
---|
196 |
|
---|
197 | m_bone_ids.resize( m_animation->node_count );
|
---|
198 | }
|
---|
199 |
|
---|
200 | nv::nmd_temp_animation::~nmd_temp_animation()
|
---|
201 | {
|
---|
202 | for ( auto node : m_data ) delete node;
|
---|
203 | delete m_animation;
|
---|
204 | delete m_strings;
|
---|
205 | }
|
---|
206 |
|
---|
207 | void nv::nmd_temp_animation::prepare( const nmd_temp_model* model )
|
---|
208 | {
|
---|
209 | m_offsets = model->m_bone_offsets.data();
|
---|
210 | for ( uint32 n = 0; n < m_animation->node_count; ++n )
|
---|
211 | {
|
---|
212 | const nmd_node& node = m_animation->nodes[n];
|
---|
213 | sint16 bone_id = -1;
|
---|
214 |
|
---|
215 | auto bi = model->m_bone_names.find( m_strings->get( node.name ) );
|
---|
216 | if ( bi != model->m_bone_names.end() )
|
---|
217 | {
|
---|
218 | bone_id = bi->second;
|
---|
219 | }
|
---|
220 | m_bone_ids[n] = bone_id;
|
---|
221 | }
|
---|
222 | }
|
---|
223 |
|
---|
224 | void nv::nmd_temp_animation::animate( mat4* data, uint32 time )
|
---|
225 | {
|
---|
226 | float tick_time = ( time / 1000.0f ) * m_animation->fps;
|
---|
227 | float anim_time = fmodf( tick_time, m_animation->duration );
|
---|
228 |
|
---|
229 | if ( !m_animation->flat )
|
---|
230 | {
|
---|
231 | animate_rec( data, anim_time, 0, mat4() );
|
---|
232 | return;
|
---|
233 | }
|
---|
234 |
|
---|
235 | for ( uint32 n = 0; n < m_animation->node_count; ++n )
|
---|
236 | if ( m_bone_ids[n] >= 0 )
|
---|
237 | {
|
---|
238 | const nmd_node* node = &m_animation->nodes[ n ];
|
---|
239 | nv::mat4 node_mat( node->transform );
|
---|
240 |
|
---|
241 | if ( m_data[n] && !m_data[n]->empty() )
|
---|
242 | {
|
---|
243 | node_mat = m_data[n]->get_matrix( anim_time );
|
---|
244 | }
|
---|
245 |
|
---|
246 | sint16 bone_id = m_bone_ids[n];
|
---|
247 | data[ bone_id ] = node_mat * m_offsets[ bone_id ];
|
---|
248 | }
|
---|
249 |
|
---|
250 | }
|
---|
251 |
|
---|
252 | void nv::nmd_temp_animation::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat )
|
---|
253 | {
|
---|
254 | // TODO: fix transforms, which are now embedded,
|
---|
255 | // see note in assimp_loader.cc:load_node
|
---|
256 | const nmd_node* node = &m_animation->nodes[ node_id ];
|
---|
257 | mat4 node_mat( node->transform );
|
---|
258 |
|
---|
259 | if ( m_data[ node_id ] && !m_data[ node_id ]->empty() )
|
---|
260 | {
|
---|
261 | node_mat = m_data[ node_id ]->get_matrix( time );
|
---|
262 | }
|
---|
263 |
|
---|
264 | mat4 global_mat = parent_mat * node_mat;
|
---|
265 |
|
---|
266 | sint16 bone_id = m_bone_ids[ node_id ];
|
---|
267 | if ( bone_id >= 0 )
|
---|
268 | {
|
---|
269 | data[ bone_id ] = global_mat * m_offsets[ bone_id ];
|
---|
270 | }
|
---|
271 |
|
---|
272 | for ( auto child : m_children[ node_id ] )
|
---|
273 | {
|
---|
274 | animate_rec( data, time, child, global_mat );
|
---|
275 | }
|
---|
276 | }
|
---|
277 |
|
---|
278 | nv::nmd_temp_model::nmd_temp_model( nmd_loader* loader )
|
---|
279 | {
|
---|
280 | for ( unsigned m = 0; m < loader->get_mesh_count(); ++m )
|
---|
281 | {
|
---|
282 | m_mesh_data.push_back(loader->release_mesh_data(m));
|
---|
283 | }
|
---|
284 | nmd_bone_data* bone_data = loader->release_bone_data();
|
---|
285 | string_table* strings = loader->release_string_table();
|
---|
286 |
|
---|
287 | for ( nv::uint16 bi = 0; bi < bone_data->count; ++bi )
|
---|
288 | {
|
---|
289 | m_bone_names[ strings->get( bone_data->bones[bi].name ) ] = bi;
|
---|
290 | m_bone_offsets.push_back( bone_data->bones[bi].offset );
|
---|
291 | }
|
---|
292 |
|
---|
293 | delete bone_data;
|
---|
294 | delete strings;
|
---|
295 | }
|
---|
296 |
|
---|
297 | nv::nmd_temp_model::~nmd_temp_model()
|
---|
298 | {
|
---|
299 | for ( unsigned m = 0; m < m_mesh_data.size(); ++m )
|
---|
300 | {
|
---|
301 | delete m_mesh_data[m];
|
---|
302 | }
|
---|
303 | }
|
---|