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

Last change on this file since 420 was 420, checked in by epyon, 10 years ago
  • mesh nodes store name hash instead of string
  • nmd format refactoring
File size: 9.6 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::STRING_TABLE   : 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                data_channel_set_creator( m_meshes[i] ).move_to( 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//      m_strings = new string_table( &source );
96        return true;
97}
98
99bool nv::nmd_loader::load_animation( stream& source, const nmd_element_header& e )
100{
101        NV_ASSERT( m_node_data == nullptr, "MULTIPLE NODE ENTRIES!" );
102        nmd_animation_header animation_header;
103        source.read( &animation_header, sizeof( animation_header ), 1 );
104        m_node_array = new mesh_node_data[ e.children ];
105        for ( uint32 i = 0; i < e.children; ++i )
106        {
107                nmd_element_header element_header;
108                source.read( &element_header, sizeof( element_header ), 1 );
109                skip_attributes( source, element_header.attributes );
110                NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
111//              m_node_names.push_back( element_header.name );
112                load_node( source, &m_node_array[i], element_header );
113        }
114        m_node_data = new mesh_nodes_data( "animation", e.children, m_node_array, animation_header.frame_rate, animation_header.duration, animation_header.flat );
115        return true;
116}
117
118bool nv::nmd_loader::load_node( stream& source, mesh_node_data* data, const nmd_element_header& e )
119{
120        data->name_hash = e.name_hash;
121        data->parent_id = e.parent_id;
122        data->transform = e.transform;
123        data->data = nullptr;
124        if ( e.children > 0 )
125        {
126                data->data = data_channel_set_creator::create( e.children );
127                load_channel_set( source, data->data, e );
128        }
129        return true;
130}
131
132bool nv::nmd_loader::load_channel( stream& source, data_channel_set* channel_set )
133{
134        data_channel_set_creator kaccess( channel_set );
135        nmd_channel_header cheader;
136        source.read( &cheader, sizeof( cheader ), 1 );
137        raw_data_channel_access channel( kaccess.add_channel( cheader.format, cheader.count ) );
138        source.read( channel.raw_data(), channel.element_size(), channel.size() );
139        return true;
140}
141
142bool nv::nmd_loader::load_channel_set( stream& source, data_channel_set* channel_set, const nmd_element_header& e )
143{
144        data_channel_set_creator kaccess( channel_set );
145        for ( uint32 c = 0; c < e.children; ++c )
146        {
147                load_channel( source, channel_set );
148        }
149        return true;
150}
151
152mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
153{
154        if ( m_node_data )
155        {
156//              if ( m_strings )
157//              {
158//                      for ( uint32 i = 0; i < m_node_data->get_count(); ++i )
159//                      {
160//                              m_node_array[i].name = m_strings->get( m_node_names[i] );
161//                              m_node_array[i].name_hash = hash_string< uint64 >( m_strings->get( m_node_names[i] ) );
162//                      }
163//              }
164                mesh_nodes_data* result = m_node_data;
165                m_node_data = nullptr;
166                m_node_array = nullptr;
167                return result;
168        }
169        return nullptr;
170}
171
172// ----------------------------------------------------------------
173// nmd format dump
174// HACK : TEMPORARY - will go to it's own file, probably nmd_io
175static void nmd_dump_channel( const raw_data_channel* channel , stream& stream_out )
176{
177        nmd_channel_header sheader;
178        sheader.format = channel->descriptor();
179        sheader.count = channel->size();
180        stream_out.write( &sheader, sizeof( sheader ), 1 );
181        stream_out.write( channel->raw_data(), channel->element_size(), channel->size() );
182}
183
184static void nmd_dump_channel_set( const data_channel_set* channel_set, stream& stream_out )
185{
186        for ( auto& channel : *channel_set )
187        {
188                nmd_dump_channel( &channel, stream_out );
189        }
190}
191
192static void nmd_dump_mesh( const data_channel_set* mesh, stream& stream_out )
193{
194        uint32 size = 0;
195        for ( auto& chan : *mesh )
196        {
197                size += sizeof( nmd_channel_header );
198                size += chan.raw_size();
199        }
200
201        nmd_element_header eheader;
202        eheader.type       = nmd_type::MESH;
203//      eheader.name       = 0;
204        eheader.children   = static_cast< uint16 >( mesh->size() );
205        eheader.size       = size;
206        eheader.name_hash  = 0;
207        eheader.transform  = mat4();
208        eheader.parent_id  = -1;
209        eheader.attributes = 0;
210        stream_out.write( &eheader, sizeof( eheader ), 1 );
211        nmd_dump_channel_set( mesh, stream_out );
212}
213
214static void nmd_dump_node( const mesh_node_data* node, stream& stream_out )
215{
216        uint32 chan_size = 0;
217        uint32 chan_count = ( node->data ? node->data->size() : 0 );
218        for ( uint32 c = 0; c < chan_count; ++c )
219        {
220                chan_size += sizeof( nmd_channel_header );
221                chan_size += node->data->get_channel( c )->raw_size();
222        }
223
224        nmd_element_header eheader;
225        eheader.type = nmd_type::NODE;
226        //              eheader.name     = strings->insert( node->name );
227        eheader.children   = static_cast<uint16>( chan_count );
228        eheader.size       = chan_size;
229        eheader.name_hash  = node->name_hash;
230        eheader.parent_id  = node->parent_id;
231        eheader.transform  = node->transform;
232        eheader.attributes = 0;
233        stream_out.write( &eheader, sizeof( eheader ), 1 );
234        if ( node->data ) nmd_dump_channel_set( node->data, stream_out );
235}
236
237static void nmd_dump_nodes_data( const mesh_nodes_data* nodes, stream& stream_out, string_table_creator* /*strings*/ )
238{
239        uint32 total = sizeof( nmd_animation_header );
240        for ( uint32 i = 0; i < nodes->get_count(); ++i )
241        {
242                const mesh_node_data* node = nodes->get_node(i);
243                total += sizeof( nmd_element_header );
244                if ( node->data )
245                        for ( uint32 c = 0; c < node->data->size(); ++c )
246                        {
247                                total += sizeof( nmd_channel_header );
248                                total += node->data->get_channel(c)->raw_size();
249                        }
250        }
251
252        nmd_element_header header;
253//      header.name       = 0;
254        header.type       = nmd_type::ANIMATION;
255        header.children   = static_cast< uint16 >( nodes->get_count() );
256        header.size       = total;
257        header.name_hash  = 0;
258        header.transform  = mat4();
259        header.parent_id  = -1;
260        header.attributes = 0;
261
262        stream_out.write( &header, sizeof( header ), 1 );
263
264        nmd_animation_header aheader;
265        aheader.frame_rate  = nodes->get_frame_rate();
266        aheader.duration    = nodes->get_duration();
267        aheader.flat        = nodes->is_flat();
268        stream_out.write( &aheader, sizeof( aheader ), 1 );
269
270        for ( uint32 i = 0; i < nodes->get_count(); ++i )
271        {
272                nmd_dump_node( nodes->get_node( i ), stream_out );
273        }
274}
275
276void nv::nmd_dump( const mesh_data_pack* model, stream& stream_out )
277{
278        string_table_creator strings;
279        {
280                nmd_header header;
281                header.id       = four_cc<'n','m','f','1'>::value;
282                header.elements = 0; // +1 string array
283                header.elements += model->get_count();
284                if ( model->get_nodes() && model->get_nodes()->get_count() > 0 )
285                        header.elements += 1;//  +1 bone array
286                header.version  = 1;
287                header.attributes = 0;
288                stream_out.write( &header, sizeof( header ), 1 );
289        }
290
291        for ( uint32 i = 0; i < model->get_count(); ++i )
292        {
293                const data_channel_set* mesh = model->get_mesh(i);
294                nmd_dump_mesh( mesh, stream_out );
295        }
296
297        if ( model->get_nodes() && model->get_nodes()->get_count() > 0 )
298        {
299                nmd_dump_nodes_data( model->get_nodes(), stream_out, &strings );
300        }
301
302//      nmd_element_header sheader;
303//      sheader.type     = nv::nmd_type::STRING_TABLE;
304//      sheader.name     = 0;
305//      sheader.size     = strings.dump_size();
306//      sheader.children = 0;
307//  sheader.attributes = 0;
308//      stream_out.write( &sheader, sizeof( sheader ), 1 );
309//      strings.dump( &stream_out );
310}
Note: See TracBrowser for help on using the repository browser.