source: trunk/src/gfx/keyframed_mesh.cc @ 299

Last change on this file since 299 was 299, checked in by epyon, 11 years ago
  • all bind and update function for graphics objects are done via context (will simplify directx device, and allow for handles instead of objects)
File size: 7.7 KB
RevLine 
[158]1// Copyright (C) 2011 Kornel Kisielewicz
2// This file is part of NV Libraries.
3// For conditions of distribution and use, see copyright notice in nv.hh
4
5#include "nv/gfx/keyframed_mesh.hh"
6
7#include <glm/gtc/matrix_access.hpp>
8#include <glm/gtx/matrix_interpolation.hpp>
9#include "nv/interface/context.hh"
10#include "nv/interface/device.hh"
11
12
13#include "nv/logging.hh"
14
15using namespace nv;
16
[299]17nv::keyframed_mesh::keyframed_mesh( const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
[231]18        : animated_mesh()
[239]19        , m_mesh_data( a_data )
20        , m_tag_map( a_tag_map )
[158]21        , m_last_frame( 0 )
22        , m_next_frame( 0 )
23        , m_interpolation( 0.0f )
24        , m_active( false )
25{
[239]26        m_index_count  = m_mesh_data->get_index_channel()->count;
[280]27        m_vertex_count = m_mesh_data->get_channel<vertex_t>()->count;
[294]28        m_vchannel     = m_mesh_data->get_channel<vertex_pnt>();
29        m_vsize        = sizeof( vertex_pnt );
30        m_has_tangent  = true;
31        if ( m_vchannel == nullptr )
32        {
33                m_vchannel     = m_mesh_data->get_channel<vertex_pn>();
34                m_has_tangent  = false;
35                m_vsize        = sizeof( vertex_pn );
36        }
37        m_frame_count  = m_vchannel->count / m_vertex_count;
[158]38}
39
[204]40size_t keyframed_mesh::get_max_frames() const
[158]41{
[239]42        return m_frame_count;
[158]43}
44
[287]45transform keyframed_mesh::get_node_transform( uint32 node_id ) const
[158]46{
[239]47        NV_ASSERT( m_tag_map, "TAGMAP FAIL" );
[287]48        NV_ASSERT( node_id < m_tag_map->get_count(), "TAGMAP FAIL" );
49        const key_data* data = m_tag_map->get_node( node_id )->data;
[285]50        NV_ASSERT( data, "TAG FAIL" );
51        transform last = data->get_raw_transform( m_last_frame );
52        transform next = data->get_raw_transform( m_next_frame );
53        return interpolate( last, next, m_interpolation  );
[158]54}
55
[287]56mat4 keyframed_mesh::get_node_matrix( uint32 node_id ) const
57{
58        return get_node_transform( node_id ).extract();
59}
60
[223]61void nv::keyframed_mesh::set_frame( uint32 frame )
62{
63        m_last_frame    = frame;
64        m_next_frame    = frame;
65        m_active        = false;
66        m_interpolation = 0.0f;
67}
68
[288]69void nv::keyframed_mesh::update_animation( animation_entry* anim, uint32 a_anim_time )
[158]70{
71        if ( m_active )
72        {
[288]73                float tick_time = ( (float)a_anim_time * 0.001f ) * anim->get_frame_rate();
74                float duration  = anim->is_looping() ? anim->get_duration() + 1.0f : anim->get_duration();
75                if ( tick_time >= duration )
[158]76                {
[288]77                        if ( anim->is_looping() )
[158]78                        {
[288]79                                tick_time = fmodf( tick_time, duration );
[158]80                        }
81                        else
82                        {
83                                m_active     = false;
[288]84                                m_last_frame = (uint32)anim->get_end();
85                                m_next_frame = m_last_frame;
86                                m_interpolation = 0.0f;
87                                return;
[158]88                        }
89                }
[288]90                m_last_frame    = (uint32)( glm::floor( tick_time ) + anim->get_start() );
[283]91                m_next_frame    = m_last_frame + 1;
[288]92                if ( m_next_frame > (uint32)anim->get_end() ) m_next_frame = (uint32)anim->get_start();
93                m_interpolation = tick_time - glm::floor( tick_time );
[158]94        }
95}
96
[283]97
[296]98void nv::keyframed_mesh::update( program* a_program )
[158]99{
[230]100        a_program->set_opt_uniform( "nv_interpolate", m_interpolation );
[223]101}
102
103nv::keyframed_mesh::~keyframed_mesh()
104{
105        delete m_va;
106}
107
[230]108void nv::keyframed_mesh::run_animation( animation_entry* a_anim )
109{
[252]110        if ( a_anim )
111        {
[288]112                m_active        = true;
113                m_last_frame    = 0;
114                m_next_frame    = 0;
115                m_interpolation = 0.0f;
[252]116        }
117        else
118        {
119                m_active = false;
120        }
[230]121}
122
[299]123nv::keyframed_mesh_gpu::keyframed_mesh_gpu( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
124        : keyframed_mesh( a_data, a_tag_map )
[294]125        , m_loc_next_position( -1 )
126        , m_loc_next_normal( -1 )
127        , m_loc_next_tangent( -1 )
[223]128        , m_gpu_last_frame( 0xFFFFFFFF )
129        , m_gpu_next_frame( 0xFFFFFFFF )
130{
[299]131        m_va = a_context->get_device()->create_vertex_array( a_data, STATIC_DRAW );
[239]132}
[223]133
134
[230]135void nv::keyframed_mesh_gpu::update( uint32 ms )
[223]136{
[296]137        if ( m_loc_next_position == -1 ) return;
[283]138        animated_mesh::update( ms );
[230]139
[158]140        if ( m_gpu_last_frame != m_last_frame )
141        {
[294]142                m_va->update_vertex_buffer( slot::POSITION, m_last_frame * m_vertex_count * m_vsize );
143                m_va->update_vertex_buffer( slot::NORMAL,   m_last_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
144                if ( m_has_tangent && m_loc_next_tangent != -1 )
145                {
146                        m_va->update_vertex_buffer( slot::TANGENT,   m_last_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
147                }
[158]148                m_gpu_last_frame = m_last_frame;
149        }
[296]150        if ( m_loc_next_position != -1 && m_gpu_next_frame != m_next_frame )
[158]151        {
[294]152                m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * m_vertex_count * m_vsize );
153                m_va->update_vertex_buffer( m_loc_next_normal,   m_next_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
154                m_va->update_vertex_buffer( m_loc_next_tangent,   m_next_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
[158]155                m_gpu_next_frame = m_next_frame;
156        }
157}
158
[296]159void nv::keyframed_mesh_gpu::update( program* a_program )
160{
161        if ( m_loc_next_position == -1 )
162        {
163                m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location();
164                m_loc_next_normal   = a_program->get_attribute( "nv_next_normal" )->get_location();
165                if ( m_has_tangent )
166                        m_loc_next_tangent  = a_program->get_attribute( "nv_next_tangent" )->get_location();
167
168                vertex_buffer* vb = m_va->find_buffer( slot::POSITION );
169                m_va->add_vertex_buffer( m_loc_next_position, vb, FLOAT, 3, 0, m_vsize, false );
170                m_va->add_vertex_buffer( m_loc_next_normal,   vb, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
171                if ( m_has_tangent )
172                        m_va->add_vertex_buffer( m_loc_next_tangent, vb, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
173        }
174        keyframed_mesh::update( a_program );
175}
176
[299]177nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
178        : keyframed_mesh( a_data, a_tag_map )
179        , m_context( a_context )
[158]180{
[299]181        m_va = m_context->get_device()->create_vertex_array();
182        m_vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * m_vsize, (void*)m_vchannel->data );
[294]183        m_va->add_vertex_buffers( m_vb, m_vchannel );
[223]184
[299]185        nv::vertex_buffer* vb = m_context->get_device()->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * sizeof( nv::vec2 ), (void*)m_mesh_data->get_channel<vertex_t>()->data );
[280]186        m_va->add_vertex_buffers( vb, m_mesh_data->get_channel<vertex_t>() );
[223]187
[299]188        nv::index_buffer* ib = m_context->get_device()->create_index_buffer( nv::STATIC_DRAW, m_mesh_data->get_index_channel()->size(), (void*)m_mesh_data->get_index_channel()->data );
[280]189        m_va->set_index_buffer( ib, m_mesh_data->get_index_channel()->desc.slots[0].etype, true );
[223]190
[294]191        m_data = new uint8[ m_vertex_count * m_vsize ];
[158]192}
[223]193
194void nv::keyframed_mesh_cpu::update( uint32 ms )
195{
[283]196        animated_mesh::update( ms );
[223]197
[294]198        // TODO: this could be done generic for any data
199        if ( m_has_tangent )
[223]200        {
[294]201                const vertex_pnt* data = m_mesh_data->get_channel_data<vertex_pnt>();
202                const vertex_pnt* prev = data + m_vertex_count * m_last_frame;
203                const vertex_pnt* next = data + m_vertex_count * m_next_frame;
204                      vertex_pnt* vtx  = (vertex_pnt*)m_data;
205                for ( size_t i = 0; i < m_vertex_count; ++i )
206                {
207                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
208                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
209                        vtx[i].tangent  = glm::mix( prev[i].tangent,  next[i].tangent,   m_interpolation );
210                }
[223]211        }
[294]212        else
213        {
214                const vertex_pn* data = m_mesh_data->get_channel_data<vertex_pn>();
215                const vertex_pn* prev = data + m_vertex_count * m_last_frame;
216                const vertex_pn* next = data + m_vertex_count * m_next_frame;
217                      vertex_pn* vtx  = (vertex_pn*)m_data;
[223]218
[294]219                for ( size_t i = 0; i < m_vertex_count; ++i )
220                {
221                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
222                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
223                }
224        }
225
[299]226        m_context->update( m_vb, m_data, 0, m_vertex_count * m_vsize );
[223]227}
[294]228
229nv::keyframed_mesh_cpu::~keyframed_mesh_cpu()
230{
231        delete[] m_data;
232}
Note: See TracBrowser for help on using the repository browser.