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

Last change on this file since 304 was 304, checked in by epyon, 11 years ago
  • mouse wheel support for both SDL 1.2 and 2.0
  • optional unmerged MD3 import
  • selective delete mesh form mesh_creator
  • minor fixes
File size: 8.1 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
[302]17nv::keyframed_mesh::keyframed_mesh( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
[231]18        : animated_mesh()
[302]19        , m_context( a_context )
[239]20        , m_mesh_data( a_data )
21        , m_tag_map( a_tag_map )
[158]22        , m_last_frame( 0 )
23        , m_next_frame( 0 )
24        , m_interpolation( 0.0f )
25        , m_active( false )
26{
[239]27        m_index_count  = m_mesh_data->get_index_channel()->count;
[280]28        m_vertex_count = m_mesh_data->get_channel<vertex_t>()->count;
[294]29        m_vchannel     = m_mesh_data->get_channel<vertex_pnt>();
30        m_vsize        = sizeof( vertex_pnt );
31        m_has_tangent  = true;
32        if ( m_vchannel == nullptr )
33        {
34                m_vchannel     = m_mesh_data->get_channel<vertex_pn>();
35                m_has_tangent  = false;
36                m_vsize        = sizeof( vertex_pn );
37        }
38        m_frame_count  = m_vchannel->count / m_vertex_count;
[302]39        m_pbuffer      = buffer();
[158]40}
41
[204]42size_t keyframed_mesh::get_max_frames() const
[158]43{
[239]44        return m_frame_count;
[158]45}
46
[287]47transform keyframed_mesh::get_node_transform( uint32 node_id ) const
[158]48{
[304]49        if ( !m_tag_map ) return transform();
[287]50        NV_ASSERT( node_id < m_tag_map->get_count(), "TAGMAP FAIL" );
51        const key_data* data = m_tag_map->get_node( node_id )->data;
[285]52        NV_ASSERT( data, "TAG FAIL" );
53        transform last = data->get_raw_transform( m_last_frame );
54        transform next = data->get_raw_transform( m_next_frame );
55        return interpolate( last, next, m_interpolation  );
[158]56}
57
[287]58mat4 keyframed_mesh::get_node_matrix( uint32 node_id ) const
59{
60        return get_node_transform( node_id ).extract();
61}
62
[223]63void nv::keyframed_mesh::set_frame( uint32 frame )
64{
65        m_last_frame    = frame;
66        m_next_frame    = frame;
67        m_active        = false;
68        m_interpolation = 0.0f;
69}
70
[288]71void nv::keyframed_mesh::update_animation( animation_entry* anim, uint32 a_anim_time )
[158]72{
73        if ( m_active )
74        {
[288]75                float tick_time = ( (float)a_anim_time * 0.001f ) * anim->get_frame_rate();
76                float duration  = anim->is_looping() ? anim->get_duration() + 1.0f : anim->get_duration();
77                if ( tick_time >= duration )
[158]78                {
[288]79                        if ( anim->is_looping() )
[158]80                        {
[288]81                                tick_time = fmodf( tick_time, duration );
[158]82                        }
83                        else
84                        {
85                                m_active     = false;
[288]86                                m_last_frame = (uint32)anim->get_end();
87                                m_next_frame = m_last_frame;
88                                m_interpolation = 0.0f;
89                                return;
[158]90                        }
91                }
[288]92                m_last_frame    = (uint32)( glm::floor( tick_time ) + anim->get_start() );
[283]93                m_next_frame    = m_last_frame + 1;
[288]94                if ( m_next_frame > (uint32)anim->get_end() ) m_next_frame = (uint32)anim->get_start();
95                m_interpolation = tick_time - glm::floor( tick_time );
[158]96        }
97}
98
[283]99
[303]100void nv::keyframed_mesh::update( program a_program )
[158]101{
[303]102        m_context->get_device()->set_opt_uniform( a_program, "nv_interpolate", m_interpolation );
[223]103}
104
105nv::keyframed_mesh::~keyframed_mesh()
106{
[302]107        m_context->get_device()->release( m_va );
[223]108}
109
[230]110void nv::keyframed_mesh::run_animation( animation_entry* a_anim )
111{
[252]112        if ( a_anim )
113        {
[288]114                m_active        = true;
115                m_last_frame    = 0;
116                m_next_frame    = 0;
117                m_interpolation = 0.0f;
[252]118        }
119        else
120        {
121                m_active = false;
122        }
[230]123}
124
[299]125nv::keyframed_mesh_gpu::keyframed_mesh_gpu( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
[302]126        : keyframed_mesh( a_context, a_data, a_tag_map )
[294]127        , m_loc_next_position( -1 )
128        , m_loc_next_normal( -1 )
129        , m_loc_next_tangent( -1 )
[223]130        , m_gpu_last_frame( 0xFFFFFFFF )
131        , m_gpu_next_frame( 0xFFFFFFFF )
132{
[302]133        m_va      = a_context->get_device()->create_vertex_array( a_data, STATIC_DRAW );
134        m_pbuffer = a_context->get_device()->find_buffer( m_va, slot::POSITION );
[239]135}
[223]136
137
[230]138void nv::keyframed_mesh_gpu::update( uint32 ms )
[223]139{
[296]140        if ( m_loc_next_position == -1 ) return;
[283]141        animated_mesh::update( ms );
[302]142        device* dev = m_context->get_device();
[158]143        if ( m_gpu_last_frame != m_last_frame )
144        {
[302]145                uint32 base_offset = m_last_frame * m_vertex_count * m_vsize;
146                dev->update_attribute_offset( m_va, slot::POSITION, base_offset );
147                dev->update_attribute_offset( m_va, slot::NORMAL,   base_offset + sizeof( vec3 ) );
[294]148                if ( m_has_tangent && m_loc_next_tangent != -1 )
149                {
[302]150                        dev->update_attribute_offset( m_va, slot::TANGENT, base_offset + 2*sizeof( vec3 ) );
[294]151                }
[158]152                m_gpu_last_frame = m_last_frame;
153        }
[296]154        if ( m_loc_next_position != -1 && m_gpu_next_frame != m_next_frame )
[158]155        {
[302]156                uint32 base_offset = m_next_frame * m_vertex_count * m_vsize;
157                dev->update_attribute_offset( m_va, (slot)m_loc_next_position, base_offset );
158                dev->update_attribute_offset( m_va, (slot)m_loc_next_normal, base_offset + sizeof( vec3 ) );
159                if ( m_has_tangent && m_loc_next_tangent != -1 )
160                {
161                        dev->update_attribute_offset( m_va, (slot)m_loc_next_tangent, base_offset + 2*sizeof( vec3 ) );
162                }
[158]163                m_gpu_next_frame = m_next_frame;
164        }
165}
166
[303]167void nv::keyframed_mesh_gpu::update( program a_program )
[296]168{
169        if ( m_loc_next_position == -1 )
170        {
[303]171                device* dev = m_context->get_device();
172                m_loc_next_position = dev->get_attribute_location( a_program, "nv_next_position" );
173                m_loc_next_normal   = dev->get_attribute_location( a_program, "nv_next_normal" );
[296]174                if ( m_has_tangent )
[303]175                        m_loc_next_tangent  = dev->get_attribute_location( a_program, "nv_next_tangent" );
[296]176
[302]177                dev->add_vertex_buffer( m_va, (slot)m_loc_next_position, m_pbuffer, FLOAT, 3, 0, m_vsize, false );
178                dev->add_vertex_buffer( m_va, (slot)m_loc_next_normal,   m_pbuffer, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
[296]179                if ( m_has_tangent )
[302]180                        dev->add_vertex_buffer( m_va, (slot)m_loc_next_tangent, m_pbuffer, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
[296]181        }
182        keyframed_mesh::update( a_program );
183}
184
[299]185nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
[302]186        : keyframed_mesh( a_context, a_data, a_tag_map )
[158]187{
[302]188        m_va      = m_context->get_device()->create_vertex_array();
189        m_pbuffer = m_context->get_device()->create_buffer( VERTEX_BUFFER, STATIC_DRAW, m_vertex_count * m_vsize, (void*)m_vchannel->data );
190        m_context->get_device()->add_vertex_buffers( m_va, m_pbuffer, m_vchannel );
[223]191
[302]192        buffer  vb = m_context->get_device()->create_buffer( VERTEX_BUFFER, STATIC_DRAW, m_vertex_count * sizeof( vec2 ), (void*)m_mesh_data->get_channel<vertex_t>()->data );
193        m_context->get_device()->add_vertex_buffers( m_va, vb, m_mesh_data->get_channel<vertex_t>() );
[223]194
[302]195        buffer  ib = m_context->get_device()->create_buffer( INDEX_BUFFER, STATIC_DRAW, m_mesh_data->get_index_channel()->size(), (void*)m_mesh_data->get_index_channel()->data );
[223]196
[302]197        m_context->get_device()->set_index_buffer( m_va, ib, m_mesh_data->get_index_channel()->desc.slots[0].etype, true );
198
[294]199        m_data = new uint8[ m_vertex_count * m_vsize ];
[158]200}
[223]201
202void nv::keyframed_mesh_cpu::update( uint32 ms )
203{
[283]204        animated_mesh::update( ms );
[223]205
[294]206        // TODO: this could be done generic for any data
207        if ( m_has_tangent )
[223]208        {
[294]209                const vertex_pnt* data = m_mesh_data->get_channel_data<vertex_pnt>();
210                const vertex_pnt* prev = data + m_vertex_count * m_last_frame;
211                const vertex_pnt* next = data + m_vertex_count * m_next_frame;
212                      vertex_pnt* vtx  = (vertex_pnt*)m_data;
213                for ( size_t i = 0; i < m_vertex_count; ++i )
214                {
215                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
216                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
217                        vtx[i].tangent  = glm::mix( prev[i].tangent,  next[i].tangent,   m_interpolation );
218                }
[223]219        }
[294]220        else
221        {
222                const vertex_pn* data = m_mesh_data->get_channel_data<vertex_pn>();
223                const vertex_pn* prev = data + m_vertex_count * m_last_frame;
224                const vertex_pn* next = data + m_vertex_count * m_next_frame;
225                      vertex_pn* vtx  = (vertex_pn*)m_data;
[223]226
[294]227                for ( size_t i = 0; i < m_vertex_count; ++i )
228                {
229                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
230                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
231                }
232        }
233
[302]234        m_context->update( m_pbuffer, m_data, 0, m_vertex_count * m_vsize );
[223]235}
[294]236
237nv::keyframed_mesh_cpu::~keyframed_mesh_cpu()
238{
239        delete[] m_data;
240}
Note: See TracBrowser for help on using the repository browser.