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

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