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

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