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

Last change on this file since 413 was 413, checked in by epyon, 10 years ago
  • data_descriptor creators ( buggy )
File size: 9.6 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"
[283]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        for ( uint32 i = 0; i < root_header.elements; ++i )
20        {
21                nmd_element_header element_header;
22                source.read( &element_header, sizeof( element_header ), 1 );
23                switch ( element_header.type )
24                {
[284]25                case nmd_type::MESH           : load_mesh( source, element_header ); break;
26                case nmd_type::ANIMATION      : load_animation( source, element_header ); break;
[283]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
[284]34bool nv::nmd_loader::load_mesh( stream& source, const nmd_element_header& e )
[283]35{
36        mesh_data* mesh = new mesh_data();
[284]37        for ( uint32 s = 0; s < e.children; ++s )
[283]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 );
[413]45                raw_data_channel_creator channel_creator( stream_header.format, stream_header.count );
46                source.read( channel_creator.raw_data(), channel_creator.element_size(), channel_creator.size() );
47                mesh->add_channel( channel_creator.release() );
[283]48        }
[287]49        m_mesh_names.push_back( e.name );
[283]50        m_meshes.push_back( mesh );
51        return true;
52}
53
54mesh_data* nv::nmd_loader::release_mesh_data( size_t index )
55{
56        mesh_data* result = m_meshes[ index ];
[287]57        if ( m_strings ) result->set_name( m_strings->get( m_mesh_names[ index ] ) );
[283]58        m_meshes[ index ] = nullptr;
59        return result;
60}
61
[287]62mesh_data_pack* nv::nmd_loader::release_mesh_data_pack()
63{
64        uint32 size = m_meshes.size();
65        mesh_data* meshes = new mesh_data[ size ];
66        for ( uint32 i = 0; i < size; ++i )
67        {
68                m_meshes[i]->move_to( meshes[i] );
69                delete m_meshes[i];
70        }
71        m_meshes.clear();
72        return new mesh_data_pack( size, meshes, release_mesh_nodes_data() );
73}
74
[283]75void nv::nmd_loader::reset()
76{
77        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
78        if ( m_strings )   delete m_strings;
[287]79        if ( m_node_data ) delete m_node_data;
[283]80        m_meshes.clear();
[287]81        m_mesh_names.clear();
82        m_node_names.clear();
83
84        m_node_data  = nullptr;
85        m_node_array = nullptr;
86        m_strings    = nullptr;
[283]87}
88
89nv::nmd_loader::~nmd_loader()
90{
91        reset();
92}
93
94bool nv::nmd_loader::load_strings( stream& source )
95{
96        NV_ASSERT( m_strings == nullptr, "MULTIPLE STRING ENTRIES!" );
97        m_strings = new string_table( &source );
98        return true;
99}
100
[284]101bool nv::nmd_loader::load_animation( stream& source, const nmd_element_header& e )
[283]102{
[287]103        NV_ASSERT( m_node_data == nullptr, "MULTIPLE NODE ENTRIES!" );
104        nmd_animation_header animation_header;
105        source.read( &animation_header, sizeof( animation_header ), 1 );
106        m_node_array = new mesh_node_data[ e.children ];
[284]107        for ( uint32 i = 0; i < e.children; ++i )
[283]108        {
109                nmd_element_header element_header;
110                source.read( &element_header, sizeof( element_header ), 1 );
[287]111                NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
112                m_node_names.push_back( element_header.name );
[283]113                uint16 ch_count = element_header.children;
114
[287]115                nmd_node_header node_header;
[283]116                source.read( &node_header, sizeof( node_header ), 1 );
[287]117                m_node_array[i].parent_id     = node_header.parent_id;
118                m_node_array[i].transform     = node_header.transform;
119                m_node_array[i].data          = nullptr;
[283]120                if ( ch_count > 0 )
121                {
[285]122                        key_data* kdata = new key_data;
[287]123                        m_node_array[i].data = kdata;
[283]124                        for ( uint32 c = 0; c < ch_count; ++c )
125                        {
126                                source.read( &element_header, sizeof( element_header ), 1 );
[287]127                                NV_ASSERT( element_header.type == nmd_type::KEY_CHANNEL, "CHANNEL expected!" );
[410]128                                nv::nmd_stream_header cheader;
[283]129                                source.read( &cheader, sizeof( cheader ), 1 );
[413]130                                raw_data_channel_creator channel_creator( cheader.format, cheader.count );
131                                source.read( channel_creator.raw_data(), channel_creator.element_size(), channel_creator.size() );
132                                kdata->add_channel( channel_creator.release() );
[283]133                        }
134                }
135        }
[287]136        m_node_data = new mesh_nodes_data( "animation", e.children, m_node_array, animation_header.frame_rate, animation_header.duration, animation_header.flat );
[283]137        return true;
138}
139
[291]140mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
[283]141{
[287]142        if ( m_node_data )
[283]143        {
[287]144                if ( m_strings )
[283]145                {
[287]146                        for ( uint32 i = 0; i < m_node_data->get_count(); ++i )
[283]147                        {
[287]148                                m_node_array[i].name = m_strings->get( m_node_names[i] );
[283]149                        }
150                }
[287]151                mesh_nodes_data* result = m_node_data;
152                m_node_data = nullptr;
153                m_node_array = nullptr;
154                return result;
[283]155        }
[287]156        return nullptr;
[283]157}
158
[292]159// ----------------------------------------------------------------
160// nmd format dump
161// HACK : TEMPORARY - will go to it's own file, probably nmd_io
162static void nmd_dump_mesh( const mesh_data* mesh, stream& stream_out )
163{
[411]164        array_view< raw_data_channel* > data  = mesh->get_raw_channels();
[292]165
166        uint32 size = sizeof( nmd_element_header );
167        for ( auto chan : data )
168        {
169                size += sizeof( nmd_element_header ) + sizeof( nmd_stream_header );
[412]170                size += chan->raw_size();
[292]171        }
172
173        nmd_element_header eheader;
174        eheader.type     = nmd_type::MESH;
175        eheader.name     = 0;
[406]176        eheader.children = static_cast< uint16 >( data.size() );
[292]177        eheader.size     = size;
178        stream_out.write( &eheader, sizeof( eheader ), 1 );
179
180        for ( auto chan : data )
181        {
182                nmd_element_header cheader;
183                eheader.name     = 0;
184                cheader.type     = nmd_type::STREAM;
185                cheader.children = 0;
[412]186                cheader.size     = chan->raw_size() + sizeof( nmd_stream_header );
[292]187                stream_out.write( &cheader, sizeof( cheader ), 1 );
188
189                nmd_stream_header sheader;
[412]190                sheader.format = chan->descriptor();
191                sheader.count  = chan->element_count();
[292]192                stream_out.write( &sheader, sizeof( sheader ), 1 );
[412]193                stream_out.write( chan->raw_data(), chan->element_size(), chan->element_count() );
[292]194        }
195}
196
197static void nmd_dump_nodes_data( const mesh_nodes_data* nodes, stream& stream_out, string_table_creator* strings )
198{
199        uint32 total = sizeof( nmd_animation_header );
200        for ( uint32 i = 0; i < nodes->get_count(); ++i )
201        {
202                const mesh_node_data* node = nodes->get_node(i);
203                total += sizeof( nmd_element_header ) + sizeof( nmd_node_header );
204                if ( node->data )
205                        for ( uint32 c = 0; c < node->data->get_channel_count(); ++c )
206                        {
[410]207                                total += sizeof( nmd_element_header ) + sizeof( nmd_stream_header );
[412]208                                total += node->data->get_channel(c)->raw_size();
[292]209                        }
210        }
211
212        nmd_element_header header;
213        header.name     = 0;
214        header.type     = nmd_type::ANIMATION;
[406]215        header.children = static_cast< uint16 >( nodes->get_count() );
[292]216        header.size     = total;
217        stream_out.write( &header, sizeof( header ), 1 );
218
219        nmd_animation_header aheader;
220        aheader.frame_rate  = nodes->get_frame_rate();
221        aheader.duration    = nodes->get_duration();
222        aheader.flat        = nodes->is_flat();
223        stream_out.write( &aheader, sizeof( aheader ), 1 );
224
225        for ( uint32 i = 0; i < nodes->get_count(); ++i )
226        {
227                const mesh_node_data* node = nodes->get_node(i);
228                uint32 chan_size  = 0;
229                uint32 chan_count = ( node->data ? node->data->get_channel_count() : 0 );
230                for ( uint32 c = 0; c < chan_count; ++c )
231                {
[410]232                        chan_size += sizeof( nmd_element_header ) + sizeof( nv::nmd_stream_header );
[412]233                        chan_size += node->data->get_channel(c)->raw_size();
[292]234                }
235
236                nmd_element_header eheader;
237                eheader.type     = nmd_type::NODE;
238                eheader.name     = strings->insert( node->name );
[406]239                eheader.children = static_cast< uint16 >( chan_count );
[292]240                eheader.size     = sizeof( nmd_node_header ) + chan_size;
241                stream_out.write( &eheader, sizeof( eheader ), 1 );
242
243                nmd_node_header nheader;
[323]244                nheader.parent_id = node->parent_id;
[292]245                nheader.transform = node->transform;
246                stream_out.write( &nheader, sizeof( nheader ), 1 );
247
248                for ( uint32 c = 0; c < chan_count; ++c )
249                {
[411]250                        const raw_data_channel* channel = node->data->get_channel(c);
[292]251
252                        eheader.type     = nmd_type::KEY_CHANNEL;
253                        eheader.children = 0;
[412]254                        eheader.size     = sizeof( nmd_stream_header ) + channel->raw_size();
[292]255                        stream_out.write( &eheader, sizeof( eheader ), 1 );
256
[410]257                        nmd_stream_header cheader;
[412]258                        cheader.format    = channel->descriptor();
259                        cheader.count     = channel->element_count();
[292]260                        stream_out.write( &cheader, sizeof( cheader ), 1 );
[412]261                        stream_out.write( channel->raw_data(), channel->element_size(), channel->element_count() );
[292]262                }
263        }
264}
265
266void nv::nmd_dump( const mesh_data_pack* model, stream& stream_out )
267{
268        string_table_creator strings;
269        {
270                nmd_header header;
271                header.id       = four_cc<'n','m','f','1'>::value;
272                header.elements = 1; // +1 string array
273                header.elements += model->get_count();
274                if ( model->get_nodes() && model->get_nodes()->get_count() > 0 )
275                        header.elements += 1;//  +1 bone array
276                header.version  = 1;
277                stream_out.write( &header, sizeof( header ), 1 );
278        }
279
280        for ( uint32 i = 0; i < model->get_count(); ++i )
281        {
282                const mesh_data* mesh = model->get_mesh(i);
283                nmd_dump_mesh( mesh, stream_out );
284        }
285
286        if ( model->get_nodes() && model->get_nodes()->get_count() > 0 )
287        {
288                nmd_dump_nodes_data( model->get_nodes(), stream_out, &strings );
289        }
290
291        nmd_element_header sheader;
292        sheader.type     = nv::nmd_type::STRING_TABLE;
293        sheader.name     = 0;
294        sheader.size     = strings.dump_size();
295        sheader.children = 0;
296        stream_out.write( &sheader, sizeof( sheader ), 1 );
297        strings.dump( &stream_out );
298}
Note: See TracBrowser for help on using the repository browser.