source: trunk/src/formats/nmd_loader.cc @ 283

Last change on this file since 283 was 283, checked in by epyon, 11 years ago
  • Nova Model Data format loader added
  • keyframed mesh and skeletal mesh don't store time info anymore
  • NMD loader has a temporary utility class for fast usage
File size: 8.6 KB
Line 
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
10using namespace nv;
11
12bool 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
34bool 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
53mesh_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
60void 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
72nv::nmd_loader::~nmd_loader()
73{
74        reset();
75}
76
77bool 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
84bool 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
94nmd_animation* nv::nmd_loader::release_animation()
95{
96        nmd_animation* result = m_animation;
97        m_animation = nullptr;
98        return result;
99}
100
101nmd_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
108string_table* nv::nmd_loader::release_string_table()
109{
110        string_table* result = m_strings;
111        m_strings = nullptr;
112        return result;
113}
114
115
116bool 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
162nv::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
200nv::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
207void 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
224void 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
252void 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
278nv::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
297nv::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}
Note: See TracBrowser for help on using the repository browser.