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/Rendering.hpp> 00033 #include <vlGraphics/OpenGLContext.hpp> 00034 #include <vlGraphics/Renderer.hpp> 00035 #include <vlGraphics/SceneManager.hpp> 00036 #include <vlGraphics/RenderQueue.hpp> 00037 #include <vlGraphics/GLSL.hpp> 00038 #include <vlCore/Log.hpp> 00039 #include <vlCore/Say.hpp> 00040 00041 using namespace vl; 00042 00043 //------------------------------------------------------------------------------ 00044 Rendering::Rendering(): 00045 mAutomaticResourceInit(true), 00046 mCullingEnabled(true), 00047 mEvaluateLOD(true), 00048 mShaderAnimationEnabled(true), 00049 mNearFarClippingPlanesOptimized(false) 00050 { 00051 VL_DEBUG_SET_OBJECT_NAME() 00052 mRenderQueueSorter = new RenderQueueSorterStandard; 00053 mActorQueue = new ActorCollection; 00054 mRenderQueue = new RenderQueue; 00055 mSceneManagers = new Collection<SceneManager>; 00056 mCamera = new Camera; 00057 mTransform = new Transform; 00058 mRenderers.push_back( new Renderer ); 00059 } 00060 //------------------------------------------------------------------------------ 00061 Rendering& Rendering::operator=(const Rendering& other) 00062 { 00063 super::operator=(other); 00064 00065 mEnableMask = other.mEnableMask; 00066 mAutomaticResourceInit = other.mAutomaticResourceInit; 00067 mCullingEnabled = other.mCullingEnabled; 00068 mEvaluateLOD = other.mEvaluateLOD; 00069 mShaderAnimationEnabled = other.mShaderAnimationEnabled; 00070 mNearFarClippingPlanesOptimized = other.mNearFarClippingPlanesOptimized; 00071 00072 mRenderQueueSorter = other.mRenderQueueSorter; 00073 /*mActorQueue = other.mActorQueue;*/ 00074 /*mRenderQueue = other.mRenderQueue;*/ 00075 *mSceneManagers = *other.mSceneManagers; 00076 mRenderers = other.mRenderers; 00077 mCamera = other.mCamera; 00078 mTransform = other.mTransform; 00079 00080 return *this; 00081 } 00082 //------------------------------------------------------------------------------ 00083 void Rendering::render() 00084 { 00085 VL_CHECK(camera()); 00086 VL_CHECK(camera()->viewport()); 00087 00088 // if rendering is disabled skip all. 00089 00090 if ( enableMask() == 0 ) 00091 return; 00092 00093 // enter/exit behavior contract 00094 00095 class InOutContract 00096 { 00097 Rendering* mRendering; 00098 OpenGLContext* mOpenGLContext; 00099 00100 public: 00101 InOutContract(Rendering* rendering): mRendering(rendering) 00102 { 00103 VL_CHECK(mRendering->renderers().size()); 00104 VL_CHECK(mRendering->renderers()[0]->framebuffer()); 00105 VL_CHECK(mRendering->renderers()[0]->framebuffer()->openglContext()); 00106 00107 // as stated in the documentation all the renderers must target the same OpenGLContext 00108 mOpenGLContext = mRendering->renderers()[0]->framebuffer()->openglContext(); 00109 00110 // activate OpenGL context 00111 mOpenGLContext->makeCurrent(); 00112 VL_CHECK_OGL(); // the first check must be done when the context is active! 00113 00114 // render states ]shield[ 00115 mOpenGLContext->resetContextStates(RCS_RenderingStarted); 00116 00117 // pre rendering callback 00118 mRendering->dispatchOnRenderingStarted(); 00119 00120 // check user-generated errors. 00121 VL_CHECK_OGL() 00122 } 00123 00124 ~InOutContract() 00125 { 00126 // post rendering callback 00127 mRendering->dispatchOnRenderingFinished(); 00128 00129 // release rendered Actors 00130 mRendering->actorQueue()->resize(0); 00131 00132 // check user-generated errors. 00133 VL_CHECK_OGL() 00134 00135 // render states ]shield[ 00136 mOpenGLContext->resetContextStates(RCS_RenderingFinished); 00137 } 00138 } contract(this); 00139 00140 // --------------- rendering --------------- 00141 00142 if (renderers().empty()) 00143 { 00144 vl::Log::error("Rendering::render(): no Renderer specified for this Rendering!\n"); 00145 VL_TRAP(); 00146 return; 00147 } 00148 00149 if (!renderers()[0]->framebuffer()) 00150 { 00151 vl::Log::error("Rendering::render(): no RendererTarget specified for Renderer #0!\n"); 00152 VL_TRAP(); 00153 return; 00154 } 00155 00156 if (!renderers()[0]->framebuffer()->openglContext()) 00157 { 00158 vl::Log::error("Rendering::render(): invalid Framebuffer for Renderer #0, OpenGLContext is NULL!\n"); 00159 VL_TRAP(); 00160 return; 00161 } 00162 00163 if (sceneManagers()->empty()) 00164 return; 00165 00166 if (!camera()) 00167 return; 00168 00169 if (!camera()->viewport()) 00170 return; 00171 00172 // transform 00173 00174 if (transform() != NULL) 00175 transform()->computeWorldMatrixRecursive( camera() ); 00176 00177 // camera transform update (can be redundant) 00178 00179 if (camera()->boundTransform()) 00180 camera()->setModelingMatrix( camera()->boundTransform()->worldMatrix() ); 00181 00182 VL_CHECK_OGL() 00183 00184 // culling & actor queue filling 00185 00186 camera()->computeFrustumPlanes(); 00187 00188 // if near/far clipping planes optimization is enabled don't perform far-culling 00189 if (nearFarClippingPlanesOptimized()) 00190 { 00191 // perform only near culling with plane at distance 0 00192 camera()->frustum().planes().resize(5); 00193 camera()->frustum().planes()[4] = Plane( camera()->modelingMatrix().getT(), 00194 camera()->modelingMatrix().getZ()); 00195 } 00196 00197 actorQueue()->clear(); 00198 for(int i=0; i<sceneManagers()->size(); ++i) 00199 { 00200 if ( isEnabled(sceneManagers()->at(i)->enableMask()) ) 00201 { 00202 if (cullingEnabled() && sceneManagers()->at(i)->cullingEnabled()) 00203 { 00204 if (sceneManagers()->at(i)->boundsDirty()) 00205 sceneManagers()->at(i)->computeBounds(); 00206 // try to cull the scene with both bsphere and bbox 00207 bool visible = !camera()->frustum().cull(sceneManagers()->at(i)->boundingSphere()) && 00208 !camera()->frustum().cull(sceneManagers()->at(i)->boundingBox()); 00209 if ( visible ) 00210 sceneManagers()->at(i)->extractVisibleActors( *actorQueue(), camera() ); 00211 } 00212 else 00213 sceneManagers()->at(i)->extractActors( *actorQueue() ); 00214 } 00215 } 00216 00217 // collect near/far clipping planes optimization information 00218 if (nearFarClippingPlanesOptimized()) 00219 { 00220 Sphere world_bounding_sphere; 00221 for(int i=0; i<actorQueue()->size(); ++i) 00222 world_bounding_sphere += actorQueue()->at(i)->boundingSphere(); 00223 00224 // compute the optimized 00225 camera()->computeNearFarOptimizedProjMatrix(world_bounding_sphere); 00226 00227 // recompute frustum planes to account for new near/far values 00228 camera()->computeFrustumPlanes(); 00229 } 00230 00231 // render queue filling 00232 00233 renderQueue()->clear(); 00234 fillRenderQueue( actorQueue() ); 00235 00236 // sort the rendering queue according to this renderer sorting algorithm 00237 00238 if (renderQueueSorter()) 00239 renderQueue()->sort( renderQueueSorter(), camera() ); 00240 00241 // --- RENDER THE QUEUE: loop through the renderers, feeding the output of one as input for the next --- 00242 00243 const RenderQueue* render_queue = renderQueue(); 00244 for(size_t i=0; i<renderers().size(); ++i) 00245 { 00246 if (renderers()[i]) 00247 { 00248 if (renderers()[i]->framebuffer() == NULL) 00249 { 00250 vl::Log::error( Say("Rendering::render(): no RendererTarget specified for Renderer #%n!\n") << i ); 00251 VL_TRAP(); 00252 continue; 00253 } 00254 00255 if (renderers()[i]->framebuffer()->openglContext() == NULL) 00256 { 00257 vl::Log::error( Say("Rendering::render(): invalid Framebuffer for Renderer #%n, OpenGLContext is NULL!\n") << i ); 00258 VL_TRAP(); 00259 continue; 00260 } 00261 00262 // loop the rendering 00263 render_queue = renderers()[i]->render( render_queue, camera(), frameClock() ); 00264 } 00265 } 00266 00267 VL_CHECK_OGL() 00268 } 00269 //------------------------------------------------------------------------------ 00270 void Rendering::fillRenderQueue( ActorCollection* actor_list ) 00271 { 00272 if (actor_list == NULL) 00273 return; 00274 00275 if (actor_list->empty()) 00276 return; 00277 00278 if (camera() == NULL) 00279 return; 00280 00281 if (enableMask() == 0) 00282 return; 00283 00284 RenderQueue* list = renderQueue(); 00285 std::set<Shader*> shader_set; 00286 00287 // iterate actor list 00288 00289 for(int iactor=0; iactor < actor_list->size(); iactor++) 00290 { 00291 Actor* actor = actor_list->at(iactor); 00292 00293 VL_CHECK(actor->lod(0)) 00294 00295 if ( !isEnabled(actor->enableMask()) ) 00296 continue; 00297 00298 // update the Actor's bounds 00299 actor->computeBounds(); 00300 00301 Effect* effect = actor->effect(); 00302 VL_CHECK(effect) 00303 00304 // effect override: select the first that matches 00305 00306 for( std::map< unsigned int, ref<Effect> >::iterator eom_it = mEffectOverrideMask.begin(); 00307 eom_it != mEffectOverrideMask.end(); 00308 ++eom_it ) 00309 { 00310 if (eom_it->first & actor->enableMask()) 00311 { 00312 effect = eom_it->second.get(); 00313 break; 00314 } 00315 } 00316 00317 if ( !isEnabled(effect->enableMask()) ) 00318 continue; 00319 00320 // --------------- LOD evaluation --------------- 00321 00322 int effect_lod = effect->evaluateLOD( actor, camera() ); 00323 00324 int geometry_lod = 0; 00325 if ( evaluateLOD() ) 00326 geometry_lod = actor->evaluateLOD( camera() ); 00327 00328 // --------------- M U L T I P A S S I N G --------------- 00329 00330 RenderToken* prev_pass = NULL; 00331 const int pass_count = effect->lod(effect_lod)->size(); 00332 for(int ipass=0; ipass<pass_count; ++ipass) 00333 { 00334 // setup the shader to be used for this pass 00335 00336 Shader* shader = effect->lod(effect_lod)->at(ipass); 00337 00338 // --------------- fill render token --------------- 00339 00340 // create a render token 00341 RenderToken* tok = list->newToken(prev_pass != NULL); 00342 00343 // multipass chain: implemented as a linked list 00344 if ( prev_pass != NULL ) 00345 prev_pass->mNextPass = tok; 00346 prev_pass = tok; 00347 tok->mNextPass = NULL; 00348 // track the current state 00349 tok->mActor = actor; 00350 tok->mRenderable = actor->lod(geometry_lod); 00351 // set the shader used (multipassing shader or effect->shader()) 00352 tok->mShader = shader; 00353 00354 if ( shaderAnimationEnabled() ) 00355 { 00356 VL_CHECK(frameClock() >= 0) 00357 if( frameClock() >= 0 ) 00358 { 00359 // note that the condition is != as opposed to < 00360 if ( shader->lastUpdateTime() != frameClock() && shader->shaderAnimator() && shader->shaderAnimator()->isEnabled() ) 00361 { 00362 // update 00363 shader->shaderAnimator()->updateShader( shader, camera(), frameClock() ); 00364 00365 // note that we update this after 00366 shader->setLastUpdateTime( frameClock() ); 00367 } 00368 } 00369 } 00370 00371 if ( automaticResourceInit() && shader_set.find(shader) == shader_set.end() ) 00372 { 00373 shader_set.insert(shader); 00374 00375 // link GLSLProgram 00376 if (shader->glslProgram() && !shader->glslProgram()->linked()) 00377 { 00378 shader->glslProgram()->linkProgram(); 00379 VL_CHECK( shader->glslProgram()->linked() ); 00380 } 00381 00382 // lazy texture creation 00383 if ( shader->gocRenderStateSet() ) 00384 { 00385 size_t count = shader->gocRenderStateSet()->renderStatesCount(); 00386 RenderStateSlot* states = shader->gocRenderStateSet()->renderStates(); 00387 for( size_t i=0; i<count; ++i ) 00388 { 00389 if (states[i].mRS->type() == RS_TextureSampler) 00390 { 00391 TextureSampler* tex_unit = static_cast<TextureSampler*>( states[i].mRS.get() ); 00392 VL_CHECK(tex_unit); 00393 if (tex_unit) 00394 { 00395 if (tex_unit->texture() && tex_unit->texture()->setupParams()) 00396 tex_unit->texture()->createTexture(); 00397 } 00398 } 00399 } 00400 00401 } 00402 } 00403 00404 tok->mEffectRenderRank = effect->renderRank(); 00405 } 00406 } 00407 } 00408 //------------------------------------------------------------------------------