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

Last change on this file since 421 was 421, checked in by epyon, 10 years ago
  • move ops for data_channel_set
  • string_table works on string_views, stores hashes
File size: 9.5 KB
RevLine 
[395]1// Copyright (C) 2014-2015 ChaosForge Ltd
[283]2// http://chaosforge.org/
3//
[395]4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
[283]6
7#include "nv/formats/nmd_loader.hh"
8#include "nv/io/std_stream.hh"
[368]9#include "nv/stl/string.hh"
[416]10#include "nv/interface/data_channel_access.hh"
[283]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 );
[420]20        skip_attributes( source, root_header.attributes );
[283]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 );
[420]25                skip_attributes( source, element_header.attributes );
[283]26                switch ( element_header.type )
27                {
[284]28                case nmd_type::MESH           : load_mesh( source, element_header ); break;
29                case nmd_type::ANIMATION      : load_animation( source, element_header ); break;
[420]30//              case nmd_type::STRING_TABLE   : load_strings( source ); break;
[283]31                default: NV_ASSERT( false, "UNKNOWN NMD ELEMENT!" ); break;
32                }
33        }
34        return true;
35}
36
[284]37bool nv::nmd_loader::load_mesh( stream& source, const nmd_element_header& e )
[283]38{
[417]39        data_channel_set* mesh = data_channel_set_creator::create( e.children );
[420]40        load_channel_set( source, mesh, e );
41//      m_mesh_names.push_back( e.name );
[417]42        m_meshes.push_back( mesh );
[283]43        return true;
44}
45
[416]46data_channel_set* nv::nmd_loader::release_mesh_data( size_t index )
[283]47{
[416]48        data_channel_set* result = m_meshes[ index ];
[420]49//      if ( m_strings ) data_channel_set_creator( result ).set_name( m_strings->get( m_mesh_names[ index ] ) );
[283]50        m_meshes[ index ] = nullptr;
51        return result;
52}
53
[287]54mesh_data_pack* nv::nmd_loader::release_mesh_data_pack()
55{
56        uint32 size = m_meshes.size();
[416]57        data_channel_set* meshes = data_channel_set_creator::create_array( size, 0 );
[287]58        for ( uint32 i = 0; i < size; ++i )
59        {
[421]60                meshes[i] = move( *m_meshes[i] );
[287]61                delete m_meshes[i];
62        }
63        m_meshes.clear();
64        return new mesh_data_pack( size, meshes, release_mesh_nodes_data() );
65}
66
[283]67void nv::nmd_loader::reset()
68{
69        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
[420]70//      if ( m_strings )   delete m_strings;
[287]71        if ( m_node_data ) delete m_node_data;
[283]72        m_meshes.clear();
[420]73//      m_mesh_names.clear();
74//      m_node_names.clear();
[287]75
76        m_node_data  = nullptr;
77        m_node_array = nullptr;
[420]78//      m_strings    = nullptr;
[283]79}
80
[420]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
[283]87nv::nmd_loader::~nmd_loader()
88{
89        reset();
90}
91
[420]92bool nv::nmd_loader::load_strings( stream& /*source*/ )
[283]93{
[420]94//      NV_ASSERT( m_strings == nullptr, "MULTIPLE STRING ENTRIES!" );
95//      m_strings = new string_table( &source );
[283]96        return true;
97}
98
[284]99bool nv::nmd_loader::load_animation( stream& source, const nmd_element_header& e )
[283]100{
[287]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 ];
[284]105        for ( uint32 i = 0; i < e.children; ++i )
[283]106        {
107                nmd_element_header element_header;
108                source.read( &element_header, sizeof( element_header ), 1 );
[420]109                skip_attributes( source, element_header.attributes );
[287]110                NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
[420]111//              m_node_names.push_back( element_header.name );
112                load_node( source, &m_node_array[i], element_header );
[283]113        }
[287]114        m_node_data = new mesh_nodes_data( "animation", e.children, m_node_array, animation_header.frame_rate, animation_header.duration, animation_header.flat );
[283]115        return true;
116}
117
[420]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
[291]152mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
[283]153{
[287]154        if ( m_node_data )
[283]155        {
[420]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//              }
[287]164                mesh_nodes_data* result = m_node_data;
165                m_node_data = nullptr;
166                m_node_array = nullptr;
167                return result;
[283]168        }
[287]169        return nullptr;
[283]170}
171
[292]172// ----------------------------------------------------------------
173// nmd format dump
174// HACK : TEMPORARY - will go to it's own file, probably nmd_io
[420]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
[416]192static void nmd_dump_mesh( const data_channel_set* mesh, stream& stream_out )
[292]193{
[420]194        uint32 size = 0;
[418]195        for ( auto& chan : *mesh )
[292]196        {
[420]197                size += sizeof( nmd_channel_header );
[418]198                size += chan.raw_size();
[292]199        }
200
201        nmd_element_header eheader;
[420]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;
[292]210        stream_out.write( &eheader, sizeof( eheader ), 1 );
[420]211        nmd_dump_channel_set( mesh, stream_out );
212}
[292]213
[420]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 )
[292]219        {
[420]220                chan_size += sizeof( nmd_channel_header );
221                chan_size += node->data->get_channel( c )->raw_size();
222        }
[292]223
[420]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 );
[292]235}
236
[420]237static void nmd_dump_nodes_data( const mesh_nodes_data* nodes, stream& stream_out, string_table_creator* /*strings*/ )
[292]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);
[420]243                total += sizeof( nmd_element_header );
[292]244                if ( node->data )
[416]245                        for ( uint32 c = 0; c < node->data->size(); ++c )
[292]246                        {
[420]247                                total += sizeof( nmd_channel_header );
[412]248                                total += node->data->get_channel(c)->raw_size();
[292]249                        }
250        }
251
252        nmd_element_header header;
[420]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
[292]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        {
[420]272                nmd_dump_node( nodes->get_node( i ), stream_out );
[292]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;
[420]282                header.elements = 0; // +1 string array
[292]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;
[420]287                header.attributes = 0;
[292]288                stream_out.write( &header, sizeof( header ), 1 );
289        }
290
291        for ( uint32 i = 0; i < model->get_count(); ++i )
292        {
[416]293                const data_channel_set* mesh = model->get_mesh(i);
[292]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
[420]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 );
[292]310}
Note: See TracBrowser for help on using the repository browser.