// Copyright (C) 2011 Kornel Kisielewicz // This file is part of NV Libraries. // For conditions of distribution and use, see copyright notice in nv.hh #include "nv/gfx/keyframed_mesh.hh" #include #include #include "nv/interface/context.hh" #include "nv/interface/device.hh" #include "nv/logging.hh" using namespace nv; keyframed_mesh::keyframed_mesh( context* a_context, mesh_data* a_data ) : animated_mesh( a_context ) , m_data( a_data ) , m_start_frame( false ) , m_stop_frame( false ) , m_last_frame( 0 ) , m_next_frame( 0 ) , m_time( 0 ) , m_fps( 0 ) , m_interpolation( 0.0f ) , m_looping( false ) , m_active( false ) { m_va = m_context->get_device()->create_vertex_array(); } size_t keyframed_mesh::get_max_frames() const { return m_data->get_frame_count(); } transform keyframed_mesh::get_tag( const std::string& tag ) const { const std::vector< transform >& transforms = m_data->get_tag_map().at( tag ); return interpolate( transforms[ m_last_frame ], transforms[ m_next_frame ], m_interpolation ); } void keyframed_mesh::setup_animation( uint32 start, uint32 count, uint32 fps, bool loop ) { m_start_frame = start; m_stop_frame = start+count-1; m_looping = loop; m_fps = fps; m_active = count > 1; m_time = 0; m_last_frame = start; m_next_frame = (count > 1 ? start + 1 : start ); m_interpolation = 0.0f; } void nv::keyframed_mesh::set_frame( uint32 frame ) { m_last_frame = frame; m_next_frame = frame; m_active = false; m_interpolation = 0.0f; } void keyframed_mesh::update( uint32 ms ) { if ( m_active ) { m_time += ms; uint32 f_diff = (m_stop_frame - m_start_frame); float f_time = 1000 / (float)m_fps; float f_max = ( m_looping ? ( f_diff + 1 ) : f_diff ) * f_time; float f_pos = m_time / f_time; m_last_frame = (uint32)glm::floor( f_pos ) + m_start_frame; m_next_frame = m_last_frame + 1; if ( m_next_frame > m_stop_frame ) { m_next_frame = m_start_frame; } if ( m_time >= f_max ) { if ( m_looping ) { uint32 left = m_time - static_cast< uint32 >( f_max ); m_time = 0; update( left ); } else { m_active = false; m_last_frame = m_stop_frame; m_next_frame = m_stop_frame; } } m_interpolation = f_pos - glm::floor( f_pos ); } } void nv::keyframed_mesh::update( program* a_program ) { a_program->set_opt_uniform( "nv_interpolate", m_interpolation ); } nv::keyframed_mesh::~keyframed_mesh() { delete m_va; } void nv::keyframed_mesh::run_animation( animation_entry* a_anim ) { keyframed_animation_entry * anim = down_cast(a_anim); setup_animation( anim->m_start, anim->m_frames, anim->m_fps, anim->m_looping ); } keyframed_mesh_gpu::keyframed_mesh_gpu( context* a_context, mesh_data* a_data, program* a_program ) : keyframed_mesh( a_context, a_data ) , m_loc_next_position( 0 ) , m_loc_next_normal( 0 ) , m_gpu_last_frame( 0xFFFFFFFF ) , m_gpu_next_frame( 0xFFFFFFFF ) { nv::vertex_buffer* vb; m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location(); m_loc_next_normal = a_program->get_attribute( "nv_next_normal" )->get_location(); vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ) * m_data->get_frame_count(), (void*)m_data->get_positions().data() ); m_va->add_vertex_buffer( m_loc_next_position, vb, nv::FLOAT, 3, 0, 0, false ); m_va->add_vertex_buffer( nv::POSITION, vb, nv::FLOAT, 3 ); vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ) * m_data->get_frame_count(), (void*)m_data->get_normals().data() ); m_va->add_vertex_buffer( m_loc_next_normal, vb, nv::FLOAT, 3, 0, 0, false ); m_va->add_vertex_buffer( nv::NORMAL, vb, nv::FLOAT, 3 ); vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec2 ), (void*)m_data->get_texcoords().data() ); m_va->add_vertex_buffer( nv::slot::TEXCOORD, vb, nv::FLOAT, 2 ); nv::index_buffer* ib = m_context->get_device()->create_index_buffer( nv::STATIC_DRAW, m_data->get_index_count() * sizeof( nv::uint32 ), (void*)m_data->get_indices().data() ); m_va->set_index_buffer( ib, nv::UINT, true ); } void nv::keyframed_mesh_gpu::update( uint32 ms ) { keyframed_mesh::update( ms ); size_t vtx_count = m_data->get_vertex_count(); if ( m_gpu_last_frame != m_last_frame ) { m_va->update_vertex_buffer( slot::POSITION, m_last_frame * vtx_count * sizeof( nv::vec3 ) ); m_va->update_vertex_buffer( slot::NORMAL, m_last_frame * vtx_count * sizeof( nv::vec3 ) ); m_gpu_last_frame = m_last_frame; } if ( m_gpu_next_frame != m_next_frame ) { m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * vtx_count * sizeof( nv::vec3 ) ); m_va->update_vertex_buffer( m_loc_next_normal, m_next_frame * vtx_count * sizeof( nv::vec3 ) ); m_gpu_next_frame = m_next_frame; } } nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, mesh_data* a_data ) : keyframed_mesh( a_context, a_data ) { m_vb_position = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ), (void*)m_data->get_position_frame(0) ); m_va->add_vertex_buffer( nv::slot::POSITION, m_vb_position, nv::FLOAT, 3 ); m_vb_normal = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec3 ), (void*)m_data->get_normal_frame(0) ); m_va->add_vertex_buffer( nv::slot::NORMAL, m_vb_normal, nv::FLOAT, 3 ); nv::vertex_buffer* vb; vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_data->get_vertex_count() * sizeof( nv::vec2 ), (void*)m_data->get_texcoords().data() ); m_va->add_vertex_buffer( nv::slot::TEXCOORD, vb, nv::FLOAT, 2 ); nv::index_buffer* ib = m_context->get_device()->create_index_buffer( nv::STATIC_DRAW, m_data->get_index_count() * sizeof( nv::uint32 ), (void*)m_data->get_indices().data() ); m_va->set_index_buffer( ib, nv::UINT, true ); m_position.resize( m_data->get_vertex_count() ); m_normal.resize( m_data->get_vertex_count() ); } void nv::keyframed_mesh_cpu::update( uint32 ms ) { keyframed_mesh::update( ms ); size_t vtx_count = m_data->get_vertex_count(); const vec3* prev_position = m_data->get_position_frame( m_last_frame ); const vec3* next_position = m_data->get_position_frame( m_next_frame ); const vec3* prev_normal = m_data->get_normal_frame( m_last_frame ); const vec3* next_normal = m_data->get_normal_frame( m_next_frame ); for ( size_t i = 0; i < vtx_count; ++i ) { m_position[i] = glm::mix( prev_position[i], next_position[i], m_interpolation ); m_normal[i] = glm::mix( prev_normal[i], next_normal[i], m_interpolation ); } m_vb_position->bind(); m_vb_position->update( m_position.data(), 0, vtx_count * sizeof( nv::vec3 ) ); m_vb_position->unbind(); m_vb_normal->bind(); m_vb_normal->update( m_normal.data(), 0, vtx_count * sizeof( nv::vec3 ) ); m_vb_normal->unbind(); }