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

Last change on this file since 410 was 410, checked in by epyon, 10 years ago
  • merge of vertex_descriptor and key_descriptor concepts - unified raw data description via data_descriptor
  • minor bugfixes
File size: 8.3 KB
Line 
1// Copyright (C) 2011-2015 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7#include "nv/gfx/keyframed_mesh.hh"
8
9#include "nv/interface/context.hh"
10#include "nv/interface/device.hh"
11#include "nv/core/logging.hh"
12
13using namespace nv;
14
15nv::keyframed_mesh::keyframed_mesh( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
16        : animated_mesh()
17        , m_context( a_context )
18        , m_mesh_data( a_data )
19        , m_tag_map( a_tag_map )
20        , m_last_frame( 0 )
21        , m_next_frame( 0 )
22        , m_interpolation( 0.0f )
23        , m_active( false )
24{
25        m_index_count  = m_mesh_data->get_index_channel()->count;
26        m_vertex_count = m_mesh_data->get_channel<vertex_t>()->count;
27        m_vchannel     = m_mesh_data->get_channel<vertex_pnt>();
28        m_vsize        = sizeof( vertex_pnt );
29        m_has_tangent  = true;
30        if ( m_vchannel == nullptr )
31        {
32                m_vchannel     = m_mesh_data->get_channel<vertex_pn>();
33                m_has_tangent  = false;
34                m_vsize        = sizeof( vertex_pn );
35        }
36        m_frame_count  = m_vchannel->count / m_vertex_count;
37        m_pbuffer      = buffer();
38}
39
40nv::size_t keyframed_mesh::get_max_frames() const
41{
42        return m_frame_count;
43}
44
45transform keyframed_mesh::get_node_transform( uint32 node_id ) const
46{
47        if ( !m_tag_map ) return transform();
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;
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  );
54}
55
56mat4 keyframed_mesh::get_node_matrix( uint32 node_id ) const
57{
58        return get_node_transform( node_id ).extract();
59}
60
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
69void nv::keyframed_mesh::update_animation( animation_entry* anim, uint32 a_anim_time )
70{
71        if ( m_active )
72        {
73                float tick_time = ( static_cast<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 )
76                {
77                        if ( anim->is_looping() )
78                        {
79                                tick_time = fmodf( tick_time, duration );
80                        }
81                        else
82                        {
83                                m_active     = false;
84                                m_last_frame = static_cast<uint32>( anim->get_end() );
85                                m_next_frame = m_last_frame;
86                                m_interpolation = 0.0f;
87                                return;
88                        }
89                }
90                m_last_frame    = static_cast<uint32>( glm::floor( tick_time ) + anim->get_start() );
91                m_next_frame    = m_last_frame + 1;
92                if ( m_next_frame > static_cast<uint32>( anim->get_end() ) ) m_next_frame = static_cast<uint32>( anim->get_start() );
93                m_interpolation = tick_time - glm::floor( tick_time );
94        }
95}
96
97
98void nv::keyframed_mesh::update( program a_program )
99{
100        m_context->get_device()->set_opt_uniform( a_program, "nv_interpolate", m_interpolation );
101}
102
103nv::keyframed_mesh::~keyframed_mesh()
104{
105        m_context->release( m_va );
106}
107
108void nv::keyframed_mesh::run_animation( animation_entry* a_anim )
109{
110        if ( a_anim )
111        {
112                m_active        = true;
113                m_last_frame    = 0;
114                m_next_frame    = 0;
115                m_interpolation = 0.0f;
116        }
117        else
118        {
119                m_active = false;
120        }
121}
122
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_context, a_data, a_tag_map )
125        , m_loc_next_position( -1 )
126        , m_loc_next_normal( -1 )
127        , m_loc_next_tangent( -1 )
128        , m_gpu_last_frame( 0xFFFFFFFF )
129        , m_gpu_next_frame( 0xFFFFFFFF )
130{
131        m_va      = a_context->create_vertex_array( a_data, STATIC_DRAW );
132        m_pbuffer = a_context->find_buffer( m_va, slot::POSITION );
133}
134
135
136void nv::keyframed_mesh_gpu::update_animation( animation_entry* anim, uint32 a_anim_time )
137{
138        keyframed_mesh::update_animation( anim, a_anim_time );
139        if ( m_loc_next_position == -1 ) return;
140        if ( m_gpu_last_frame != m_last_frame )
141        {
142                uint32 base_offset = m_last_frame * m_vertex_count * m_vsize;
143                m_context->update_attribute_offset( m_va, slot::POSITION, base_offset );
144                m_context->update_attribute_offset( m_va, slot::NORMAL,   base_offset + sizeof( vec3 ) );
145                if ( m_has_tangent && m_loc_next_tangent != -1 )
146                {
147                        m_context->update_attribute_offset( m_va, slot::TANGENT, base_offset + 2*sizeof( vec3 ) );
148                }
149                m_gpu_last_frame = m_last_frame;
150        }
151        if ( m_loc_next_position != -1 && m_gpu_next_frame != m_next_frame )
152        {
153                uint32 base_offset = m_next_frame * m_vertex_count * m_vsize;
154                m_context->update_attribute_offset( m_va, static_cast<slot>( m_loc_next_position ), base_offset );
155                m_context->update_attribute_offset( m_va, static_cast<slot>( m_loc_next_normal ), base_offset + sizeof( vec3 ) );
156                if ( m_has_tangent && m_loc_next_tangent != -1 )
157                {
158                        m_context->update_attribute_offset( m_va, static_cast<slot>( m_loc_next_tangent ), base_offset + 2*sizeof( vec3 ) );
159                }
160                m_gpu_next_frame = m_next_frame;
161        }
162}
163
164void nv::keyframed_mesh_gpu::update( program a_program )
165{
166        if ( m_loc_next_position == -1 )
167        {
168                device* dev = m_context->get_device();
169                m_loc_next_position = dev->get_attribute_location( a_program, "nv_next_position" );
170                m_loc_next_normal   = dev->get_attribute_location( a_program, "nv_next_normal" );
171                if ( m_has_tangent )
172                        m_loc_next_tangent  = dev->get_attribute_location( a_program, "nv_next_tangent" );
173
174                m_context->add_vertex_buffer( m_va, static_cast<slot>( m_loc_next_position ), m_pbuffer, FLOAT, 3, 0, m_vsize, false );
175                m_context->add_vertex_buffer( m_va, static_cast<slot>( m_loc_next_normal ),   m_pbuffer, FLOAT, 3, sizeof( vec3 ), m_vsize, false );
176                if ( m_has_tangent )
177                        m_context->add_vertex_buffer( m_va, static_cast<slot>( m_loc_next_tangent ), m_pbuffer, FLOAT, 4, 2*sizeof( vec3 ), m_vsize, false );
178        }
179        keyframed_mesh::update( a_program );
180}
181
182nv::keyframed_mesh_cpu::keyframed_mesh_cpu( context* a_context, const mesh_data* a_data, const mesh_nodes_data* a_tag_map )
183        : keyframed_mesh( a_context, a_data, a_tag_map )
184{
185        m_va      = m_context->create_vertex_array();
186        m_pbuffer = m_context->get_device()->create_buffer( VERTEX_BUFFER, STATIC_DRAW, m_vertex_count * m_vsize, m_vchannel->data );
187        m_context->add_vertex_buffers( m_va, m_pbuffer, m_vchannel );
188
189        buffer  vb = m_context->get_device()->create_buffer( VERTEX_BUFFER, STATIC_DRAW, m_vertex_count * sizeof( vec2 ), m_mesh_data->get_channel<vertex_t>()->data );
190        m_context->add_vertex_buffers( m_va, vb, m_mesh_data->get_channel<vertex_t>() );
191
192        buffer  ib = m_context->get_device()->create_buffer( INDEX_BUFFER, STATIC_DRAW, m_mesh_data->get_index_channel()->size(), m_mesh_data->get_index_channel()->data );
193
194        m_context->set_index_buffer( m_va, ib, m_mesh_data->get_index_channel()->desc[0].etype, true );
195
196        m_data = new uint8[ m_vertex_count * m_vsize ];
197}
198
199void nv::keyframed_mesh_cpu::update_animation( animation_entry* anim, uint32 a_anim_time )
200{
201        keyframed_mesh::update_animation( anim, a_anim_time );
202        // TODO: this could be done generic for any data
203        if ( m_has_tangent )
204        {
205                const vertex_pnt* data = m_mesh_data->get_channel_data<vertex_pnt>();
206                const vertex_pnt* prev = data + m_vertex_count * m_last_frame;
207                const vertex_pnt* next = data + m_vertex_count * m_next_frame;
208                      vertex_pnt* vtx  = reinterpret_cast<vertex_pnt*>( m_data );
209                for ( size_t i = 0; i < m_vertex_count; ++i )
210                {
211                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
212                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
213                        vtx[i].tangent  = glm::mix( prev[i].tangent,  next[i].tangent,   m_interpolation );
214                }
215        }
216        else
217        {
218                const vertex_pn* data = m_mesh_data->get_channel_data<vertex_pn>();
219                const vertex_pn* prev = data + m_vertex_count * m_last_frame;
220                const vertex_pn* next = data + m_vertex_count * m_next_frame;
221                      vertex_pn* vtx  = reinterpret_cast<vertex_pn*>( m_data );
222
223                for ( size_t i = 0; i < m_vertex_count; ++i )
224                {
225                        vtx[i].position = glm::mix( prev[i].position, next[i].position, m_interpolation );
226                        vtx[i].normal   = glm::mix( prev[i].normal,   next[i].normal,   m_interpolation );
227                }
228        }
229
230        m_context->update( m_pbuffer, m_data, 0, m_vertex_count * m_vsize );
231}
232
233nv::keyframed_mesh_cpu::~keyframed_mesh_cpu()
234{
235        delete[] m_data;
236}
Note: See TracBrowser for help on using the repository browser.