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

Last change on this file since 484 was 482, checked in by epyon, 10 years ago
  • skeletal animation updated
File size: 10.2 KB
Line 
1// Copyright (C) 2014-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/formats/nmd_loader.hh"
8#include "nv/stl/string.hh"
9#include "nv/interface/data_channel_access.hh"
10
11using namespace nv;
12
13bool nv::nmd_loader::load( stream& source )
14{
15        // TODO: proper error handling
16        reset();
17        nmd_header root_header;
18        source.read( &root_header, sizeof( root_header ), 1 );
19        skip_attributes( source, root_header.attributes );
20        for ( uint32 i = 0; i < root_header.elements; ++i )
21        {
22                nmd_element_header element_header;
23                source.read( &element_header, sizeof( element_header ), 1 );
24                skip_attributes( source, element_header.attributes );
25                switch ( element_header.type )
26                {
27                case nmd_type::MESH           : load_mesh( source, element_header ); break;
28                case nmd_type::ANIMATION      : load_animation( source, element_header ); break;
29                case nmd_type::STRINGS        : load_strings( source ); break;
30                default: NV_ASSERT( false, "UNKNOWN NMD ELEMENT!" ); break;
31                }
32        }
33        return true;
34}
35
36bool nv::nmd_loader::load_mesh( stream& source, const nmd_element_header& e )
37{
38        data_channel_set* mesh = data_channel_set_creator::create_set( e.children );
39        data_node_info info;
40        load_channel_set( source, mesh, info, e );
41//      m_mesh_names.push_back( e.name );
42        m_infos.push_back( info );
43        m_meshes.push_back( mesh );
44        return true;
45}
46
47data_channel_set* nv::nmd_loader::release_mesh_data( size_t index, data_node_info& info )
48{
49        data_channel_set* result = m_meshes[ index ];
50        info = m_infos[ index ];
51        m_meshes[ index ] = nullptr;
52        return result;
53}
54
55void nv::nmd_loader::reset()
56{
57        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
58        if ( m_node_data ) delete m_node_data;
59        if ( m_bone_data ) delete m_bone_data;
60        m_meshes.clear();
61
62        m_node_data = nullptr;
63        m_bone_data = nullptr;
64}
65
66void nv::nmd_loader::skip_attributes( stream& source, uint32 count )
67{
68        if ( count == 0 ) return;
69        source.seek( count * sizeof( nmd_attribute ), origin::CUR );
70}
71
72nv::nmd_loader::~nmd_loader()
73{
74        reset();
75}
76
77bool nv::nmd_loader::load_strings( stream& source )
78{
79        if ( !m_strings ) return true;
80        // TODO: load strings optionally
81        string_table* strings = new string_table( source );
82        m_strings->insert( strings );
83        delete strings;
84        return true;
85}
86
87bool nv::nmd_loader::load_animation( stream& source, const nmd_element_header& e )
88{
89        NV_ASSERT( m_node_data == nullptr, "MULTIPLE NODE ENTRIES!" );
90        nmd_animation_header animation_header;
91        source.read( &animation_header, sizeof( animation_header ), 1 );
92        m_node_data = new mesh_nodes_data( e.name, animation_header.frame_rate, animation_header.frame_count );
93        m_bone_data = new data_node_list( e.name );
94        for ( uint32 i = 0; i < e.children; ++i )
95        {
96                nmd_element_header element_header;
97                source.read( &element_header, sizeof( element_header ), 1 );
98                skip_attributes( source, element_header.attributes );
99                NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
100                data_channel_set* set = data_channel_set_creator::create_set( element_header.children );
101                data_node_info info;
102                load_channel_set( source, set, info, element_header );
103                m_bone_data->append( info );
104                m_node_data->append( set, info );
105        }
106        m_node_data->initialize();
107        return true;
108}
109
110bool nv::nmd_loader::load_channel( stream& source, data_channel_set* channel_set )
111{
112        data_channel_set_creator kaccess( channel_set );
113        nmd_channel_header cheader;
114        source.read( &cheader, sizeof( cheader ), 1 );
115        raw_data_channel_access channel( kaccess.add_channel( cheader.format, cheader.count ) );
116        source.read( channel.raw_data(), channel.element_size(), channel.size() );
117        return true;
118}
119
120bool nv::nmd_loader::load_channel_set( stream& source, data_channel_set* channel_set, data_node_info& info, const nmd_element_header& e )
121{
122        data_channel_set_creator kaccess( channel_set );
123        for ( uint32 c = 0; c < e.children; ++c )
124        {
125                load_channel( source, channel_set );
126        }
127        info.name = e.name;
128        info.parent_id = e.parent_id;
129        info.transform = e.transform;
130        return true;
131}
132
133mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
134{
135        mesh_nodes_data* result = m_node_data;
136        m_node_data = nullptr;
137        return result;
138}
139
140data_node_list* nv::nmd_loader::release_data_node_list( size_t )
141{
142        data_node_list* result = m_bone_data;
143        m_bone_data = nullptr;
144        return result;
145}
146
147bool nv::nmd_loader::is_animated( size_t /*= 0 */ )
148{
149        if ( !m_node_data ) return false;
150        return m_node_data->is_animated();
151}
152
153// ----------------------------------------------------------------
154// nmd format dump
155// HACK : TEMPORARY - will go to it's own file, probably nmd_io
156
157void nv::nmd_dump_header( stream& stream_out, uint32 elements, uint64 name )
158{
159        nmd_header header;
160        header.id = four_cc<'n', 'm', 'f', '1'>::value;
161        header.elements = elements; // +1 string array
162        header.name = name;
163        header.version = 1;
164        header.attributes = 0;
165        stream_out.write( &header, sizeof( header ), 1 );
166}
167
168void nv::nmd_dump_element( stream& stream_out, const data_channel_set& data, const data_node_info& info, nmd_type type )
169{
170        uint32 size = 0;
171        for ( auto& chan : data )
172        {
173                size += sizeof( nmd_channel_header );
174                size += chan.raw_size();
175        }
176
177        nmd_element_header eheader;
178        eheader.type       = type;
179        eheader.children   = static_cast<uint16>( data.size() );
180        eheader.size       = size;
181        eheader.name       = info.name;
182        eheader.transform  = info.transform;
183        eheader.parent_id  = info.parent_id;
184        eheader.attributes = 0;
185        stream_out.write( &eheader, sizeof( eheader ), 1 );
186        for ( auto& channel : data )
187        {
188                nmd_channel_header cheader;
189                cheader.format = channel.descriptor();
190                cheader.count = channel.size();
191                stream_out.write( &cheader, sizeof( cheader ), 1 );
192                stream_out.write( channel.raw_data(), channel.element_size(), channel.size() );
193        }
194}
195
196void nv::nmd_dump_nodes( stream& stream_out, const mesh_nodes_data& nodes )
197{
198        uint32 total = sizeof( nmd_animation_header );
199        for ( auto node : nodes )
200        {
201                total += sizeof( nmd_element_header );
202                for ( uint32 c = 0; c < node->size(); ++c )
203                {
204                        total += sizeof( nmd_channel_header );
205                        total += node->get_channel( c )->raw_size();
206                }
207        }
208
209        nmd_element_header header;
210        header.type = nmd_type::ANIMATION;
211        header.children = static_cast<uint16>( nodes.size() );
212        header.size = total;
213        header.name = nodes.get_name();
214        header.transform = mat4();
215        header.parent_id = -1;
216        header.attributes = 0;
217
218        stream_out.write( &header, sizeof( header ), 1 );
219
220        nmd_animation_header aheader;
221        aheader.frame_rate  = nodes.get_fps();
222        aheader.frame_count = nodes.get_frame_count();
223        aheader.unused      = false;
224        stream_out.write( &aheader, sizeof( aheader ), 1 );
225
226        for ( uint32 i = 0; i < nodes.size(); ++i )
227        {
228                nmd_dump_element( stream_out, *nodes[i], nodes.get_info(i), nv::nmd_type::NODE );
229        }
230}
231
232void nv::nmd_dump_bones( stream& stream_out, const data_node_list& nodes )
233{
234        uint32 total = sizeof( nmd_animation_header );
235        for ( auto node : nodes )
236        {
237                total += sizeof( nmd_element_header );
238        }
239
240        nmd_element_header header;
241        header.type = nmd_type::ANIMATION;
242        header.children = static_cast<uint16>( nodes.size() );
243        header.size = total;
244        header.name = nodes.get_name();
245        header.transform = mat4();
246        header.parent_id = -1;
247        header.attributes = 0;
248
249        stream_out.write( &header, sizeof( header ), 1 );
250
251        nmd_animation_header aheader;
252        aheader.frame_rate = 0;
253        aheader.frame_count = 0;
254        aheader.unused = false;
255        stream_out.write( &aheader, sizeof( aheader ), 1 );
256
257        for ( auto node : nodes )
258        {
259                nmd_element_header eheader;
260                eheader.type = nv::nmd_type::NODE;
261                eheader.children = 0;
262                eheader.size = 0;
263                eheader.name = node.name;
264                eheader.transform = node.transform;
265                eheader.parent_id = node.parent_id;
266                eheader.attributes = 0;
267                stream_out.write( &eheader, sizeof( eheader ), 1 );
268        }
269}
270
271void nv::nmd_dump_strings( stream& stream_out, const string_table& strings )
272{
273        nmd_element_header sheader;
274        sheader.type       = nv::nmd_type::STRINGS;
275        sheader.children   = 0;
276        sheader.size       = strings.dump_size();
277        sheader.name       = shash64();
278        sheader.parent_id  = -1;
279    sheader.attributes = 0;
280        stream_out.write( &sheader, sizeof( sheader ), 1 );
281        strings.dump( stream_out );
282}
283
284void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const mesh_nodes_data* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
285{
286        uint32 elements = ( strings ? 1 : 0 ) // +1 string array
287                + meshes.size() // meshes
288                + ( nodes && nodes->size() > 0 ? 1 : 0 ); // nodes
289        nmd_dump_header( stream_out, elements, name );
290
291        for ( uint32 i = 0; i < meshes.size(); ++i )
292        {
293                NV_ASSERT( meshes[i], "mesh is null!" );
294                nmd_dump_element( stream_out, *meshes[i], infos[i], nv::nmd_type::MESH );
295        }
296
297        if ( nodes && nodes->size() > 0 )
298        {
299                nmd_dump_nodes( stream_out, *nodes );
300        }
301
302        if ( strings )
303        {
304                nmd_dump_strings( stream_out, *strings );
305        }
306}
307
308void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const nv::data_node_list* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
309{
310        uint32 elements = ( strings ? 1 : 0 ) // +1 string array
311                + meshes.size() // meshes
312                + ( nodes && nodes->size() > 0 ? 1 : 0 ); // nodes
313        nmd_dump_header( stream_out, elements, name );
314
315        for ( uint32 i = 0; i < meshes.size(); ++i )
316        {
317                NV_ASSERT( meshes[i], "mesh is null!" );
318                nmd_dump_element( stream_out, *meshes[i], infos[i], nv::nmd_type::MESH );
319        }
320
321        if ( nodes && nodes->size() > 0 )
322        {
323                nmd_dump_bones( stream_out, *nodes );
324        }
325
326        if ( strings )
327        {
328                nmd_dump_strings( stream_out, *strings );
329        }
330}
331
332void nv::nmd_dump( stream& stream_out, const mesh_nodes_data& animation, const string_table* strings, uint64 name )
333{
334        uint32 elements = ( strings ? 1 : 0 ) // +1 string array
335                + ( animation.size() > 0 ? 1 : 0 ); // nodes
336        nmd_dump_header( stream_out, elements, name );
337
338        if ( animation.size() > 0 )
339        {
340                nmd_dump_nodes( stream_out, animation );
341        }
342
343        if ( strings )
344        {
345                nmd_dump_strings( stream_out, *strings );
346        }
347}
Note: See TracBrowser for help on using the repository browser.