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

Last change on this file since 484 was 482, checked in by epyon, 10 years ago
  • skeletal animation updated
File size: 10.2 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"
[368]8#include "nv/stl/string.hh"
[416]9#include "nv/interface/data_channel_access.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 );
[420]19        skip_attributes( source, root_header.attributes );
[283]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 );
[420]24                skip_attributes( source, element_header.attributes );
[283]25                switch ( element_header.type )
26                {
[284]27                case nmd_type::MESH           : load_mesh( source, element_header ); break;
28                case nmd_type::ANIMATION      : load_animation( source, element_header ); break;
[423]29                case nmd_type::STRINGS        : load_strings( source ); break;
[283]30                default: NV_ASSERT( false, "UNKNOWN NMD ELEMENT!" ); break;
31                }
32        }
33        return true;
34}
35
[284]36bool nv::nmd_loader::load_mesh( stream& source, const nmd_element_header& e )
[283]37{
[424]38        data_channel_set* mesh = data_channel_set_creator::create_set( e.children );
[482]39        data_node_info info;
40        load_channel_set( source, mesh, info, e );
[420]41//      m_mesh_names.push_back( e.name );
[482]42        m_infos.push_back( info );
[417]43        m_meshes.push_back( mesh );
[283]44        return true;
45}
46
[482]47data_channel_set* nv::nmd_loader::release_mesh_data( size_t index, data_node_info& info )
[283]48{
[416]49        data_channel_set* result = m_meshes[ index ];
[482]50        info = m_infos[ index ];
[283]51        m_meshes[ index ] = nullptr;
52        return result;
53}
54
55void nv::nmd_loader::reset()
56{
57        for ( auto mesh : m_meshes ) if ( mesh ) delete mesh;
[287]58        if ( m_node_data ) delete m_node_data;
[482]59        if ( m_bone_data ) delete m_bone_data;
[283]60        m_meshes.clear();
[287]61
[482]62        m_node_data = nullptr;
63        m_bone_data = nullptr;
[283]64}
65
[420]66void nv::nmd_loader::skip_attributes( stream& source, uint32 count )
67{
68        if ( count == 0 ) return;
69        source.seek( count * sizeof( nmd_attribute ), origin::CUR );
70}
71
[283]72nv::nmd_loader::~nmd_loader()
73{
74        reset();
75}
76
[423]77bool nv::nmd_loader::load_strings( stream& source )
[283]78{
[425]79        if ( !m_strings ) return true;
[423]80        // TODO: load strings optionally
[425]81        string_table* strings = new string_table( source );
82        m_strings->insert( strings );
83        delete strings;
[283]84        return true;
85}
86
[284]87bool nv::nmd_loader::load_animation( stream& source, const nmd_element_header& e )
[283]88{
[287]89        NV_ASSERT( m_node_data == nullptr, "MULTIPLE NODE ENTRIES!" );
90        nmd_animation_header animation_header;
91        source.read( &animation_header, sizeof( animation_header ), 1 );
[482]92        m_node_data = new mesh_nodes_data( e.name, animation_header.frame_rate, animation_header.frame_count );
93        m_bone_data = new data_node_list( e.name );
[284]94        for ( uint32 i = 0; i < e.children; ++i )
[283]95        {
96                nmd_element_header element_header;
97                source.read( &element_header, sizeof( element_header ), 1 );
[420]98                skip_attributes( source, element_header.attributes );
[287]99                NV_ASSERT( element_header.type == nmd_type::NODE, "NODE expected!" );
[427]100                data_channel_set* set = data_channel_set_creator::create_set( element_header.children );
[482]101                data_node_info info;
102                load_channel_set( source, set, info, element_header );
103                m_bone_data->append( info );
104                m_node_data->append( set, info );
[283]105        }
[475]106        m_node_data->initialize();
[283]107        return true;
108}
109
[420]110bool nv::nmd_loader::load_channel( stream& source, data_channel_set* channel_set )
111{
112        data_channel_set_creator kaccess( channel_set );
113        nmd_channel_header cheader;
114        source.read( &cheader, sizeof( cheader ), 1 );
115        raw_data_channel_access channel( kaccess.add_channel( cheader.format, cheader.count ) );
116        source.read( channel.raw_data(), channel.element_size(), channel.size() );
117        return true;
118}
119
[482]120bool nv::nmd_loader::load_channel_set( stream& source, data_channel_set* channel_set, data_node_info& info, const nmd_element_header& e )
[420]121{
122        data_channel_set_creator kaccess( channel_set );
123        for ( uint32 c = 0; c < e.children; ++c )
124        {
125                load_channel( source, channel_set );
126        }
[482]127        info.name = e.name;
128        info.parent_id = e.parent_id;
129        info.transform = e.transform;
[420]130        return true;
131}
132
[291]133mesh_nodes_data* nv::nmd_loader::release_mesh_nodes_data( size_t )
[283]134{
[482]135        mesh_nodes_data* result = m_node_data;
136        m_node_data = nullptr;
137        return result;
[283]138}
139
[482]140data_node_list* nv::nmd_loader::release_data_node_list( size_t )
141{
142        data_node_list* result = m_bone_data;
143        m_bone_data = nullptr;
144        return result;
145}
146
147bool nv::nmd_loader::is_animated( size_t /*= 0 */ )
148{
149        if ( !m_node_data ) return false;
150        return m_node_data->is_animated();
151}
152
[292]153// ----------------------------------------------------------------
154// nmd format dump
155// HACK : TEMPORARY - will go to it's own file, probably nmd_io
[420]156
[423]157void nv::nmd_dump_header( stream& stream_out, uint32 elements, uint64 name )
[292]158{
[423]159        nmd_header header;
160        header.id = four_cc<'n', 'm', 'f', '1'>::value;
161        header.elements = elements; // +1 string array
162        header.name = name;
163        header.version = 1;
164        header.attributes = 0;
165        stream_out.write( &header, sizeof( header ), 1 );
166}
167
[482]168void nv::nmd_dump_element( stream& stream_out, const data_channel_set& data, const data_node_info& info, nmd_type type )
[423]169{
170        uint32 size = 0;
[427]171        for ( auto& chan : data )
[423]172        {
173                size += sizeof( nmd_channel_header );
174                size += chan.raw_size();
175        }
176
177        nmd_element_header eheader;
[427]178        eheader.type       = type;
179        eheader.children   = static_cast<uint16>( data.size() );
[423]180        eheader.size       = size;
[482]181        eheader.name       = info.name;
182        eheader.transform  = info.transform;
183        eheader.parent_id  = info.parent_id;
[423]184        eheader.attributes = 0;
185        stream_out.write( &eheader, sizeof( eheader ), 1 );
[427]186        for ( auto& channel : data )
187        {
188                nmd_channel_header cheader;
189                cheader.format = channel.descriptor();
190                cheader.count = channel.size();
191                stream_out.write( &cheader, sizeof( cheader ), 1 );
192                stream_out.write( channel.raw_data(), channel.element_size(), channel.size() );
193        }
[423]194}
195
196void nv::nmd_dump_nodes( stream& stream_out, const mesh_nodes_data& nodes )
197{
[292]198        uint32 total = sizeof( nmd_animation_header );
[427]199        for ( auto node : nodes )
[292]200        {
[420]201                total += sizeof( nmd_element_header );
[427]202                for ( uint32 c = 0; c < node->size(); ++c )
203                {
204                        total += sizeof( nmd_channel_header );
205                        total += node->get_channel( c )->raw_size();
206                }
[292]207        }
208
209        nmd_element_header header;
[423]210        header.type = nmd_type::ANIMATION;
[428]211        header.children = static_cast<uint16>( nodes.size() );
[423]212        header.size = total;
213        header.name = nodes.get_name();
214        header.transform = mat4();
215        header.parent_id = -1;
[420]216        header.attributes = 0;
217
[292]218        stream_out.write( &header, sizeof( header ), 1 );
219
220        nmd_animation_header aheader;
[470]221        aheader.frame_rate  = nodes.get_fps();
222        aheader.frame_count = nodes.get_frame_count();
[482]223        aheader.unused      = false;
[292]224        stream_out.write( &aheader, sizeof( aheader ), 1 );
225
[482]226        for ( uint32 i = 0; i < nodes.size(); ++i )
227        {
228                nmd_dump_element( stream_out, *nodes[i], nodes.get_info(i), nv::nmd_type::NODE );
229        }
230}
231
232void nv::nmd_dump_bones( stream& stream_out, const data_node_list& nodes )
233{
234        uint32 total = sizeof( nmd_animation_header );
[427]235        for ( auto node : nodes )
[292]236        {
[482]237                total += sizeof( nmd_element_header );
[292]238        }
[482]239
240        nmd_element_header header;
241        header.type = nmd_type::ANIMATION;
242        header.children = static_cast<uint16>( nodes.size() );
243        header.size = total;
244        header.name = nodes.get_name();
245        header.transform = mat4();
246        header.parent_id = -1;
247        header.attributes = 0;
248
249        stream_out.write( &header, sizeof( header ), 1 );
250
251        nmd_animation_header aheader;
252        aheader.frame_rate = 0;
253        aheader.frame_count = 0;
254        aheader.unused = false;
255        stream_out.write( &aheader, sizeof( aheader ), 1 );
256
257        for ( auto node : nodes )
258        {
259                nmd_element_header eheader;
260                eheader.type = nv::nmd_type::NODE;
261                eheader.children = 0;
262                eheader.size = 0;
263                eheader.name = node.name;
264                eheader.transform = node.transform;
265                eheader.parent_id = node.parent_id;
266                eheader.attributes = 0;
267                stream_out.write( &eheader, sizeof( eheader ), 1 );
268        }
[292]269}
270
[423]271void nv::nmd_dump_strings( stream& stream_out, const string_table& strings )
[292]272{
[423]273        nmd_element_header sheader;
274        sheader.type       = nv::nmd_type::STRINGS;
275        sheader.children   = 0;
276        sheader.size       = strings.dump_size();
[431]277        sheader.name       = shash64();
[423]278        sheader.parent_id  = -1;
279    sheader.attributes = 0;
280        stream_out.write( &sheader, sizeof( sheader ), 1 );
281        strings.dump( stream_out );
282}
283
[482]284void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const mesh_nodes_data* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
[423]285{
286        uint32 elements = ( strings ? 1 : 0 ) // +1 string array
[480]287                + meshes.size() // meshes
288                + ( nodes && nodes->size() > 0 ? 1 : 0 ); // nodes
[423]289        nmd_dump_header( stream_out, elements, name );
290
[480]291        for ( uint32 i = 0; i < meshes.size(); ++i )
[292]292        {
[480]293                NV_ASSERT( meshes[i], "mesh is null!" );
[482]294                nmd_dump_element( stream_out, *meshes[i], infos[i], nv::nmd_type::MESH );
[292]295        }
296
[480]297        if ( nodes && nodes->size() > 0 )
[292]298        {
[480]299                nmd_dump_nodes( stream_out, *nodes );
[292]300        }
301
[423]302        if ( strings )
[292]303        {
[423]304                nmd_dump_strings( stream_out, *strings );
[292]305        }
306}
[480]307
[482]308void nv::nmd_dump( stream& stream_out, array_view< data_channel_set* > meshes, array_view< data_node_info > infos, const nv::data_node_list* nodes, const string_table* strings /*= nullptr*/, uint64 name /*= 0 */ )
309{
310        uint32 elements = ( strings ? 1 : 0 ) // +1 string array
311                + meshes.size() // meshes
312                + ( nodes && nodes->size() > 0 ? 1 : 0 ); // nodes
313        nmd_dump_header( stream_out, elements, name );
314
315        for ( uint32 i = 0; i < meshes.size(); ++i )
316        {
317                NV_ASSERT( meshes[i], "mesh is null!" );
318                nmd_dump_element( stream_out, *meshes[i], infos[i], nv::nmd_type::MESH );
319        }
320
321        if ( nodes && nodes->size() > 0 )
322        {
323                nmd_dump_bones( stream_out, *nodes );
324        }
325
326        if ( strings )
327        {
328                nmd_dump_strings( stream_out, *strings );
329        }
330}
331
[480]332void nv::nmd_dump( stream& stream_out, const mesh_nodes_data& animation, const string_table* strings, uint64 name )
333{
334        uint32 elements = ( strings ? 1 : 0 ) // +1 string array
335                + ( animation.size() > 0 ? 1 : 0 ); // nodes
336        nmd_dump_header( stream_out, elements, name );
337
338        if ( animation.size() > 0 )
339        {
340                nmd_dump_nodes( stream_out, animation );
341        }
342
343        if ( strings )
344        {
345                nmd_dump_strings( stream_out, *strings );
346        }
347}
Note: See TracBrowser for help on using the repository browser.