// Copyright (C) 2014-2017 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of Nova libraries. // For conditions of distribution and use, see copying.txt file in root folder. #include "nv/formats/ndfm_loader.hh" #include "nv/interface/data_channel_access.hh" #include "nv/stl/string.hh" using namespace nv; #if 0 bool nv::ndfm_loader::load( stream& source ) { // TODO: proper error handling reset(); ndf_header header; source.read( &header, sizeof( header ), 1 ); ndf_element root_header; source.read( &root_header, sizeof( root_header ), 1 ); skip_attributes( source, root_header.attributes ); for ( uint32 i = 0; i < root_header.children; ++i ) { ndf_element element_header; source.read( &element_header, sizeof( element_header ), 1 ); skip_attributes( source, element_header.attributes ); if ( element_header.type == "mesh"_sh64 ) load_mesh( source, element_header ); else if ( element_header.type == "animation"_sh64 ) load_animation( source, element_header ); else if ( element_header.type == "strings"_sh64 ) load_strings( source ); else NV_ASSERT( false, "UNKNOWN NMD ELEMENT!" ); } return true; } bool nv::ndfm_loader::load_mesh( stream& source, const ndf_element& e ) { data_channel_set* mesh = data_channel_set_creator::create_set( e.children ); load_channel_set( source, mesh, e ); m_meshes.push_back( mesh ); return true; } data_channel_set* nv::ndfm_loader::release_mesh_data( uint32 index ) { data_channel_set* result = m_meshes[index]; m_meshes[index] = nullptr; return result; } void nv::ndfm_loader::reset() { for ( auto mesh : m_meshes ) if ( mesh ) delete mesh; if ( m_node_data ) delete m_node_data; m_meshes.clear(); m_node_data = nullptr; } void nv::ndfm_loader::skip_attributes( stream& source, uint32 count ) { if ( count == 0 ) return; source.seek( count * sizeof( ndf_attribute ), origin::CUR ); } nv::ndfm_loader::~ndfm_loader() { reset(); } bool nv::ndfm_loader::load_strings( stream& source ) { if ( !m_strings ) return true; // TODO: load strings optionally string_table* strings = new string_table( source ); m_strings->insert( strings ); delete strings; return true; } bool nv::ndfm_loader::load_animation( stream& source, const ndf_element& e ) { NV_ASSERT( m_node_data == nullptr, "MULTIPLE NODE ENTRIES!" ); ndfm_animation_data animation_header; source.read( &animation_header, sizeof( animation_header ), 1 ); m_node_data = new mesh_nodes_data( e.name, animation_header.frame_rate, animation_header.frame_count, animation_header.flat ); for ( uint32 i = 0; i < e.children; ++i ) { ndf_element element_header; source.read( &element_header, sizeof( element_header ), 1 ); skip_attributes( source, element_header.attributes ); NV_ASSERT( element_header.type == "node"_sh64, "NODE expected!" ); data_channel_set* set = data_channel_set_creator::create_set( element_header.children ); load_channel_set( source, set, element_header ); m_node_data->append( set ); } m_node_data->initialize(); return true; } bool nv::ndfm_loader::load_channel( stream& source, data_channel_set* channel_set ) { data_channel_set_creator kaccess( channel_set ); ndfm_channel_header cheader; source.read( &cheader, sizeof( cheader ), 1 ); raw_data_channel_access channel( kaccess.add_channel( cheader.format, cheader.count ) ); source.read( channel.raw_data(), channel.element_size(), channel.size() ); return true; } bool nv::ndfm_loader::load_channel_set( stream& source, data_channel_set* channel_set, const ndf_element& e ) { ndfm_node_data nheader; source.read( &nheader, sizeof( nheader ), 1 ); data_channel_set_creator kaccess( channel_set ); for ( uint32 c = 0; c < e.children; ++c ) { load_channel( source, channel_set ); } data_channel_set_creator access( channel_set ); access.set_name( e.name ); access.set_parent_id( nheader.parent_id ); access.set_transform( nheader.transform ); return true; } mesh_nodes_data* nv::ndfm_loader::release_mesh_nodes_data( uint32 ) { mesh_nodes_data* result = m_node_data; m_node_data = nullptr; return result; } data_node_list* nv::ndfm_loader::release_data_node_list( uint32 /*= 0 */ ) { if ( !m_node_data ) return nullptr; data_node_list* result = new data_node_list( m_node_data->get_name() ); for ( auto node : *m_node_data ) result->append( node->get_info() ); delete m_node_data; m_node_data = nullptr; return result; } bool nv::ndfm_loader::is_animated( uint32 /*= 0 */ ) { if ( !m_node_data ) return false; return m_node_data->is_animated(); } // ---------------------------------------------------------------- // nmd format dump // HACK : TEMPORARY - will go to it's own file, probably nmd_io void nv::ndfm_dump_header( stream& stream_out, uint16 elements, shash64 name ) { ndf_header header; header.id = four_cc<'n', 'd', 'f', '1'>::value; header.version = 1; stream_out.write( &header, sizeof( header ), 1 ); ndf_element eheader; eheader.name = name; eheader.type = "model"_sh64; eheader.flags = 0; eheader.size = 0; eheader.attributes = 0; eheader.children = elements; stream_out.write( &eheader, sizeof( eheader ), 1 ); } void nv::ndfm_dump_element( stream& stream_out, const data_channel_set& data, shash64 type ) { uint32 size = sizeof( ndfm_node_data ); for ( auto& chan : data ) { size += sizeof( ndfm_channel_header ); size += chan.raw_size(); } ndf_element eheader; eheader.name = data.get_name(); eheader.type = type; eheader.flags = 0; eheader.size = size; eheader.attributes = 0; eheader.children = static_cast( data.size() ); stream_out.write( &eheader, sizeof( eheader ), 1 ); ndfm_node_data nheader; int confirm_that_not_needed; // nheader.transform = data.get_transform(); nheader.parent_id = data.get_parent_id(); stream_out.write( &nheader, sizeof( nheader ), 1 ); for ( auto& channel : data ) { ndfm_channel_header cheader; cheader.format = channel.descriptor(); cheader.count = channel.size(); stream_out.write( &cheader, sizeof( cheader ), 1 ); stream_out.write( channel.raw_data(), channel.element_size(), channel.size() ); } } void nv::ndfm_dump_animation( stream& stream_out, const mesh_nodes_data& nodes ) { uint32 total = sizeof( ndfm_animation_data ); for ( auto node : nodes ) { total += sizeof( ndf_element ) + sizeof( ndfm_node_data ); for ( uint32 c = 0; c < node->size(); ++c ) { total += sizeof( ndfm_channel_header ); total += node->get_channel( c )->raw_size(); } } ndf_element eheader; eheader.name = nodes.get_name(); eheader.type = "animation"_sh64; eheader.flags = 0; eheader.size = total; eheader.attributes = 0; eheader.children = static_cast( nodes.size() ); stream_out.write( &eheader, sizeof( eheader ), 1 ); ndfm_animation_data aheader; aheader.frame_rate = nodes.get_fps(); aheader.frame_count = nodes.get_frame_count(); stream_out.write( &aheader, sizeof( aheader ), 1 ); for ( auto node : nodes ) { ndfm_dump_element( stream_out, *node, "node"_sh64 ); } } void nv::ndfm_dump_bones( stream& stream_out, const data_node_list& bones ) { uint32 total = sizeof( ndfm_animation_data ); for ( auto bone : bones ) { total += sizeof( ndf_element ) + sizeof( ndfm_node_data ); } ndf_element eheader; eheader.name = bones.get_name(); eheader.type = "animation"_sh64; eheader.flags = 0; eheader.size = total; eheader.attributes = 0; eheader.children = static_cast( bones.size() ); stream_out.write( &eheader, sizeof( eheader ), 1 ); for ( auto bone : bones ) { uint32 size = sizeof( ndfm_node_data ); ndf_element eheader; eheader.name = bone.name; eheader.type = "bone"_sh64; eheader.flags = 0; eheader.size = size; eheader.attributes = 0; eheader.children = 0; stream_out.write( &eheader, sizeof( eheader ), 1 ); ndfm_node_data nheader; nheader.transform = bone.transform; nheader.parent_id = bone.parent_id; stream_out.write( &nheader, sizeof( nheader ), 1 ); } } void nv::ndfm_dump_strings( stream& stream_out, const string_table& strings ) { ndf_element sheader; sheader.name = shash64(); sheader.type = "strings"_sh64; sheader.flags = 0; sheader.size = strings.dump_size(); sheader.children = 0; sheader.attributes = 0; stream_out.write( &sheader, sizeof( sheader ), 1 ); strings.dump( stream_out ); } // void nv::ndfm_dump( stream& stream_out, const mesh_data_pack* model, const string_table* strings, shash64 name ) // { // uint16 elements = ( strings ? 1 : 0 ) // +1 string array // + uint16( model->get_count() ) // meshes // + ( model->get_node_count() > 0 ? 1 : 0 ); // nodes // ndfm_dump_header( stream_out, elements, name ); // // for ( uint32 i = 0; i < model->get_count(); ++i ) // { // ndfm_dump_element( stream_out, *model->get_mesh( i ), "mesh"_sh64 ); // } // // if ( model->get_node_count() > 0 ) // { // ndfm_dump_nodes( stream_out, *model->get_nodes() ); // } // // if ( strings ) // { // ndfm_dump_strings( stream_out, *strings ); // } // } #endif