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

Last change on this file since 285 was 285, checked in by epyon, 11 years ago
  • full pure data model for animation
  • all loaders now use pure data model instead of the template/virtual one
File size: 8.2 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 ); break;
25                case nmd_type::ANIMATION      : load_animation( source, element_header ); break;
26                case nmd_type::BONE_ARRAY     : load_bones( source, element_header ); 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, const nmd_element_header& e )
35{
36        mesh_data* mesh = new mesh_data();
37        for ( uint32 s = 0; s < e.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, const nmd_element_header& e )
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[ e.children ];
89        m_bone_data->count = (uint16)e.children;
90        source.read( m_bone_data->bones, sizeof( nmd_bone ), e.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, const nmd_element_header& e )
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)e.children;
126        m_animation->nodes      = new nmd_node[ e.children ];
127        for ( uint32 i = 0; i < e.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                m_animation->nodes[i].name          = element_header.name;
133
134                uint16 ch_count = element_header.children;
135
136                nmd_animation_node_header node_header;
137                source.read( &node_header, sizeof( node_header ), 1 );
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].data          = nullptr;
141                if ( ch_count > 0 )
142                {
143                        key_data* kdata = new key_data;
144                        m_animation->nodes[i].data = kdata;
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                                kdata->add_channel( 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                m_data.push_back( node.data );
171                node.data = nullptr;
172        }
173
174        if ( !m_animation->flat )
175        {
176                m_children.resize( m_animation->node_count );
177                for ( nv::uint32 n = 0; n < m_animation->node_count; ++n )
178                {
179                        const nmd_node& node = m_animation->nodes[n];
180                        if ( node.parent_id != -1 )
181                        {
182                                m_children[ node.parent_id ].push_back( n );
183                        }
184                }
185        }
186
187        m_bone_ids.resize( m_animation->node_count );
188}
189
190nv::nmd_temp_animation::~nmd_temp_animation()
191{
192        for ( auto node : m_data ) delete node;
193        delete m_animation;
194        delete m_strings;
195}
196
197void nv::nmd_temp_animation::prepare( const nmd_temp_model* model )
198{
199        m_offsets = model->m_bone_offsets.data();
200        for ( uint32 n = 0; n < m_animation->node_count; ++n )
201        {
202                const nmd_node& node = m_animation->nodes[n];
203                sint16 bone_id = -1;
204
205                auto bi = model->m_bone_names.find( m_strings->get( node.name ) );
206                if ( bi != model->m_bone_names.end() )
207                {
208                        bone_id = bi->second;
209                }
210                m_bone_ids[n] = bone_id;
211        }
212}
213
214void nv::nmd_temp_animation::animate( mat4* data, uint32 time )
215{
216        float tick_time = ( time / 1000.0f ) * m_animation->fps;
217        float anim_time = fmodf( tick_time, m_animation->duration );
218
219        if ( !m_animation->flat )
220        {
221                animate_rec( data, anim_time, 0, mat4() );
222                return;
223        }
224
225        for ( uint32 n = 0; n < m_animation->node_count; ++n )
226                if ( m_bone_ids[n] >= 0 )
227                {
228                        const nmd_node* node = &m_animation->nodes[ n ];
229                        nv::mat4 node_mat( node->transform );
230
231                        if ( m_data[n] )
232                        {
233                                node_mat = m_data[n]->get_matrix( anim_time );
234                        }
235
236                        sint16 bone_id = m_bone_ids[n];
237                        data[ bone_id ] = node_mat * m_offsets[ bone_id ];
238                }
239
240}
241
242void nv::nmd_temp_animation::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat )
243{
244        // TODO: fix transforms, which are now embedded,
245        //       see note in assimp_loader.cc:load_node
246        const nmd_node* node = &m_animation->nodes[ node_id ];
247        mat4 node_mat( node->transform );
248
249        if ( m_data[ node_id ] )
250        {
251                node_mat = m_data[ node_id ]->get_matrix( time );
252        }
253
254        mat4 global_mat = parent_mat * node_mat;
255
256        sint16 bone_id = m_bone_ids[ node_id ];
257        if ( bone_id >= 0 )
258        {
259                data[ bone_id ] = global_mat * m_offsets[ bone_id ];
260        }
261
262        for ( auto child : m_children[ node_id ] )
263        {
264                animate_rec( data, time, child, global_mat );
265        }
266}
267
268nv::nmd_temp_model::nmd_temp_model( nmd_loader* loader )
269{
270        for ( unsigned m = 0; m < loader->get_mesh_count(); ++m )
271        {
272                m_mesh_data.push_back(loader->release_mesh_data(m));
273        }
274        nmd_bone_data* bone_data = loader->release_bone_data();
275        string_table*  strings   = loader->release_string_table();
276
277        for ( nv::uint16 bi = 0; bi < bone_data->count; ++bi )
278        {
279                m_bone_names[ strings->get( bone_data->bones[bi].name ) ] = bi;
280                m_bone_offsets.push_back( bone_data->bones[bi].offset );
281        }
282
283        delete bone_data;
284        delete strings;
285}
286
287nv::nmd_temp_model::~nmd_temp_model()
288{
289        for ( unsigned m = 0; m < m_mesh_data.size(); ++m )
290        {
291                delete m_mesh_data[m];
292        }
293}
Note: See TracBrowser for help on using the repository browser.