[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 | {
|
---|
[470] | 15 | m_root = uint32(-1);
|
---|
[287] | 16 | m_prepared = false;
|
---|
| 17 | m_children = nullptr;
|
---|
| 18 | m_offsets = nullptr;
|
---|
[428] | 19 | m_bone_ids = new sint16[m_node_data->size()];
|
---|
[287] | 20 |
|
---|
[419] | 21 | NV_ASSERT( m_node_data, "node data empty!" );
|
---|
| 22 |
|
---|
[287] | 23 | if ( !m_node_data->is_flat() )
|
---|
| 24 | {
|
---|
[428] | 25 | m_children = new vector< uint32 >[m_node_data->size()];
|
---|
| 26 | for ( uint32 n = 0; n < m_node_data->size(); ++n )
|
---|
[287] | 27 | {
|
---|
[427] | 28 | const data_channel_set* node = (*m_node_data)[n];
|
---|
| 29 | if ( node->get_parent_id() != -1 )
|
---|
[287] | 30 | {
|
---|
[427] | 31 | m_children[ node->get_parent_id()].push_back( n );
|
---|
[287] | 32 | }
|
---|
[470] | 33 | else
|
---|
| 34 | {
|
---|
| 35 | if ( m_root >= 0 )
|
---|
| 36 | {
|
---|
| 37 | m_root = uint32( -2 );
|
---|
| 38 | }
|
---|
| 39 | else
|
---|
| 40 | m_root = n;
|
---|
| 41 | }
|
---|
[287] | 42 | }
|
---|
[470] | 43 | NV_ASSERT( m_root != uint32( -1 ), "Animation without root!" );
|
---|
[287] | 44 | }
|
---|
[283] | 45 | }
|
---|
| 46 |
|
---|
[470] | 47 | void nv::skeletal_animation_entry::update_skeleton( mat4* data, uint32 a_ms_time ) const
|
---|
[283] | 48 | {
|
---|
[470] | 49 | float fframe = ( a_ms_time * 0.001f ) * m_fps;
|
---|
[471] | 50 | uint32 frame = uint32( math::floor( fframe ) );
|
---|
[470] | 51 | float reminder = fframe - static_cast<float>( frame );
|
---|
| 52 | uint32 duration = get_frame_count();
|
---|
| 53 | if ( duration == 0 )
|
---|
| 54 | {
|
---|
| 55 | frame = get_start_frame();
|
---|
| 56 | fframe = static_cast<float>( frame );
|
---|
| 57 | }
|
---|
| 58 | else if ( frame >= duration )
|
---|
| 59 | {
|
---|
| 60 | if ( is_looping() )
|
---|
| 61 | {
|
---|
| 62 | frame = frame % duration;
|
---|
| 63 | fframe = static_cast<float>( frame ) + reminder;
|
---|
| 64 | }
|
---|
| 65 | else
|
---|
| 66 | {
|
---|
| 67 | frame = get_end_frame();
|
---|
| 68 | fframe = static_cast<float>( frame );
|
---|
| 69 | }
|
---|
| 70 | }
|
---|
[287] | 71 |
|
---|
| 72 | if ( !m_node_data->is_flat() )
|
---|
| 73 | {
|
---|
[470] | 74 | if ( m_root == uint32( -2 ) ) // multi-root
|
---|
| 75 | {
|
---|
| 76 | for ( uint32 n = 0; n < m_node_data->size(); ++n )
|
---|
| 77 | if ( ( *m_node_data )[n]->get_parent_id() == -1 )
|
---|
| 78 | animate_rec( data, fframe, n, mat4() );
|
---|
| 79 | }
|
---|
| 80 | else
|
---|
| 81 | animate_rec( data, fframe, m_root, mat4() );
|
---|
[287] | 82 | return;
|
---|
| 83 | }
|
---|
| 84 |
|
---|
[428] | 85 | for ( uint32 n = 0; n < m_node_data->size(); ++n )
|
---|
[287] | 86 | if ( m_bone_ids[n] >= 0 )
|
---|
| 87 | {
|
---|
[428] | 88 | const data_channel_set* node = (*m_node_data)[n];
|
---|
[427] | 89 | nv::mat4 node_mat( node->get_transform() );
|
---|
[287] | 90 |
|
---|
[427] | 91 | if ( node->size() > 0 )
|
---|
[287] | 92 | {
|
---|
[427] | 93 | raw_channel_interpolator interpolator( node, m_interpolation_key );
|
---|
[470] | 94 | node_mat = interpolator.get< mat4 >( fframe );
|
---|
[287] | 95 | }
|
---|
| 96 |
|
---|
| 97 | sint16 bone_id = m_bone_ids[n];
|
---|
| 98 | data[ bone_id ] = node_mat * m_offsets[ bone_id ];
|
---|
| 99 | }
|
---|
[283] | 100 | }
|
---|
| 101 |
|
---|
[467] | 102 | void nv::skeletal_animation_entry::prepare( const mesh_nodes_data* bones )
|
---|
[283] | 103 | {
|
---|
[287] | 104 | if ( m_prepared ) return;
|
---|
[470] | 105 | nv::hash_store< shash64, uint16 > bone_names;
|
---|
[428] | 106 | m_offsets = new mat4[ bones->size() ];
|
---|
| 107 | for ( nv::uint16 bi = 0; bi < bones->size(); ++bi )
|
---|
[287] | 108 | {
|
---|
[428] | 109 | const data_channel_set* bone = (*bones)[ bi ];
|
---|
[470] | 110 | bone_names[ bone->get_name() ] = bi;
|
---|
[427] | 111 | m_offsets[bi] = bone->get_transform();
|
---|
[287] | 112 | }
|
---|
| 113 |
|
---|
[428] | 114 | for ( uint32 n = 0; n < m_node_data->size(); ++n )
|
---|
[287] | 115 | {
|
---|
[428] | 116 | const data_channel_set* node = (*m_node_data)[ n ];
|
---|
[287] | 117 | sint16 bone_id = -1;
|
---|
| 118 |
|
---|
[470] | 119 | auto bi = bone_names.find( node->get_name() );
|
---|
[287] | 120 | if ( bi != bone_names.end() )
|
---|
| 121 | {
|
---|
[406] | 122 | bone_id = sint16( bi->second );
|
---|
[287] | 123 | }
|
---|
| 124 | m_bone_ids[n] = bone_id;
|
---|
[419] | 125 |
|
---|
[427] | 126 | if ( m_interpolation_key.size() == 0 && node->size() > 0 )
|
---|
| 127 | m_interpolation_key = node->get_interpolation_key();
|
---|
[419] | 128 |
|
---|
[287] | 129 | }
|
---|
| 130 | m_prepared = true;
|
---|
[283] | 131 | }
|
---|
| 132 |
|
---|
[467] | 133 | void nv::skeletal_animation_entry::animate_rec( mat4* data, float time, uint32 node_id, const mat4& parent_mat ) const
|
---|
[287] | 134 | {
|
---|
| 135 | // TODO: fix transforms, which are now embedded,
|
---|
| 136 | // see note in assimp_loader.cc:load_node
|
---|
[428] | 137 | const data_channel_set* node = ( *m_node_data )[ node_id ];
|
---|
[427] | 138 | mat4 node_mat( node->get_transform() );
|
---|
[287] | 139 |
|
---|
[427] | 140 | if ( node->size() > 0 )
|
---|
[287] | 141 | {
|
---|
[427] | 142 | raw_channel_interpolator interpolator( node, m_interpolation_key );
|
---|
[419] | 143 | node_mat = interpolator.get< mat4 >( time );
|
---|
[287] | 144 | }
|
---|
| 145 |
|
---|
| 146 | mat4 global_mat = parent_mat * node_mat;
|
---|
| 147 |
|
---|
| 148 | sint16 bone_id = m_bone_ids[ node_id ];
|
---|
| 149 | if ( bone_id >= 0 )
|
---|
| 150 | {
|
---|
| 151 | data[ bone_id ] = global_mat * m_offsets[ bone_id ];
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | for ( auto child : m_children[ node_id ] )
|
---|
| 155 | {
|
---|
| 156 | animate_rec( data, time, child, global_mat );
|
---|
| 157 | }
|
---|
| 158 | }
|
---|
| 159 |
|
---|
[467] | 160 | nv::skeletal_animation_entry::~skeletal_animation_entry()
|
---|
[287] | 161 | {
|
---|
| 162 | delete[] m_offsets;
|
---|
| 163 | delete[] m_children;
|
---|
| 164 | delete[] m_bone_ids;
|
---|
| 165 | }
|
---|
| 166 |
|
---|
[467] | 167 | nv::skeletal_mesh::skeletal_mesh( context* a_context, const data_channel_set* a_mesh, const mesh_nodes_data* a_bone_data )
|
---|
[470] | 168 | : m_context( a_context ), m_bone_data( a_bone_data ), m_index_count( 0 ), m_transform( nullptr ), m_parent_id(-1)
|
---|
[287] | 169 | {
|
---|
[458] | 170 | if ( a_mesh )
|
---|
| 171 | {
|
---|
| 172 | m_va = a_context->create_vertex_array( a_mesh, nv::STATIC_DRAW );
|
---|
| 173 | m_index_count = a_mesh->get_channel_size( slot::INDEX );
|
---|
[470] | 174 | m_parent_id = a_mesh->get_parent_id();
|
---|
[458] | 175 | }
|
---|
[287] | 176 | if ( m_bone_data )
|
---|
| 177 | {
|
---|
[428] | 178 | m_transform = new mat4[ m_bone_data->size() ];
|
---|
[287] | 179 | }
|
---|
| 180 | }
|
---|
| 181 |
|
---|
[467] | 182 | void nv::skeletal_mesh::update_animation( animation_entry* a_anim, uint32 a_anim_time )
|
---|
[283] | 183 | {
|
---|
[287] | 184 | if ( m_bone_data && a_anim )
|
---|
[283] | 185 | {
|
---|
[467] | 186 | skeletal_animation_entry * anim = static_cast<skeletal_animation_entry*>( a_anim );
|
---|
[296] | 187 | anim->prepare( m_bone_data );
|
---|
[287] | 188 | anim->update_skeleton( m_transform, a_anim_time );
|
---|
[283] | 189 | }
|
---|
| 190 | }
|
---|
| 191 |
|
---|
[467] | 192 | void nv::skeletal_mesh::update( program a_program )
|
---|
[283] | 193 | {
|
---|
[287] | 194 | if ( m_bone_data )
|
---|
[428] | 195 | m_context->get_device()->set_opt_uniform_array( a_program, "nv_m_bones", m_transform, m_bone_data->size() );
|
---|
[287] | 196 | }
|
---|
| 197 |
|
---|
[467] | 198 | nv::transform nv::skeletal_mesh::get_node_transform( uint32 node_id ) const
|
---|
[287] | 199 | {
|
---|
[290] | 200 | if ( node_id == 0 ) return transform();
|
---|
[458] | 201 | if ( node_id == uint32(-1) ) return transform( m_transform[0] );
|
---|
[287] | 202 | return transform( m_transform[ node_id ] );
|
---|
| 203 | }
|
---|
| 204 |
|
---|
[467] | 205 | nv::mat4 nv::skeletal_mesh::get_node_matrix( uint32 node_id ) const
|
---|
[287] | 206 | {
|
---|
| 207 | return m_transform[ node_id ];
|
---|
| 208 | }
|
---|