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

Last change on this file since 368 was 368, checked in by epyon, 10 years ago
  • massive restructuring
  • detail::data_base class for container/reference class base
File size: 9.4 KB
Line 
1// Copyright (C) 2014 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of NV Libraries.
5// For conditions of distribution and use, see copyright notice in nv.hh
6
7#include "nv/formats/nmd_loader.hh"
8#include "nv/io/std_stream.hh"
9#include "nv/stl/string.hh"
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                {
25                case nmd_type::MESH           : load_mesh( source, element_header ); break;
26                case nmd_type::ANIMATION      : load_animation( source, element_header ); break;
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
34bool nv::nmd_loader::load_mesh( stream& source, const nmd_element_header& e )
35{
36        mesh_data* mesh = new mesh_data();
37        for ( uint32 s = 0; s < e.children; ++s )
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 );
45                mesh_raw_channel* channel = mesh_raw_channel::create( stream_header.format, stream_header.count );
46                source.read( channel->data, stream_header.format.size, stream_header.count );
47                mesh->add_channel( channel );
48        }
49        m_mesh_names.push_back( e.name );
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 ];
57        if ( m_strings ) result->set_name( m_strings->get( m_mesh_names[ index ] ) );
58        m_meshes[ index ] = nullptr;
59        return result;
60}
61
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
75void nv::nmd_loader::reset()
76{
77        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
78        if ( m_strings )   delete m_strings;
79        if ( m_node_data ) delete m_node_data;
80        m_meshes.clear();
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;
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
101bool nv::nmd_loader::load_animation( stream& source, const nmd_element_header& e )
102{
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 ];
107        for ( uint32 i = 0; i < e.children; ++i )
108        {
109                nmd_element_header element_header;
110                source.read( &element_header, sizeof( element_header ), 1 );
111                NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
112                m_node_names.push_back( element_header.name );
113                uint16 ch_count = element_header.children;
114
115                nmd_node_header node_header;
116                source.read( &node_header, sizeof( node_header ), 1 );
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;
120                if ( ch_count > 0 )
121                {
122                        key_data* kdata = new key_data;
123                        m_node_array[i].data = kdata;
124                        for ( uint32 c = 0; c < ch_count; ++c )
125                        {
126                                source.read( &element_header, sizeof( element_header ), 1 );
127                                NV_ASSERT( element_header.type == nmd_type::KEY_CHANNEL, "CHANNEL expected!" );
128                                nv::nmd_key_channel_header cheader;
129                                source.read( &cheader, sizeof( cheader ), 1 );
130                                key_raw_channel* channel = key_raw_channel::create( cheader.format, cheader.count );
131                                source.read( channel->data, channel->desc.size, channel->count );
132                                kdata->add_channel( channel );
133                        }
134                }
135        }
136        m_node_data = new mesh_nodes_data( "animation", e.children, m_node_array, animation_header.frame_rate, animation_header.duration, animation_header.flat );
137        return true;
138}
139
140mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
141{
142        if ( m_node_data )
143        {
144                if ( m_strings )
145                {
146                        for ( uint32 i = 0; i < m_node_data->get_count(); ++i )
147                        {
148                                m_node_array[i].name = m_strings->get( m_node_names[i] );
149                        }
150                }
151                mesh_nodes_data* result = m_node_data;
152                m_node_data = nullptr;
153                m_node_array = nullptr;
154                return result;
155        }
156        return nullptr;
157}
158
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{
164        const std::vector< mesh_raw_channel* >& data  = mesh->get_raw_channels();
165
166        uint32 size = sizeof( nmd_element_header );
167        for ( auto chan : data )
168        {
169                size += sizeof( nmd_element_header ) + sizeof( nmd_stream_header );
170                size += chan->size();
171        }
172
173        nmd_element_header eheader;
174        eheader.type     = nmd_type::MESH;
175        eheader.name     = 0;
176        eheader.children = (uint16)data.size();
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;
186                cheader.size     = chan->size() + sizeof( nmd_stream_header );
187                stream_out.write( &cheader, sizeof( cheader ), 1 );
188
189                nmd_stream_header sheader;
190                sheader.format = chan->desc;
191                sheader.count  = chan->count;
192                stream_out.write( &sheader, sizeof( sheader ), 1 );
193                stream_out.write( chan->data, chan->desc.size, chan->count );
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                        {
207                                total += sizeof( nmd_element_header ) + sizeof( nmd_key_channel_header );
208                                total += node->data->get_channel(c)->size();
209                        }
210        }
211
212        nmd_element_header header;
213        header.name     = 0;
214        header.type     = nmd_type::ANIMATION;
215        header.children = (uint16)nodes->get_count();
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                {
232                        chan_size += sizeof( nmd_element_header ) + sizeof( nv::nmd_key_channel_header );
233                        chan_size += node->data->get_channel(c)->size();
234                }
235
236                nmd_element_header eheader;
237                eheader.type     = nmd_type::NODE;
238                eheader.name     = strings->insert( node->name );
239                eheader.children = (uint16)chan_count;
240                eheader.size     = sizeof( nmd_node_header ) + chan_size;
241                stream_out.write( &eheader, sizeof( eheader ), 1 );
242
243                nmd_node_header nheader;
244                nheader.parent_id = node->parent_id;
245                nheader.transform = node->transform;
246                stream_out.write( &nheader, sizeof( nheader ), 1 );
247
248                for ( uint32 c = 0; c < chan_count; ++c )
249                {
250                        const key_raw_channel* channel = node->data->get_channel(c);
251
252                        eheader.type     = nmd_type::KEY_CHANNEL;
253                        eheader.children = 0;
254                        eheader.size     = sizeof( nmd_key_channel_header ) + channel->size();
255                        stream_out.write( &eheader, sizeof( eheader ), 1 );
256
257                        nmd_key_channel_header cheader;
258                        cheader.format    = channel->desc;
259                        cheader.count     = channel->count;
260                        stream_out.write( &cheader, sizeof( cheader ), 1 );
261                        stream_out.write( channel->data, channel->desc.size, channel->count );
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.