Visualization Library

A lightweight C++ OpenGL middleware for 2D/3D graphics
[Home] [Tutorials] [All Classes] [Grouped Classes]

X:/dropbox/visualizationlibrary/src/vlGraphics/Renderer.cpp

Go to the documentation of this file.
00001 /**************************************************************************************/
00002 /*                                                                                    */
00003 /*  Visualization Library                                                             */
00004 /*  http://www.visualizationlibrary.org                                               */
00005 /*                                                                                    */
00006 /*  Copyright (c) 2005-2011, 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 <vlCore/GlobalSettings.hpp>
00033 #include <vlGraphics/Renderer.hpp>
00034 #include <vlGraphics/OpenGLContext.hpp>
00035 #include <vlGraphics/GLSL.hpp>
00036 #include <vlGraphics/RenderQueue.hpp>
00037 #include <vlCore/Log.hpp>
00038 
00039 using namespace vl;
00040 
00041 //------------------------------------------------------------------------------
00042 // Renderer
00043 //------------------------------------------------------------------------------
00044 Renderer::Renderer()
00045 {
00046   VL_DEBUG_SET_OBJECT_NAME()
00047 
00048   mProjViewTransfCallback = new ProjViewTransfCallback;
00049 
00050   mDummyEnables  = new EnableSet;
00051   mDummyStateSet = new RenderStateSet;
00052 }
00053 //------------------------------------------------------------------------------
00054 namespace
00055 {
00056   struct GLSLProgState
00057   {
00058   public:
00059     GLSLProgState(): mCamera(NULL), mTransform(NULL), mGLSLProgUniformSet(NULL), mShaderUniformSet(NULL), mActorUniformSet(NULL) {}
00060 
00061     bool operator<(const GLSLProgState& other) const
00062     {
00063       if ( mCamera != other.mCamera )
00064         return mCamera < other.mCamera;
00065       else
00066       if ( mTransform != other.mTransform )
00067         return mTransform < other.mTransform;
00068       else
00069       if ( mGLSLProgUniformSet != other.mGLSLProgUniformSet )
00070         return mGLSLProgUniformSet < other.mGLSLProgUniformSet;
00071       else
00072       if ( mShaderUniformSet != other.mShaderUniformSet ) 
00073         return mShaderUniformSet < other.mShaderUniformSet;
00074       else
00075         return mActorUniformSet < other.mActorUniformSet;
00076     }
00077 
00078     const Camera* mCamera;
00079     const Transform* mTransform;
00080     const UniformSet* mGLSLProgUniformSet;
00081     const UniformSet* mShaderUniformSet;
00082     const UniformSet* mActorUniformSet;
00083   };
00084 }
00085 //------------------------------------------------------------------------------
00086 const RenderQueue* Renderer::render(const RenderQueue* render_queue, Camera* camera, real frame_clock)
00087 {
00088   VL_CHECK_OGL()
00089 
00090   // skip if renderer is disabled
00091 
00092   if (enableMask() == 0)
00093     return render_queue;
00094 
00095   // enter/exit behavior contract
00096 
00097   class InOutContract 
00098   {
00099     Renderer* mRenderer;
00100     std::vector<RenderStateSlot> mOriginalDefaultRS;
00101   public:
00102     InOutContract(Renderer* renderer, Camera* camera): mRenderer(renderer)
00103     {
00104       // increment the render tick.
00105       mRenderer->mRenderTick++;
00106 
00107       // render-target activation.
00108       // note: an OpenGL context can have multiple rendering targets!
00109       mRenderer->framebuffer()->activate();
00110 
00111       // viewport setup.
00112       camera->viewport()->setClearFlags( mRenderer->clearFlags() );
00113       camera->viewport()->activate();
00114 
00115       OpenGLContext* gl_context = renderer->framebuffer()->openglContext();
00116 
00117       // default render states override
00118       for(size_t i=0; i<renderer->overriddenDefaultRenderStates().size(); ++i)
00119       {
00120         // save overridden default render state to be restored later
00121         ERenderState type = renderer->overriddenDefaultRenderStates()[i].type();
00122         mOriginalDefaultRS.push_back(gl_context->defaultRenderState(type));
00123         // set new default render state
00124         gl_context->setDefaultRenderState(renderer->overriddenDefaultRenderStates()[i]);
00125       }
00126 
00127       // dispatch the renderer-started event.
00128       mRenderer->dispatchOnRendererStarted();
00129 
00130       // check user-generated errors.
00131       VL_CHECK_OGL()
00132     }
00133 
00134     ~InOutContract()
00135     {
00136       // dispatch the renderer-finished event
00137       mRenderer->dispatchOnRendererFinished();
00138 
00139       OpenGLContext* gl_context = mRenderer->framebuffer()->openglContext();
00140 
00141       // restore default render states
00142       for(size_t i=0; i<mOriginalDefaultRS.size(); ++i)
00143       {
00144         gl_context->setDefaultRenderState(mOriginalDefaultRS[i]);
00145       }
00146 
00147       VL_CHECK( !globalSettings()->checkOpenGLStates() || mRenderer->framebuffer()->openglContext()->isCleanState(true) );
00148 
00149       // check user-generated errors.
00150       VL_CHECK_OGL()
00151 
00152       // note: we don't reset the render target here
00153     }
00154   } contract(this, camera);
00155 
00156   // --------------- rendering --------------- 
00157 
00158   std::map<const GLSLProgram*, GLSLProgState> glslprogram_map;
00159 
00160   OpenGLContext* opengl_context = framebuffer()->openglContext();
00161 
00162   // --------------- default scissor ---------------
00163 
00164   // non GLSLProgram state sets
00165   const RenderStateSet* cur_render_state_set = NULL;
00166   const EnableSet* cur_enable_set = NULL;
00167   const Scissor* cur_scissor = NULL;
00168 
00169   // scissor the viewport by default: needed for points and lines since they are not clipped against the viewport
00170   // this is already setup by the Viewport
00171   /*
00172   glEnable(GL_SCISSOR_TEST);
00173   glScissor(camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height());
00174   */
00175 
00176   // --------------- rendering ---------------
00177 
00178   for(int itok=0; itok < render_queue->size(); ++itok)
00179   {
00180     const RenderToken* tok = render_queue->at(itok); VL_CHECK(tok);
00181     Actor* actor = tok->mActor; VL_CHECK(actor);
00182 
00183     if ( !isEnabled(actor->enableMask()) )
00184       continue;
00185 
00186     // --------------- Actor's scissor ---------------
00187 
00188     // mic fixme:this kind of scissor management is not particularly elegant.
00189     // It is required mainly for convenience for the vector graphics that allow the specification of a clipping rectangular area at any point in the rendering.
00190     // We must also find a good general solution to support indexed scissoring and viewport.
00191 
00192     const Scissor* scissor = actor->scissor() ? actor->scissor() : tok->mShader->scissor();
00193     if (cur_scissor != scissor)
00194     {
00195       cur_scissor = scissor;
00196       if (cur_scissor)
00197       {
00198         cur_scissor->enable(camera->viewport());
00199       }
00200       else
00201       {
00202         // scissor the viewport by default: needed for points and lines with size > 1.0 as they are not clipped against the viewport.
00203         VL_CHECK(glIsEnabled(GL_SCISSOR_TEST))
00204         glScissor(camera->viewport()->x(), camera->viewport()->y(), camera->viewport()->width(), camera->viewport()->height());
00205       }
00206     }
00207 
00208     // multipassing
00209     for( int ipass=0; tok != NULL; tok = tok->mNextPass, ++ipass )
00210     {
00211       VL_CHECK_OGL()
00212 
00213       // --------------- shader setup ---------------
00214 
00215       const Shader* shader = tok->mShader;
00216 
00217       // shader override: select the first that matches
00218 
00219       for( std::map< unsigned int, ref<Shader> >::const_iterator eom_it = mShaderOverrideMask.begin(); 
00220            eom_it != mShaderOverrideMask.end(); 
00221            ++eom_it )
00222       {
00223         if ( eom_it->first & actor->enableMask() )
00224         {
00225           shader = eom_it->second.get();
00226           break;
00227         }
00228       }
00229 
00230       // shader's render states
00231 
00232       if ( cur_render_state_set != shader->getRenderStateSet() )
00233       {
00234         opengl_context->applyRenderStates( shader->getRenderStateSet(), camera );
00235         cur_render_state_set = shader->getRenderStateSet();
00236       }
00237 
00238       VL_CHECK_OGL()
00239 
00240       // shader's enables
00241 
00242       if ( cur_enable_set != shader->getEnableSet() )
00243       {
00244         opengl_context->applyEnables( shader->getEnableSet() );
00245         cur_enable_set = shader->getEnableSet();
00246       }
00247 
00248       #ifndef NDEBUG
00249         if (glGetError() != GL_NO_ERROR)
00250         {
00251           Log::error("An unsupported OpenGL glEnable/glDisable capability has been enabled!\n");
00252           VL_TRAP()
00253         }
00254       #endif
00255 
00256       // --------------- Actor pre-render callback ---------------
00257 
00258       // here the user has still the possibility to modify the Actor's uniforms
00259 
00260       actor->dispatchOnActorRenderStarted( frame_clock, camera, tok->mRenderable, shader, ipass );
00261 
00262       VL_CHECK_OGL()
00263 
00264       // --------------- GLSLProgram setup ---------------
00265 
00266       VL_CHECK( !shader->glslProgram() || shader->glslProgram()->linked() );
00267 
00268       VL_CHECK_OGL()
00269 
00270       // current transform
00271       const Transform*   cur_transform             = actor->transform(); 
00272       const GLSLProgram* cur_glsl_program          = NULL; // NULL == fixed function pipeline
00273       const UniformSet*  cur_glsl_prog_uniform_set = NULL;
00274       const UniformSet*  cur_shader_uniform_set    = NULL;
00275       const UniformSet*  cur_actor_uniform_set     = NULL;
00276 
00277       // make sure we update these things only if there is a valid GLSLProgram
00278       if (shader->glslProgram() && shader->glslProgram()->handle())
00279       {
00280         cur_glsl_program = shader->glslProgram();
00281 
00282         // consider them NULL if they are empty
00283         if (cur_glsl_program->getUniformSet() && !cur_glsl_program->getUniformSet()->uniforms().empty())
00284           cur_glsl_prog_uniform_set = cur_glsl_program->getUniformSet();
00285 
00286         if (shader->getUniformSet() && !shader->getUniformSet()->uniforms().empty())
00287           cur_shader_uniform_set = shader->getUniformSet();
00288         
00289         if (actor->getUniformSet() && !actor->getUniformSet()->uniforms().empty())
00290           cur_actor_uniform_set = actor->getUniformSet();
00291       } 
00292 
00293       bool update_cm = false; // update camera
00294       bool update_tr = false; // update transform
00295       bool update_pu = false; // update glsl-program uniforms
00296       bool update_su = false; // update shader uniforms
00297       bool update_au = false; // update actor uniforms
00298       GLSLProgState* glsl_state = NULL;
00299 
00300       // retrieve the state of this GLSLProgram (including the NULL one)
00301       std::map<const GLSLProgram*, GLSLProgState>::iterator glsl_state_it = glslprogram_map.find(cur_glsl_program);
00302       
00303       if ( glsl_state_it == glslprogram_map.end() )
00304       {
00305         //
00306         // this is the first time we see this GLSL program so we update everything we can
00307         //
00308 
00309         // create a new glsl-state entry
00310         glsl_state = &glslprogram_map[cur_glsl_program];
00311         update_cm = true;
00312         update_tr = true;
00313         update_pu = cur_glsl_prog_uniform_set != NULL;
00314         update_su = cur_shader_uniform_set    != NULL;
00315         update_au = cur_actor_uniform_set     != NULL;
00316       }
00317       else
00318       {
00319         //
00320         // we already know this GLSLProgram so we update only what has changed since last time
00321         //
00322 
00323         glsl_state = &glsl_state_it->second;
00324         // check for differences
00325         update_cm = glsl_state->mCamera             != camera;
00326         update_tr = glsl_state->mTransform          != cur_transform;
00327         update_pu = glsl_state->mGLSLProgUniformSet != cur_glsl_prog_uniform_set && cur_glsl_prog_uniform_set != NULL;
00328         update_su = glsl_state->mShaderUniformSet   != cur_shader_uniform_set    && cur_shader_uniform_set    != NULL;
00329         update_au = glsl_state->mActorUniformSet    != cur_actor_uniform_set     && cur_actor_uniform_set     != NULL;
00330       }
00331 
00332       // update glsl-state structure
00333       glsl_state->mCamera             = camera;
00334       glsl_state->mTransform          = cur_transform;
00335       glsl_state->mGLSLProgUniformSet = cur_glsl_prog_uniform_set;
00336       glsl_state->mShaderUniformSet   = cur_shader_uniform_set;
00337       glsl_state->mActorUniformSet    = cur_actor_uniform_set;
00338 
00339       // --- update proj, view and transform matrices ---
00340 
00341       VL_CHECK_OGL()
00342 
00343       if (update_cm || update_tr)
00344         projViewTransfCallback()->updateMatrices( update_cm, update_tr, cur_glsl_program, camera, cur_transform );
00345 
00346       VL_CHECK_OGL()
00347 
00348       // --- uniforms ---
00349 
00350       // note: the user must not make the glslprogram's, shader's and actor's uniforms collide!
00351       VL_CHECK( !opengl_context->areUniformsColliding(cur_shader_uniform_set, cur_actor_uniform_set) );
00352       VL_CHECK( !opengl_context->areUniformsColliding(cur_shader_uniform_set, cur_glsl_prog_uniform_set ) );
00353       VL_CHECK( !opengl_context->areUniformsColliding(cur_actor_uniform_set, cur_glsl_prog_uniform_set ) );
00354 
00355       VL_CHECK_OGL()
00356 
00357       // glsl program uniform set
00358       if ( update_pu )
00359       {
00360         VL_CHECK( cur_glsl_prog_uniform_set && cur_glsl_prog_uniform_set->uniforms().size() );
00361         VL_CHECK( shader->getRenderStateSet()->glslProgram() && shader->getRenderStateSet()->glslProgram()->handle() )
00362         cur_glsl_program->applyUniformSet( cur_glsl_prog_uniform_set );
00363       }
00364 
00365       VL_CHECK_OGL()
00366 
00367       // shader uniform set
00368       if ( update_su )
00369       {
00370         VL_CHECK( cur_shader_uniform_set && cur_shader_uniform_set->uniforms().size() );
00371         VL_CHECK( shader->getRenderStateSet()->glslProgram() && shader->getRenderStateSet()->glslProgram()->handle() )
00372         cur_glsl_program->applyUniformSet( cur_shader_uniform_set );
00373       }
00374 
00375       VL_CHECK_OGL()
00376 
00377       // actor uniform set
00378       if ( update_au )
00379       {
00380         VL_CHECK( cur_actor_uniform_set && cur_actor_uniform_set->uniforms().size() );
00381         VL_CHECK( shader->getRenderStateSet()->glslProgram() && shader->getRenderStateSet()->glslProgram()->handle() )
00382         cur_glsl_program->applyUniformSet( cur_actor_uniform_set );
00383       }
00384 
00385       VL_CHECK_OGL()
00386 
00387       // --------------- Actor rendering ---------------
00388 
00389       // also compiles display lists and updates BufferObjects if necessary
00390       tok->mRenderable->render( actor, shader, camera, opengl_context );
00391 
00392       VL_CHECK_OGL()
00393 
00394       // if shader is overridden it does not make sense to perform multipassing so we break the loop here.
00395       if (shader != tok->mShader)
00396         break;
00397     }
00398   }
00399 
00400   // clear enables
00401   opengl_context->applyEnables( mDummyEnables.get() ); VL_CHECK_OGL();
00402 
00403   // clear render states
00404   opengl_context->applyRenderStates( mDummyStateSet.get(), NULL ); VL_CHECK_OGL();
00405 
00406   // enabled texture unit #0
00407   VL_glActiveTexture( GL_TEXTURE0 ); VL_CHECK_OGL();
00408   if (Has_Fixed_Function_Pipeline)
00409     VL_glClientActiveTexture( GL_TEXTURE0 ); VL_CHECK_OGL();
00410 
00411   // disable scissor test
00412   glDisable(GL_SCISSOR_TEST); VL_CHECK_OGL();
00413 
00414   // disable all vertex arrays, note this also calls "glBindBuffer(GL_ARRAY_BUFFER, 0)"
00415   opengl_context->bindVAS(NULL, false, false); VL_CHECK_OGL();
00416 
00417   return render_queue;
00418 }
00419 //-----------------------------------------------------------------------------

Visualization Library 2011.09.1160 Reference Documentation
Copyright 2005-2011 Michele Bosi. All rights reserved.
Updated on Thu May 2 2013 13:40:40.
Permission is granted to use this page to write and publish articles regarding Visualization Library.