[395] | 1 | // Copyright (C) 2011-2015 ChaosForge Ltd
|
---|
| 2 | // http://chaosforge.org/
|
---|
| 3 | //
|
---|
| 4 | // This file is part of Nova libraries.
|
---|
| 5 | // For conditions of distribution and use, see copying.txt file in root folder.
|
---|
[227] | 6 |
|
---|
| 7 | #include "nv/gfx/skeletal_mesh.hh"
|
---|
| 8 |
|
---|
| 9 | #include "nv/interface/context.hh"
|
---|
| 10 | #include "nv/interface/device.hh"
|
---|
[392] | 11 | #include "nv/stl/unordered_map.hh"
|
---|
[227] | 12 |
|
---|
[467] | 13 | void nv::skeletal_animation_entry::initialize()
|
---|
[227] | 14 | {
|
---|
[287] | 15 | m_prepared = false;
|
---|
| 16 | m_children = nullptr;
|
---|
| 17 | m_offsets = nullptr;
|
---|
[428] | 18 | m_bone_ids = new sint16[m_node_data->size()];
|
---|
[287] | 19 |
|
---|
[419] | 20 | NV_ASSERT( m_node_data, "node data empty!" );
|
---|
| 21 |
|
---|
[287] | 22 | if ( !m_node_data->is_flat() )
|
---|
| 23 | {
|
---|
[428] | 24 | m_children = new vector< uint32 >[m_node_data->size()];
|
---|
| 25 | for ( uint32 n = 0; n < m_node_data->size(); ++n )
|
---|
[287] | 26 | {
|
---|
[427] | 27 | const data_channel_set* node = (*m_node_data)[n];
|
---|
| 28 | if ( node->get_parent_id() != -1 )
|
---|
[287] | 29 | {
|
---|
[427] | 30 | m_children[ node->get_parent_id()].push_back( n );
|
---|
[287] | 31 | }
|
---|
| 32 | }
|
---|
| 33 | }
|
---|
[283] | 34 | }
|
---|
| 35 |
|
---|
[467] | 36 | void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 time ) const
|
---|
[283] | 37 | {
|
---|
[290] | 38 | float tick_time = ( time * 0.001f ) * m_frame_rate;
|
---|
| 39 | float anim_time = m_start;
|
---|
| 40 | if ( m_duration > 0.0f ) anim_time += fmodf( tick_time, m_duration );
|
---|
[287] | 41 |
|
---|
| 42 | if ( !m_node_data->is_flat() )
|
---|
| 43 | {
|
---|
| 44 | animate_rec( data, anim_time, 0, mat4() );
|
---|
| 45 | return;
|
---|
| 46 | }
|
---|
| 47 |
|
---|
[428] | 48 | for ( uint32 n = 0; n < m_node_data->size(); ++n )
|
---|
[287] | 49 | if ( m_bone_ids[n] >= 0 )
|
---|
| 50 | {
|
---|
[428] | 51 | const data_channel_set* node = (*m_node_data)[n];
|
---|
[427] | 52 | nv::mat4 node_mat( node->get_transform() );
|
---|
[287] | 53 |
|
---|
[427] | 54 | if ( node->size() > 0 )
|
---|
[287] | 55 | {
|
---|
[427] | 56 | raw_channel_interpolator interpolator( node, m_interpolation_key );
|
---|
[419] | 57 | node_mat = interpolator.get< mat4 >( anim_time );
|
---|
[287] | 58 | }
|
---|
| 59 |
|
---|
| 60 | sint16 bone_id = m_bone_ids[n];
|
---|
| 61 | data[ bone_id ] = node_mat * m_offsets[ bone_id ];
|
---|
| 62 | }
|
---|
[283] | 63 | }
|
---|
| 64 |
|
---|
[467] | 65 | void nv::skeletal_animation_entry::prepare( const mesh_nodes_data* bones )
|
---|
[283] | 66 | {
|
---|
[287] | 67 | if ( m_prepared ) return;
|
---|
[420] | 68 | unordered_map< uint64, uint16 > bone_names;
|
---|
[428] | 69 | m_offsets = new mat4[ bones->size() ];
|
---|
| 70 | for ( nv::uint16 bi = 0; bi < bones->size(); ++bi )
|
---|
[287] | 71 | {
|
---|
[428] | 72 | const data_channel_set* bone = (*bones)[ bi ];
|
---|
[431] | 73 | bone_names[ bone->get_name().value() ] = bi;
|
---|
[427] | 74 | m_offsets[bi] = bone->get_transform();
|
---|
[287] | 75 | }
|
---|
| 76 |
|
---|
[428] | 77 | for ( uint32 n = 0; n < m_node_data->size(); ++n )
|
---|
[287] | 78 | {
|
---|
[428] | 79 | const data_channel_set* node = (*m_node_data)[ n ];
|
---|
[287] | 80 | sint16 bone_id = -1;
|
---|
| 81 |
|
---|
[431] | 82 | auto bi = bone_names.find( node->get_name().value() );
|
---|
[287] | 83 | if ( bi != bone_names.end() )
|
---|
| 84 | {
|
---|
[406] | 85 | bone_id = sint16( bi->second );
|
---|
[287] | 86 | }
|
---|
| 87 | m_bone_ids[n] = bone_id;
|
---|
[419] | 88 |
|
---|
[427] | 89 | if ( m_interpolation_key.size() == 0 && node->size() > 0 )
|
---|
| 90 | m_interpolation_key = node->get_interpolation_key();
|
---|
[419] | 91 |
|
---|
[287] | 92 | }
|
---|
| 93 | m_prepared = true;
|
---|
[283] | 94 | }
|
---|
| 95 |
|
---|
[467] | 96 | void nv::skeletal_animation_entry::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
|
---|
[287] | 97 | {
|
---|
| 98 | // TODO: fix transforms, which are now embedded,
|
---|
| 99 | // see note in assimp_loader.cc:load_node
|
---|
[428] | 100 | const data_channel_set* node = ( *m_node_data )[ node_id ];
|
---|
[427] | 101 | mat4 node_mat( node->get_transform() );
|
---|
[287] | 102 |
|
---|
[427] | 103 | if ( node->size() > 0 )
|
---|
[287] | 104 | {
|
---|
[427] | 105 | raw_channel_interpolator interpolator( node, m_interpolation_key );
|
---|
[419] | 106 | node_mat = interpolator.get< mat4 >( time );
|
---|
[287] | 107 | }
|
---|
| 108 |
|
---|
| 109 | mat4 global_mat = parent_mat * node_mat;
|
---|
| 110 |
|
---|
| 111 | sint16 bone_id = m_bone_ids[ node_id ];
|
---|
| 112 | if ( bone_id >= 0 )
|
---|
| 113 | {
|
---|
| 114 | data[ bone_id ] = global_mat * m_offsets[ bone_id ];
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | for ( auto child : m_children[ node_id ] )
|
---|
| 118 | {
|
---|
| 119 | animate_rec( data, time, child, global_mat );
|
---|
| 120 | }
|
---|
| 121 | }
|
---|
| 122 |
|
---|
[467] | 123 | nv::skeletal_animation_entry::~skeletal_animation_entry()
|
---|
[287] | 124 | {
|
---|
| 125 | delete[] m_offsets;
|
---|
| 126 | delete[] m_children;
|
---|
| 127 | delete[] m_bone_ids;
|
---|
| 128 | }
|
---|
| 129 |
|
---|
[467] | 130 | nv::skeletal_mesh::skeletal_mesh( context* a_context, const data_channel_set* a_mesh, const mesh_nodes_data* a_bone_data )
|
---|
| 131 | : m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr )
|
---|
[287] | 132 | {
|
---|
[458] | 133 | if ( a_mesh )
|
---|
| 134 | {
|
---|
| 135 | m_va = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
|
---|
| 136 | m_index_count = a_mesh->get_channel_size( slot::INDEX );
|
---|
| 137 | }
|
---|
[287] | 138 | if ( m_bone_data )
|
---|
| 139 | {
|
---|
[428] | 140 | m_transform = new mat4[ m_bone_data->size() ];
|
---|
[287] | 141 | }
|
---|
| 142 | }
|
---|
| 143 |
|
---|
[467] | 144 | void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
|
---|
[283] | 145 | {
|
---|
[287] | 146 | if ( m_bone_data && a_anim )
|
---|
[283] | 147 | {
|
---|
[467] | 148 | skeletal_animation_entry * anim = static_cast<skeletal_animation_entry*>( a_anim );
|
---|
[296] | 149 | anim->prepare( m_bone_data );
|
---|
[287] | 150 | anim->update_skeleton( m_transform, a_anim_time );
|
---|
[283] | 151 | }
|
---|
| 152 | }
|
---|
| 153 |
|
---|
[467] | 154 | void nv::skeletal_mesh::update( program a_program )
|
---|
[283] | 155 | {
|
---|
[287] | 156 | if ( m_bone_data )
|
---|
[428] | 157 | m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->size() );
|
---|
[287] | 158 | }
|
---|
| 159 |
|
---|
[467] | 160 | nv::transform nv::skeletal_mesh::get_node_transform( uint32 node_id ) const
|
---|
[287] | 161 | {
|
---|
[290] | 162 | if ( node_id == 0 ) return transform();
|
---|
[458] | 163 | if ( node_id == uint32(-1) ) return transform( m_transform[0] );
|
---|
[287] | 164 | return transform( m_transform[ node_id ] );
|
---|
| 165 | }
|
---|
| 166 |
|
---|
[467] | 167 | nv::mat4 nv::skeletal_mesh::get_node_matrix( uint32 node_id ) const
|
---|
[287] | 168 | {
|
---|
| 169 | return m_transform[ node_id ];
|
---|
| 170 | }
|
---|