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

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