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

Last change on this file since 294 was 294, checked in by epyon, 11 years ago
  • mesh_creator -- very robust tangent generation mechanism
  • keyframed_mesh - support for meshes with tangent data
  • minor cleanups
File size: 7.4 KB
Line 
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
17nv::keyframed_mesh::keyframed_mesh( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
18        : animated_mesh()
19        , m_mesh_data( a_data )
20        , m_tag_map( a_tag_map )
21        , m_last_frame( 0 )
22        , m_next_frame( 0 )
23        , m_interpolation( 0.0f )
24        , m_active( false )
25{
26        m_va = a_device->create_vertex_array();
27
28        m_index_count  = m_mesh_data->get_index_channel()->count;
29        m_vertex_count = m_mesh_data->get_channel<vertex_t>()->count;
30        m_vchannel     = m_mesh_data->get_channel<vertex_pnt>();
31        m_vsize        = sizeof( vertex_pnt );
32        m_has_tangent  = true;
33        if ( m_vchannel == nullptr )
34        {
35                m_vchannel     = m_mesh_data->get_channel<vertex_pn>();
36                m_has_tangent  = false;
37                m_vsize        = sizeof( vertex_pn );
38        }
39        m_frame_count  = m_vchannel->count / m_vertex_count;
40}
41
42size_t keyframed_mesh::get_max_frames() const
43{
44        return m_frame_count;
45}
46
47transform keyframed_mesh::get_node_transform( uint32 node_id ) const
48{
49        NV_ASSERT( m_tag_map, "TAGMAP FAIL" );
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;
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  );
56}
57
58mat4 keyframed_mesh::get_node_matrix( uint32 node_id ) const
59{
60        return get_node_transform( node_id ).extract();
61}
62
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
71void nv::keyframed_mesh::update_animation( animation_entry* anim, uint32 a_anim_time )
72{
73        if ( m_active )
74        {
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 )
78                {
79                        if ( anim->is_looping() )
80                        {
81                                tick_time = fmodf( tick_time, duration );
82                        }
83                        else
84                        {
85                                m_active     = false;
86                                m_last_frame = (uint32)anim->get_end();
87                                m_next_frame = m_last_frame;
88                                m_interpolation = 0.0f;
89                                return;
90                        }
91                }
92                m_last_frame    = (uint32)( glm::floor( tick_time ) + anim->get_start() );
93                m_next_frame    = m_last_frame + 1;
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 );
96        }
97}
98
99
100void nv::keyframed_mesh::update( program* a_program ) const
101{
102        a_program->set_opt_uniform( "nv_interpolate", m_interpolation );
103}
104
105nv::keyframed_mesh::~keyframed_mesh()
106{
107        delete m_va;
108}
109
110void nv::keyframed_mesh::run_animation( animation_entry* a_anim )
111{
112        if ( a_anim )
113        {
114                m_active        = true;
115                m_last_frame    = 0;
116                m_next_frame    = 0;
117                m_interpolation = 0.0f;
118        }
119        else
120        {
121                m_active = false;
122        }
123}
124
125nv::keyframed_mesh_gpu::keyframed_mesh_gpu( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map, program* a_program )
126        : keyframed_mesh( a_device, a_data, a_tag_map )
127        , m_loc_next_position( -1 )
128        , m_loc_next_normal( -1 )
129        , m_loc_next_tangent( -1 )
130        , m_gpu_last_frame( 0xFFFFFFFF )
131        , m_gpu_next_frame( 0xFFFFFFFF )
132{
133        m_loc_next_position = a_program->get_attribute( "nv_next_position" )->get_location();
134        m_loc_next_normal   = a_program->get_attribute( "nv_next_normal" )->get_location();
135        m_loc_next_tangent  = a_program->try_get_attribute_location( "nv_next_tangent" );
136        m_va = a_device->create_vertex_array( a_data, STATIC_DRAW );
137        vertex_buffer* vb = m_va->find_buffer( slot::POSITION );
138        m_va->add_vertex_buffer( m_loc_next_position, vb, FLOAT, 3, 0, m_vsize, false );
139        m_va->add_vertex_buffer( m_loc_next_normal,   vb, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
140        if ( m_has_tangent )
141                m_va->add_vertex_buffer( m_loc_next_tangent, vb, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
142}
143
144
145void nv::keyframed_mesh_gpu::update( uint32 ms )
146{
147        animated_mesh::update( ms );
148
149        if ( m_gpu_last_frame != m_last_frame )
150        {
151                m_va->update_vertex_buffer( slot::POSITION, m_last_frame * m_vertex_count * m_vsize );
152                m_va->update_vertex_buffer( slot::NORMAL,   m_last_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
153                if ( m_has_tangent && m_loc_next_tangent != -1 )
154                {
155                        m_va->update_vertex_buffer( slot::TANGENT,   m_last_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
156                }
157                m_gpu_last_frame = m_last_frame;
158        }
159        if ( m_gpu_next_frame != m_next_frame )
160        {
161                m_va->update_vertex_buffer( m_loc_next_position, m_next_frame * m_vertex_count * m_vsize );
162                m_va->update_vertex_buffer( m_loc_next_normal,   m_next_frame * m_vertex_count * m_vsize + sizeof( vec3 ) );
163                m_va->update_vertex_buffer( m_loc_next_tangent,   m_next_frame * m_vertex_count * m_vsize + 2*sizeof( vec3 ) );
164                m_gpu_next_frame = m_next_frame;
165        }
166}
167
168nv::keyframed_mesh_cpu::keyframed_mesh_cpu( device* a_device, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
169        : keyframed_mesh( a_device, a_data, a_tag_map )
170{
171        m_vb = a_device->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * m_vsize, (void*)m_vchannel->data );
172        m_va->add_vertex_buffers( m_vb, m_vchannel );
173
174        nv::vertex_buffer* vb = a_device->create_vertex_buffer( nv::STATIC_DRAW, m_vertex_count * sizeof( nv::vec2 ), (void*)m_mesh_data->get_channel<vertex_t>()->data );
175        m_va->add_vertex_buffers( vb, m_mesh_data->get_channel<vertex_t>() );
176
177        nv::index_buffer* ib = a_device->create_index_buffer( nv::STATIC_DRAW, m_mesh_data->get_index_channel()->size(), (void*)m_mesh_data->get_index_channel()->data );
178        m_va->set_index_buffer( ib, m_mesh_data->get_index_channel()->desc.slots[0].etype, true );
179
180        m_data = new uint8[ m_vertex_count * m_vsize ];
181}
182
183void nv::keyframed_mesh_cpu::update( uint32 ms )
184{
185        animated_mesh::update( ms );
186
187        // TODO: this could be done generic for any data
188        if ( m_has_tangent )
189        {
190                const vertex_pnt* data = m_mesh_data->get_channel_data<vertex_pnt>();
191                const vertex_pnt* prev = data + m_vertex_count * m_last_frame;
192                const vertex_pnt* next = data + m_vertex_count * m_next_frame;
193                      vertex_pnt* vtx  = (vertex_pnt*)m_data;
194                for ( size_t i = 0; i < m_vertex_count; ++i )
195                {
196                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
197                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
198                        vtx[i].tangent  = glm::mix( prev[i].tangent,  next[i].tangent,   m_interpolation );
199                }
200        }
201        else
202        {
203                const vertex_pn* data = m_mesh_data->get_channel_data<vertex_pn>();
204                const vertex_pn* prev = data + m_vertex_count * m_last_frame;
205                const vertex_pn* next = data + m_vertex_count * m_next_frame;
206                      vertex_pn* vtx  = (vertex_pn*)m_data;
207
208                for ( size_t i = 0; i < m_vertex_count; ++i )
209                {
210                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
211                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
212                }
213        }
214
215        m_vb->bind();
216        m_vb->update( m_data, 0, m_vertex_count * m_vsize );
217        m_vb->unbind();
218}
219
220nv::keyframed_mesh_cpu::~keyframed_mesh_cpu()
221{
222        delete[] m_data;
223}
Note: See TracBrowser for help on using the repository browser.