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

Last change on this file since 425 was 425, checked in by epyon, 10 years ago
  • mesh formats now support string loading via string_table
  • nmd string_table dump
  • fixes all around
File size: 9.0 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;
[423]30                case nmd_type::STRINGS        : 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{
[424]39        data_channel_set* mesh = data_channel_set_creator::create_set( 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 ];
[283]49        m_meshes[ index ] = nullptr;
50        return result;
51}
52
[287]53mesh_data_pack* nv::nmd_loader::release_mesh_data_pack()
54{
55        uint32 size = m_meshes.size();
[424]56        data_channel_set* meshes = data_channel_set_creator::create_set_array( size, 0 );
[287]57        for ( uint32 i = 0; i < size; ++i )
58        {
[421]59                meshes[i] = move( *m_meshes[i] );
[287]60                delete m_meshes[i];
61        }
62        m_meshes.clear();
63        return new mesh_data_pack( size, meshes, release_mesh_nodes_data() );
64}
65
[283]66void nv::nmd_loader::reset()
67{
68        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
[287]69        if ( m_node_data ) delete m_node_data;
[283]70        m_meshes.clear();
[287]71
72        m_node_data  = nullptr;
73        m_node_array = nullptr;
[283]74}
75
[420]76void nv::nmd_loader::skip_attributes( stream& source, uint32 count )
77{
78        if ( count == 0 ) return;
79        source.seek( count * sizeof( nmd_attribute ), origin::CUR );
80}
81
[283]82nv::nmd_loader::~nmd_loader()
83{
84        reset();
85}
86
[423]87bool nv::nmd_loader::load_strings( stream& source )
[283]88{
[425]89        if ( !m_strings ) return true;
[423]90        // TODO: load strings optionally
[425]91        string_table* strings = new string_table( source );
92        m_strings->insert( strings );
93        delete strings;
[283]94        return true;
95}
96
[284]97bool nv::nmd_loader::load_animation( stream& source, const nmd_element_header& e )
[283]98{
[287]99        NV_ASSERT( m_node_data == nullptr, "MULTIPLE NODE ENTRIES!" );
100        nmd_animation_header animation_header;
101        source.read( &animation_header, sizeof( animation_header ), 1 );
102        m_node_array = new mesh_node_data[ e.children ];
[284]103        for ( uint32 i = 0; i < e.children; ++i )
[283]104        {
105                nmd_element_header element_header;
106                source.read( &element_header, sizeof( element_header ), 1 );
[420]107                skip_attributes( source, element_header.attributes );
[287]108                NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
[425]109                m_node_array[i].data = data_channel_set_creator::create_set( element_header.children );
110                load_channel_set( source, m_node_array[i].data, element_header );
[283]111        }
[423]112        m_node_data = new mesh_nodes_data( e.name, e.children, m_node_array, animation_header.frame_rate, animation_header.duration, animation_header.flat );
[283]113        return true;
114}
115
[420]116bool nv::nmd_loader::load_channel( stream& source, data_channel_set* channel_set )
117{
118        data_channel_set_creator kaccess( channel_set );
119        nmd_channel_header cheader;
120        source.read( &cheader, sizeof( cheader ), 1 );
121        raw_data_channel_access channel( kaccess.add_channel( cheader.format, cheader.count ) );
122        source.read( channel.raw_data(), channel.element_size(), channel.size() );
123        return true;
124}
125
126bool nv::nmd_loader::load_channel_set( stream& source, data_channel_set* channel_set, const nmd_element_header& e )
127{
128        data_channel_set_creator kaccess( channel_set );
129        for ( uint32 c = 0; c < e.children; ++c )
130        {
131                load_channel( source, channel_set );
132        }
[425]133        data_channel_set_creator access( channel_set );
134        access.set_name( e.name );
135        access.set_parent_id( e.parent_id );
136        access.set_transform( e.transform );
[420]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                mesh_nodes_data* result = m_node_data;
145                m_node_data = nullptr;
146                m_node_array = nullptr;
147                return result;
[283]148        }
[287]149        return nullptr;
[283]150}
151
[292]152// ----------------------------------------------------------------
153// nmd format dump
154// HACK : TEMPORARY - will go to it's own file, probably nmd_io
[420]155static void nmd_dump_channel( const raw_data_channel* channel , stream& stream_out )
156{
157        nmd_channel_header sheader;
158        sheader.format = channel->descriptor();
159        sheader.count = channel->size();
160        stream_out.write( &sheader, sizeof( sheader ), 1 );
161        stream_out.write( channel->raw_data(), channel->element_size(), channel->size() );
162}
163
164static void nmd_dump_channel_set( const data_channel_set* channel_set, stream& stream_out )
165{
166        for ( auto& channel : *channel_set )
167        {
168                nmd_dump_channel( &channel, stream_out );
169        }
170}
171
172static void nmd_dump_node( const mesh_node_data* node, stream& stream_out )
173{
174        uint32 chan_size = 0;
175        uint32 chan_count = ( node->data ? node->data->size() : 0 );
176        for ( uint32 c = 0; c < chan_count; ++c )
[292]177        {
[420]178                chan_size += sizeof( nmd_channel_header );
179                chan_size += node->data->get_channel( c )->raw_size();
180        }
[292]181
[420]182        nmd_element_header eheader;
183        eheader.type = nmd_type::NODE;
184        eheader.children   = static_cast<uint16>( chan_count );
185        eheader.size       = chan_size;
[424]186        eheader.name       = node->data->get_name();
187        eheader.parent_id  = node->data->get_parent_id();
188        eheader.transform  = node->data->get_transform();
[420]189        eheader.attributes = 0;
190        stream_out.write( &eheader, sizeof( eheader ), 1 );
[424]191        if ( chan_count > 0 ) nmd_dump_channel_set( node->data, stream_out );
[292]192}
193
[423]194void nv::nmd_dump_header( stream& stream_out, uint32 elements, uint64 name )
[292]195{
[423]196        nmd_header header;
197        header.id = four_cc<'n', 'm', 'f', '1'>::value;
198        header.elements = elements; // +1 string array
199        header.name = name;
200        header.version = 1;
201        header.attributes = 0;
202        stream_out.write( &header, sizeof( header ), 1 );
203}
204
205void nv::nmd_dump_mesh( stream& stream_out, const data_channel_set& mesh )
206{
207        uint32 size = 0;
208        for ( auto& chan : mesh )
209        {
210                size += sizeof( nmd_channel_header );
211                size += chan.raw_size();
212        }
213
214        nmd_element_header eheader;
215        eheader.type       = nmd_type::MESH;
216        eheader.children   = static_cast<uint16>( mesh.size() );
217        eheader.size       = size;
[424]218        eheader.name       = mesh.get_name();
219        eheader.transform  = mesh.get_transform();
220        eheader.parent_id  = mesh.get_parent_id();
[423]221        eheader.attributes = 0;
222        stream_out.write( &eheader, sizeof( eheader ), 1 );
223        nmd_dump_channel_set( &mesh, stream_out );
224}
225
226void nv::nmd_dump_nodes( stream& stream_out, const mesh_nodes_data& nodes )
227{
[292]228        uint32 total = sizeof( nmd_animation_header );
[423]229        for ( uint32 i = 0; i < nodes.get_count(); ++i )
[292]230        {
[423]231                const mesh_node_data* node = nodes.get_node( i );
[420]232                total += sizeof( nmd_element_header );
[292]233                if ( node->data )
[416]234                        for ( uint32 c = 0; c < node->data->size(); ++c )
[292]235                        {
[420]236                                total += sizeof( nmd_channel_header );
[423]237                                total += node->data->get_channel( c )->raw_size();
[292]238                        }
239        }
240
241        nmd_element_header header;
[423]242        header.type = nmd_type::ANIMATION;
243        header.children = static_cast<uint16>( nodes.get_count() );
244        header.size = total;
245        header.name = nodes.get_name();
246        header.transform = mat4();
247        header.parent_id = -1;
[420]248        header.attributes = 0;
249
[292]250        stream_out.write( &header, sizeof( header ), 1 );
251
252        nmd_animation_header aheader;
[423]253        aheader.frame_rate = nodes.get_frame_rate();
254        aheader.duration = nodes.get_duration();
255        aheader.flat = nodes.is_flat();
[292]256        stream_out.write( &aheader, sizeof( aheader ), 1 );
257
[423]258        for ( uint32 i = 0; i < nodes.get_count(); ++i )
[292]259        {
[423]260                nmd_dump_node( nodes.get_node( i ), stream_out );
[292]261        }
262}
263
[423]264void nv::nmd_dump_strings( stream& stream_out, const string_table& strings )
[292]265{
[423]266        nmd_element_header sheader;
267        sheader.type       = nv::nmd_type::STRINGS;
268        sheader.children   = 0;
269        sheader.size       = strings.dump_size();
270        sheader.name       = 0;
271        sheader.parent_id  = -1;
272    sheader.attributes = 0;
273        stream_out.write( &sheader, sizeof( sheader ), 1 );
274        strings.dump( stream_out );
275}
276
277void nv::nmd_dump( stream& stream_out, const mesh_data_pack* model, const string_table* strings, uint64 name )
278{
279        uint32 elements = ( strings ? 1 : 0 ) // +1 string array
280                + model->get_count() // meshes
281                + ( model->get_node_count() > 0 ? 1 : 0 ); // nodes
282        nmd_dump_header( stream_out, elements, name );
283
284        for ( uint32 i = 0; i < model->get_count(); ++i )
[292]285        {
[423]286                nmd_dump_mesh( stream_out, *model->get_mesh( i ) );
[292]287        }
288
[423]289        if ( model->get_node_count() > 0 )
[292]290        {
[423]291                nmd_dump_nodes( stream_out, *model->get_nodes() );
[292]292        }
293
[423]294        if ( strings )
[292]295        {
[423]296                nmd_dump_strings( stream_out, *strings );
[292]297        }
298}
Note: See TracBrowser for help on using the repository browser.