Visualization Library v1.0.3A lightweight C++ OpenGL middleware for 2D/3D graphics |
[Download] [Tutorials] [All Classes] [Grouped Classes] |
00001 /**************************************************************************************/ 00002 /* */ 00003 /* Visualization Library */ 00004 /* http://visualizationlibrary.org */ 00005 /* */ 00006 /* Copyright (c) 2005-2010, Michele Bosi */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without modification, */ 00010 /* are permitted provided that the following conditions are met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, this */ 00013 /* list of conditions and the following disclaimer. */ 00014 /* */ 00015 /* - Redistributions in binary form must reproduce the above copyright notice, this */ 00016 /* list of conditions and the following disclaimer in the documentation and/or */ 00017 /* other materials provided with the distribution. */ 00018 /* */ 00019 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND */ 00020 /* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED */ 00021 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE */ 00022 /* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR */ 00023 /* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES */ 00024 /* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; */ 00025 /* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON */ 00026 /* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT */ 00027 /* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ 00028 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00029 /* */ 00030 /**************************************************************************************/ 00031 00032 #include <vlGraphics/MorphingCallback.hpp> 00033 #include <vlCore/ResourceDatabase.hpp> 00034 #include <vlGraphics/GLSL.hpp> 00035 00036 using namespace vl; 00037 00038 //----------------------------------------------------------------------------- 00039 // MorphingCallback 00040 //----------------------------------------------------------------------------- 00041 MorphingCallback::MorphingCallback() 00042 { 00043 VL_DEBUG_SET_OBJECT_NAME() 00044 00045 mGeometry = new Geometry; 00046 setAnimation(0,0,0); 00047 resetGLSLBindings(); 00048 setGLSLVertexBlendEnabled(false); 00049 00050 mAnim_t = 0.0f; 00051 mFrame1 = -1; 00052 mFrame2 = -1; 00053 mLastUpdate = -1; 00054 } 00055 //----------------------------------------------------------------------------- 00056 MorphingCallback::~MorphingCallback() 00057 { 00058 } 00059 //----------------------------------------------------------------------------- 00060 void MorphingCallback::onActorRenderStarted(Actor*, real frame_clock, const Camera*, Renderable*, const Shader* shader, int pass) 00061 { 00062 // perform only on the first pass 00063 if (pass>0) 00064 return; 00065 00066 if (!mAnimationStarted) 00067 return; 00068 00069 mElapsedTime = frame_clock - mAnimationStartTime; 00070 // 30 fps update using the CPU vertex blending or continuous update if using the GPU 00071 bool do_update = mLastUpdate == -1 || (mElapsedTime - mLastUpdate) > 1.0f/30.0f || glslVertexBlendEnabled(); 00072 if ( do_update ) 00073 { 00074 mLastUpdate = mElapsedTime; 00075 real ft = mElapsedTime / mAnimationPeriod; 00076 ft = ft - (int)ft; 00077 int frame_count = mAnimationEnd - mAnimationStart + 1; 00078 mAnim_t = (float)(ft * frame_count - (int)(ft * frame_count)); 00079 mFrame1 = (int)(ft * frame_count); 00080 mFrame2 = (mFrame1 + 1) % frame_count; 00081 mFrame1 += mAnimationStart; 00082 mFrame2 += mAnimationStart; 00083 VL_CHECK(mFrame1 >= 0) 00084 VL_CHECK(mLastUpdate>=0) 00085 } 00086 00087 VL_CHECK(mFrame1 != -1) 00088 VL_CHECK(mLastUpdate != -1) 00089 00090 if (mLastUpdate == -1 || mFrame1 == -1) 00091 return; 00092 00093 const GLSLProgram* glslprogram = shader->glslProgram(); 00094 00095 // from here you can change uniforms or query uniform binding location 00096 00097 if ( glslVertexBlendEnabled() && glslprogram ) 00098 { 00099 // memo: 00100 // Since every character is in a different stage of the animation they all have different vertex/normal/etc. arrays pointers, 00101 // thus the lazy-vertex-array setup is forced to call glVertexAttribPointer/glVertexPointer/glBindBuffer continuously. 00102 // We may be able to partially solve this by putting all the animations in a single ArrayFloat3 and let the draw_calls 00103 // switch the frame by using the base-vertex functionality. 00104 // I modified the App_MorphAnimation test so that all the characters share the same animation (thus the same vertex arrays) and don't have 00105 // transforms attached to eliminate the cost of glLoadMatrix/glMatrixMode. The resulting frame to frame time resulted only 1.2% reduced. 00106 00107 // vertex/normals frame 1 00108 mGeometry->setVertexArray( mVertexFrames[mFrame1].get() ); 00109 mGeometry->setNormalArray( mNormalFrames[mFrame1].get() ); 00110 00111 if (!mVertexFrames[mFrame1]->bufferObject()->handle() || mVertexFrames[mFrame1]->isBufferObjectDirty()) 00112 mVertexFrames[mFrame1]->updateBufferObject(BUM_KeepRamBuffer); 00113 00114 if (!mVertexFrames[mFrame2]->bufferObject()->handle() || mVertexFrames[mFrame2]->isBufferObjectDirty()) 00115 mVertexFrames[mFrame2]->updateBufferObject(BUM_KeepRamBuffer); 00116 00117 if (!mNormalFrames[mFrame1]->bufferObject()->handle() || mNormalFrames[mFrame1]->isBufferObjectDirty()) 00118 mNormalFrames[mFrame1]->updateBufferObject(BUM_KeepRamBuffer); 00119 00120 if (!mNormalFrames[mFrame2]->bufferObject()->handle() || mNormalFrames[mFrame2]->isBufferObjectDirty()) 00121 mNormalFrames[mFrame2]->updateBufferObject(BUM_KeepRamBuffer); 00122 00123 VL_CHECK( mVertexFrames[mFrame1]->bufferObject()->handle() ) 00124 VL_CHECK( mVertexFrames[mFrame2]->bufferObject()->handle() ) 00125 VL_CHECK( mNormalFrames[mFrame1]->bufferObject()->handle() ) 00126 VL_CHECK( mNormalFrames[mFrame2]->bufferObject()->handle() ) 00127 00128 #if 1 // faster method: 00129 00130 // vertex attrib and uniform animation 00131 if (mVertex2_Binding == -1) 00132 mVertex2_Binding = glslprogram->getAttribLocation("vertex2"); 00133 00134 if (mNormal2_Binding == -1) 00135 mNormal2_Binding = glslprogram->getAttribLocation("normal2"); 00136 00137 if (mAnim_t_Binding == -1) 00138 mAnim_t_Binding = glslprogram->getUniformLocation("anim_t"); 00139 00140 // vertex/normals frame 2 00141 mGeometry->setVertexAttribArray( mVertex2_Binding, mVertexFrames[mFrame2].get() ); 00142 mGeometry->setVertexAttribArray( mNormal2_Binding, mNormalFrames[mFrame2].get() ); 00143 // frame interpolation ratio 00144 glUniform1fv(mAnim_t_Binding, 1, &mAnim_t); 00145 00146 #else // slower but simpler method: 00147 00148 // vertex/normals frame 2 00149 mGeometry->setVertexAttribArray( glslprogram->getAttribLocation("vertex2"), false, false, mVertexFrames[mFrame2].get() ); 00150 mGeometry->setVertexAttribArray( glslprogram->getAttribLocation("normal2"), false, false, mNormalFrames[mFrame2].get() ); 00151 // frame interpolation ratio 00152 glUniform1fv(glslprogram->getUniformLocation("anim_t"), 1, &mAnim_t); 00153 #endif 00154 } 00155 else 00156 if ( do_update ) 00157 { 00158 if (mGeometry->vertexArray() == NULL) 00159 mGeometry->setVertexArray(mVertices.get()); 00160 00161 if (mGeometry->normalArray() == NULL) 00162 mGeometry->setNormalArray(mNormals.get()); 00163 00164 blendFrames(mFrame1, mFrame2, mAnim_t); 00165 } 00166 } 00167 //----------------------------------------------------------------------------- 00168 void MorphingCallback::bindActor(Actor* actor) 00169 { 00170 actor->actorEventCallbacks()->push_back( this ); 00171 actor->setLod(0, mGeometry.get()); 00172 } 00173 //----------------------------------------------------------------------------- 00174 void MorphingCallback::init(ResourceDatabase* res_db) 00175 { 00176 if (res_db->count<Geometry>() == 0) 00177 return; 00178 00179 Geometry* geometry = res_db->get<Geometry>(0); 00180 mGeometry->shallowCopyFrom( *geometry ); 00181 mVertices = new ArrayFloat3; 00182 mNormals = new ArrayFloat3; 00183 00184 // setup Geometry vertex attributes 00185 00186 // copy vertex frames 00187 00188 for(unsigned i=0, count=res_db->count<ArrayAbstract>(); i<count; ++i) 00189 { 00190 ArrayFloat3* buffer = cast<ArrayFloat3>(res_db->get<ArrayAbstract>(i)); 00191 if (buffer && buffer->objectName() == "vertex_frame") 00192 { 00193 mVertexFrames.push_back(buffer); 00194 } 00195 else 00196 if (buffer && buffer->objectName() == "normal_frame") 00197 { 00198 mNormalFrames.push_back(buffer); 00199 } 00200 } 00201 00202 if (mVertexFrames.empty()) 00203 { 00204 Log::error("MorphingCallback::init(): no ArrayFloat3 named 'vertex_frame' found.\n"); 00205 return; 00206 } 00207 00208 if (mNormalFrames.empty()) 00209 { 00210 Log::error("MorphingCallback::init(): no ArrayFloat3 named 'normal_frame' found.\n"); 00211 return; 00212 } 00213 00214 if (mVertexFrames.size() != mNormalFrames.size()) 00215 { 00216 Log::error("MorphingCallback::init(): vertex frame count differs from normal frame count.\n"); 00217 return; 00218 } 00219 00220 // compute AABB using the first frame 00221 00222 mGeometry->setVertexArray(mVertexFrames[0].get() ); 00223 mGeometry->setNormalArray(mNormalFrames[0].get() ); 00224 mGeometry->computeBounds(); 00225 00226 mGeometry->setVertexArray(NULL); 00227 mGeometry->setNormalArray(NULL); 00228 } 00229 //----------------------------------------------------------------------------- 00230 void MorphingCallback::blendFrames(int a, int b, float t) 00231 { 00232 // allocate interpolation buffers 00233 if (mVertices->size() != mVertexFrames[0]->size() || 00234 mNormals->size() != mNormalFrames[0]->size() ) 00235 { 00236 mVertices->resize( mVertexFrames[0]->size() ); 00237 mNormals->resize( mNormalFrames[0]->size() ); 00238 } 00239 00240 #if 1 00241 float Ha = 1-t; 00242 float Hb = t; 00243 #else 00244 float Ha = 2*t*t*t - 3*t*t + 1; 00245 float Hb = -2*t*t*t + 3*t*t; 00246 #endif 00247 00248 for(size_t i=0; i<mVertices->size(); ++i) 00249 { 00250 mVertices->at(i) = mVertexFrames[ a ]->at(i)*Ha + mVertexFrames[ b ]->at(i)*Hb; 00251 mNormals->at(i) = mNormalFrames[ a ]->at(i)*Ha + mNormalFrames[ b ]->at(i)*Hb; 00252 } 00253 00254 if (mGeometry->isBufferObjectEnabled() && Has_BufferObject) 00255 { 00256 // mic fixme: 00257 // Come si vede qui' sta nomenclatura non e' chiara: 00258 // sembra che stiamo semplicemente cambiano un po di flags invece stiamo updatando tutto il BufferObject!!! 00259 mVertices->bufferObject()->setBufferData(BU_DYNAMIC_DRAW, false); 00260 mNormals ->bufferObject()->setBufferData(BU_DYNAMIC_DRAW, false); 00261 } 00262 } 00263 //----------------------------------------------------------------------------- 00264 void MorphingCallback::setAnimation(int start, int end, float period) 00265 { 00266 mFrame1 = -1; 00267 mFrame2 = -1; 00268 mLastUpdate = -1; 00269 mElapsedTime = 0; 00270 mAnimationStartTime = 0; 00271 mAnimationStart = start; 00272 mAnimationEnd = end; 00273 mAnimationPeriod = period; 00274 mAnimationStarted = false; 00275 } 00276 //----------------------------------------------------------------------------- 00277 void MorphingCallback::startAnimation(real start_time) 00278 { 00279 mAnimationStarted = true; 00280 mFrame1 = -1; 00281 mFrame2 = -1; 00282 mLastUpdate = -1; 00283 mElapsedTime = 0; 00284 mAnimationStartTime = start_time; 00285 } 00286 //----------------------------------------------------------------------------- 00287 void MorphingCallback::stopAnimation() 00288 { 00289 mAnimationStarted = false; 00290 } 00291 //----------------------------------------------------------------------------- 00292 void MorphingCallback::initFrom(MorphingCallback* morph_cb) 00293 { 00294 mVertices = new ArrayFloat3; 00295 mNormals = new ArrayFloat3; 00296 00297 // copy vertex frames 00298 00299 mVertexFrames = morph_cb->mVertexFrames; 00300 mNormalFrames = morph_cb->mNormalFrames; 00301 00302 #if 0 00303 // Geometry sharing method: works only wiht GLSL 00304 00305 // we can have a single shared Geometry since our MorphingCallback setups the 00306 // appropriate position and normal arrays for every Actor just before the rendering! 00307 mGeometry = morph_cb->mGeometry; 00308 #else 00309 // Geometry copy method 00310 mGeometry->shallowCopyFrom( *morph_cb->mGeometry ); 00311 00312 // compute AABB using the first frame 00313 00314 mGeometry->setVertexArray(morph_cb->mVertexFrames[0].get() ); 00315 mGeometry->setNormalArray(morph_cb->mNormalFrames[0].get() ); 00316 mGeometry->computeBounds(); 00317 00318 mGeometry->setVertexArray(NULL); 00319 mGeometry->setNormalArray(NULL); 00320 #endif 00321 00322 setAnimation(0,0,0); 00323 } 00324 //----------------------------------------------------------------------------- 00325 void MorphingCallback::resetGLSLBindings() 00326 { 00327 mVertex2_Binding = -1; 00328 mNormal2_Binding = -1; 00329 mAnim_t_Binding = -1; 00330 } 00331 //-----------------------------------------------------------------------------