// Copyright (C) 2011-2015 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/gfx/skeleton_instance.hh" #include "nv/core/profiler.hh" void nv::skeleton_binding::prepare( const mesh_nodes_data* node_data, const data_node_list& bone_data ) { if ( m_indices.empty() ) { // TODO: either fixed size struct or static allocator hash_store< shash64, uint16 > bone_names; m_indices.resize( node_data->size() ); for ( nv::uint16 bi = 0; bi < bone_data.size(); ++bi ) bone_names[bone_data[bi].name] = bi; for ( uint32 n = 0; n < node_data->size(); ++n ) { sint16 bone_id = -1; auto bi = bone_names.find( node_data->get_info( n ).name ); if ( bi != bone_names.end() ) { bone_id = sint16( bi->second ); } m_indices[n] = bone_id; } m_bone_count = bone_data.size(); } if ( m_key.size() == 0 ) { for ( uint32 n = 0; n < node_data->size(); ++n ) if ( ( *node_data )[n]->size() > 0 ) { m_key = ( *node_data )[n]->get_interpolation_key(); break; } } } void nv::skeleton_instance::assign( const skeleton_transforms& skeleton, const bone_transforms& bones ) { if ( bones.size() != m_matrix.size() ) m_matrix.resize( bones.size() ); const transform* transforms = skeleton.transforms(); for ( uint32 n = 0; n < skeleton.size(); ++n ) { m_matrix[n] = transforms[n].extract() * bones.m_offsets[n]; } } void nv::skeleton_instance::assign( const bone_transforms& bones ) { if ( bones.size() != m_matrix.size() ) m_matrix.resize( bones.size() ); } void nv::skeleton_transforms::assign( const data_node_list* node_data ) { NV_ASSERT( node_data, "!!!" ); if ( m_transforms.size() != node_data->size() ) m_transforms.resize( node_data->size() ); for ( uint32 n = 0; n < node_data->size(); ++n ) { const data_node_info& info = (*node_data)[ n ]; m_transforms[n] = transform( info.transform ); } } void nv::skeleton_transforms::interpolate( const skeleton_transforms& a, const skeleton_transforms& b, float t ) { NV_ASSERT( a.size() == b.size(), "!!!" ); if ( m_transforms.size() != a.size() ) m_transforms.resize( a.size() ); for ( uint32 n = 0; n < a.size(); ++n ) { m_transforms[n] = nv::interpolate( a.m_transforms[n], b.m_transforms[n], t ); } } void nv::skeleton_transforms::assign( const skeleton_transforms& other ) { m_transforms.assign( other.m_transforms ); } void nv::skeleton_transforms::animate_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame ) { if ( m_transforms.size() != binding.skeleton_size() ) m_transforms.resize( binding.skeleton_size() ); for ( uint32 n = 0; n < node_data->size(); ++n ) { const data_channel_set* node = ( *node_data )[n]; sint16 bone_id = binding.m_indices[n]; if ( bone_id >= 0 ) { if ( node->size() > 0 ) m_transforms[bone_id] = raw_channel_interpolator( node, binding.m_key ).get< transform >( frame ); int confirm_that_not_needed; // else // m_transforms[bone_id] = transform( node->get_transform() ); } } } void nv::skeleton_transforms::blend_local( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, float blend ) { if ( m_transforms.size() != binding.skeleton_size() ) m_transforms.resize( binding.skeleton_size() ); for ( uint32 n = 0; n < node_data->size(); ++n ) { const data_channel_set* node = ( *node_data )[n]; sint16 bone_id = binding.m_indices[n]; if ( bone_id >= 0 ) { transform tr = node->size() > 0 ? raw_channel_interpolator( node, binding.m_key ).get< transform >( frame ) : transform( /*node->get_transform()*/ ); int confirm_that_not_needed; m_transforms[bone_id] = nv::interpolate( m_transforms[bone_id], tr, blend ); } } } void nv::skeleton_transforms::delocalize_rec( const data_node_tree& node_data, const skeleton_binding& binding, uint32 id, const transform& parent ) { sint16 bone_id = binding.m_indices[id]; transform global_mat = parent; if ( bone_id >= 0 ) { global_mat *= m_transforms[bone_id]; m_transforms[bone_id] = global_mat; } for ( auto child : node_data.children( id ) ) { delocalize_rec( node_data, binding, child, global_mat ); } } void nv::skeleton_transforms::animate_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local ) { const data_channel_set* node = ( *node_data )[id]; transform node_mat; if ( node->size() > 0 ) node_mat = raw_channel_interpolator( node, binding.m_key ).get< transform >( frame ); int confirm_that_not_needed; // else // node_mat = transform( node->get_transform() ); sint16 bone_id = binding.m_indices[id]; transform global_mat = parent * node_mat; if ( bone_id >= 0 ) { m_transforms[bone_id] = local ? node_mat : global_mat; } for ( auto child : node_data->children( id ) ) { animate_rec( node_data, binding, frame, child, global_mat, local ); } } void nv::skeleton_transforms::blend_rec( const mesh_nodes_data* node_data, const skeleton_binding& binding, float frame, uint32 id, const transform& parent, bool local, float blend ) { const data_channel_set* node = ( *node_data )[id]; int confirm_that_not_needed; transform node_mat/*( node->get_transform() )*/; if ( node->size() > 0 ) { raw_channel_interpolator interpolator( node, binding.m_key ); node_mat = interpolator.get< transform >( frame ); } sint16 bone_id = binding.m_indices[id]; transform global_mat = parent * node_mat; if ( bone_id >= 0 ) { m_transforms[bone_id] = nv::interpolate( m_transforms[bone_id], local ? node_mat : global_mat, blend ); } for ( auto child : node_data->children( id ) ) { blend_rec( node_data, binding, frame, child, global_mat, local, blend ); } } void nv::bone_transforms::prepare( const data_node_list& bone_data ) { if ( m_offsets.empty() ) { m_offsets.resize( bone_data.size() ); for ( nv::uint16 bi = 0; bi < bone_data.size(); ++bi ) m_offsets[bi] = bone_data[bi].transform; } }