CrystalSpace

Public API Reference

csplugincommon/rendermanager/render.h
Go to the documentation of this file.
00001 /*
00002     Copyright (C) 2007-2008 by Marten Svanfeldt
00003 
00004     This library is free software; you can redistribute it and/or
00005     modify it under the terms of the GNU Library General Public
00006     License as published by the Free Software Foundation; either
00007     version 2 of the License, or (at your option) any later version.
00008 
00009     This library is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012     Library General Public License for more details.
00013 
00014     You should have received a copy of the GNU Library General Public
00015     License along with this library; if not, write to the Free
00016     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00017 */
00018 
00019 #ifndef __CS_CSPLUGINCOMMON_RENDERMANAGER_RENDER_H__
00020 #define __CS_CSPLUGINCOMMON_RENDERMANAGER_RENDER_H__
00021 
00026 #include "csplugincommon/rendermanager/posteffects.h"
00027 #include "csplugincommon/rendermanager/operations.h"
00028 #include "csplugincommon/rendermanager/rendertree.h"
00029 #include "csplugincommon/rendermanager/svarrayholder.h"
00030 #include "csplugincommon/rendermanager/occluvis.h"
00031 
00032 #include "ivideo/graph2d.h"
00033 #include "iengine/sector.h"
00034 
00035 namespace CS
00036 {
00037 namespace RenderManager
00038 {
00043   class BeginFinishDrawScope
00044   {
00045   public:
00046     BeginFinishDrawScope (iGraphics3D* g3d, int drawFlags, bool finishOnEnd = true)
00047       : g3d (g3d), finishOnEnd (finishOnEnd)
00048     {
00049       g3d->BeginDraw (drawFlags);
00050     }
00051 
00052     ~BeginFinishDrawScope ()
00053     {
00054       if (finishOnEnd)
00055         g3d->FinishDraw ();
00056     }
00057 
00058   private:
00059     iGraphics3D* g3d;
00060     bool finishOnEnd;
00061   };
00062 
00063 
00067   template<typename ContextType>
00068   class ContextTargetSetup
00069   {
00070   public:
00071     ContextTargetSetup (iGraphics3D* g3d)
00072       : g3d (g3d)
00073     {
00074     }
00075 
00076     ~ContextTargetSetup ()
00077     {
00078       g3d->FinishDraw ();
00079     }
00080 
00081     void operator() (const ContextType& context)
00082     {
00083       g3d->FinishDraw ();
00084       for (int a = 0; a < rtaNumAttachments; a++)
00085       {
00086         /* @@@ Checking for rtaColor0 is ugly. Eventually, PostEffects
00087             should act on multiple targets at the same time */
00088         if ((csRenderTargetAttachment (a) == rtaColor0)
00089             && (context.postEffects.IsValid()))
00090         {
00091           context.postEffects->SetEffectsOutputTarget (
00092             context.renderTargets[a].texHandle);
00093           g3d->SetRenderTarget (
00094             context.postEffects->GetScreenTarget (), false,
00095             context.renderTargets[a].subtexture, 
00096             csRenderTargetAttachment (a));
00097         }
00098         else
00099           g3d->SetRenderTarget (context.renderTargets[a].texHandle, false,
00100             context.renderTargets[a].subtexture, csRenderTargetAttachment (a));
00101       }
00102     }
00103 
00104   private:
00105     iGraphics3D* g3d;
00106   };
00107 
00109   template<typename RenderTree>
00110   class RenderCommon
00111   {
00112   public:
00113     void SetLayer (size_t layer)
00114     {
00115       currentLayer = layer;
00116     }
00117   protected:
00118     iGraphics3D* g3d;
00119     iShaderManager* shaderMgr;
00120     size_t currentLayer;
00121 
00122     RenderCommon (iGraphics3D* g3d, iShaderManager* shaderMgr)
00123      : g3d (g3d), shaderMgr (shaderMgr), currentLayer (0) {}
00124 
00125     void RenderMeshes (typename RenderTree::ContextNode& context, 
00126                        const typename RenderTree::MeshNode::MeshArrayType& meshes,
00127                        iShader* shader, size_t ticket,
00128                        size_t firstMesh, size_t lastMesh)
00129     {
00130       if (firstMesh == lastMesh)
00131         return;
00132       
00133       // Skip meshes without shader (for current layer)
00134       if (!shader)
00135         return;
00136 
00137       csShaderVariableStack& svStack = shaderMgr->GetShaderVariableStack ();
00138 
00139       const size_t numPasses = shader->GetNumberOfPasses (ticket);
00140 
00141       for (size_t p = 0; p < numPasses; ++p)
00142       {
00143         if (!shader->ActivatePass (ticket, p)) continue;
00144 
00145         for (size_t m = firstMesh; m < lastMesh; ++m)
00146         {
00147           const typename RenderTree::MeshNode::SingleMesh& mesh = meshes.Get (m);
00148           context.svArrays.SetupSVStack (svStack, currentLayer, mesh.contextLocalId);
00149 
00150           csRenderMeshModes modes (*mesh.renderMesh);
00151           if (!shader->SetupPass (ticket, mesh.renderMesh, modes, svStack)) continue;
00152           modes.z_buf_mode = mesh.zmode;
00153 
00154           g3d->DrawMesh (mesh.renderMesh, modes, svStack);
00155 
00156           shader->TeardownPass (ticket);
00157         }
00158         shader->DeactivatePass (ticket);
00159       }
00160     }
00161   };
00162 
00169   template<typename RenderTree>
00170   class SimpleContextRender : public RenderCommon<RenderTree>
00171   {
00172   public:
00173     SimpleContextRender (iGraphics3D* g3d, iShaderManager* shaderMgr)
00174       : RenderCommon<RenderTree> (g3d, shaderMgr)
00175     {}
00176     
00177     void operator() (typename RenderTree::MeshNode* node)
00178     {
00179       typename RenderTree::ContextNode& context = node->GetOwner();
00180       const size_t layerOffset = context.totalRenderMeshes*this->currentLayer;
00181 
00182       iShader* lastShader = 0;
00183       size_t lastTicket = ~0;
00184       size_t lastRenderedMesh = 0;
00185 
00186       for (size_t m = 0; m < node->meshes.GetSize (); ++m)
00187       {
00188         typename RenderTree::MeshNode::SingleMesh& mesh = node->meshes.Get (m);
00189         iShader* shader = context.shaderArray[mesh.contextLocalId+layerOffset];
00190         
00191         size_t ticket = context.ticketArray[mesh.contextLocalId+layerOffset];
00192 
00193         if (shader != lastShader || ticket != lastTicket
00194             || (mesh.preCopyNum != 0))
00195         {
00196           // Render the latest batch of meshes
00197           RenderMeshes (context, node->meshes, lastShader, lastTicket, lastRenderedMesh, m);
00198           lastRenderedMesh = m;
00199 
00200           lastShader = shader;
00201           lastTicket = ticket;
00202         }
00203         
00204         if (mesh.preCopyNum != 0)
00205         {
00206           this->g3d->CopyFromRenderTargets (mesh.preCopyNum,
00207             mesh.preCopyAttachments, mesh.preCopyTextures);
00208         }
00209       }
00210 
00211       RenderMeshes (context, node->meshes, lastShader, lastTicket, lastRenderedMesh, node->meshes.GetSize ());
00212     }
00213   };
00214 
00218   template<typename RenderTree>
00219   class SimpleContextRenderByMesh : public RenderCommon<RenderTree>
00220   {
00221   public:
00222     SimpleContextRenderByMesh (iGraphics3D* g3d, iShaderManager* shaderMgr)
00223       : RenderCommon<RenderTree> (g3d, shaderMgr)
00224     {}
00225     
00226     void operator() (typename RenderTree::MeshNode* node)
00227     {
00228       typename RenderTree::ContextNode& context = node->GetOwner();
00229       for (size_t m = 0; m < node->meshes.GetSize (); ++m)
00230       {
00231         typename RenderTree::MeshNode::SingleMesh& mesh = node->meshes.Get (m);
00232         if (mesh.preCopyNum != 0)
00233         {
00234           this->g3d->CopyFromRenderTargets (mesh.preCopyNum,
00235             mesh.preCopyAttachments, mesh.preCopyTextures);
00236         }
00237         for (size_t layer = 0; layer < context.svArrays.GetNumLayers(); layer++)
00238         {
00239           this->SetLayer (layer);
00240           const size_t layerOffset = context.totalRenderMeshes*layer;
00241 
00242           iShader* shader = context.shaderArray[mesh.contextLocalId+layerOffset];
00243         
00244           size_t ticket = context.ticketArray[mesh.contextLocalId+layerOffset];
00245           RenderMeshes (context, node->meshes, shader, ticket, m, m+1);
00246         }
00247       }
00248     }
00249   };
00250 
00251   template<typename RenderTree>
00252   struct OperationTraits<SimpleContextRender<RenderTree> >
00253   {
00254     typedef OperationUnordered Ordering;
00255   };
00256 
00278   template<typename RenderTree>
00279   class SimpleTreeRenderer
00280   {
00281   public:
00282     SimpleTreeRenderer (iGraphics3D* g3di, iShaderManager* shaderMgri)
00283       : targetSetup (g3di),
00284         meshRender (g3di, shaderMgri),
00285         meshRenderByMesh (g3di, shaderMgri),
00286       g3d (g3di), shaderMgr (shaderMgri), lastRenderView (0)
00287     {
00288       memset (lastTarget, 0, sizeof (lastTarget));
00289       memset (lastSubtexture, 0, sizeof (lastSubtexture));
00290     }
00291 
00292     ~SimpleTreeRenderer ()
00293     {
00294       // Render any remaining contexts
00295       RenderContextStack ();
00296     }
00297 
00298     void operator() (size_t i, typename RenderTree::ContextNode* context)
00299     {
00300       // Make sure right target is set
00301       if (IsNew (*context))
00302       {
00303         // New context, render out the old ones
00304         RenderContextStack ();
00305         for (int a = 0; a < rtaNumAttachments; a++)
00306         {
00307           lastTarget[a] = context->renderTargets[a].texHandle;
00308           lastSubtexture[a] = context->renderTargets[a].subtexture;
00309         }
00310         lastRenderView = context->renderView;
00311       }
00312 
00313       // Push the context
00314       contextStack.Push (context);      
00315     }
00316    
00317   private:
00318 
00324     void RenderContextStack ()
00325     {
00326       if (contextStack.IsEmpty ())
00327         return;
00328 
00329       // Setup context from first entry
00330       typename RenderTree::ContextNode* context = contextStack.Get (0);
00331 
00332       targetSetup (*context);
00333 
00334       RenderView* rview = context->renderView;
00335 
00336       int drawFlags = CSDRAW_3DGRAPHICS;
00337       drawFlags |= context->drawFlags;
00338 
00339       iCamera* cam = rview->GetCamera ();
00340       iClipper2D* clipper = rview->GetClipper ();
00341 
00342       if (context->owner.IsDebugClearEnabled())
00343       {
00344         iGraphics2D* G2D = g3d->GetDriver2D();
00345         g3d->BeginDraw (CSDRAW_2DGRAPHICS | CSDRAW_CLEARZBUFFER);
00346         int bgcolor_clear = G2D->FindRGB (0, 255, 255);
00347         G2D->Clear (bgcolor_clear);
00348       }
00349       
00350       // Setup the camera etc.. @@should be delayed as well
00351       g3d->SetProjectionMatrix (
00352         context->perspectiveFixup * cam->GetProjectionMatrix ());
00353       g3d->SetClipper (clipper, CS_CLIPPER_TOPLEVEL);
00354 
00355       BeginFinishDrawScope bd (g3d, drawFlags);
00356 
00357       // Any rendering required for visculling needs to be done once only per sector.
00358       csArray<iSector*> sectors;
00359       for (size_t c = 0; c < contextStack.GetSize (); ++c)
00360       {
00361         typename RenderTree::ContextNode* ctx = contextStack[c];
00362 
00363         size_t numSectors = sectors.GetSize ();
00364         if (sectors.PushSmart (ctx->sector) == numSectors)
00365         {
00366           g3d->SetWorldToCamera (ctx->cameraTransform.GetInverse ());
00367           ctx->sector->GetVisibilityCuller ()->RenderViscull (rview, ctx->shadervars);
00368         }
00369       }
00370 
00371       // Detect subsequent contexts with same grouping
00372       size_t firstContext = 0;
00373       CS::RenderPriorityGrouping lastGrouping = CS::rpgByLayer;
00374       for (size_t c = 0; c < contextStack.GetSize (); ++c)
00375       {
00376         if (contextStack[c]->renderGrouping != lastGrouping)
00377         {
00378           // Render context 'stretches' with same grouping
00379           if (lastGrouping == CS::rpgByMesh)
00380             RenderGroupedByMesh (rview, firstContext, c);
00381           else
00382             RenderGroupedByLayer (rview, firstContext, c);
00383           firstContext = c;
00384           lastGrouping = contextStack[c]->renderGrouping;
00385         }
00386       }
00387       if (lastGrouping == CS::rpgByMesh)
00388         RenderGroupedByMesh (rview, firstContext, contextStack.GetSize ());
00389       else
00390         RenderGroupedByLayer (rview, firstContext, contextStack.GetSize ());
00391 
00392       /* @@@ FIXME: When switching from RT to screen with a clipper set
00393          the clip rect gets wrong (stays at RT size). This workaround ensures
00394          that no "old" clip rect is stored which is restored later.
00395          Should really be fixed in the renderer. */
00396       g3d->SetClipper (0, CS_CLIPPER_TOPLEVEL);
00397 
00398       contextStack.Empty ();
00399       
00400       if (context->postEffects.IsValid())
00401         context->postEffects->DrawPostEffects (context->owner);
00402     }
00403 
00404     void RenderGroupedByLayer (RenderView* rview, size_t firstContext, size_t lastContext)
00405     {
00406       /* Different contexts may have different numbers of layers,
00407        * so determine the upper layer number */
00408       size_t maxLayer = 0;
00409       for (size_t i = firstContext; i < lastContext; ++i)
00410       {
00411         maxLayer = csMax (maxLayer,
00412           contextStack[i]->svArrays.GetNumLayers());
00413       }
00414 
00415       // Render all mesh nodes in context
00416       for (size_t layer = 0; layer < maxLayer; ++layer)
00417       {
00418         meshRender.SetLayer (layer);
00419 
00420         for (size_t i = firstContext; i < lastContext; ++i)
00421         {
00422           typename RenderTree::ContextNode* context = contextStack.Get (i);
00423           /* Bail out if layer index is above the actual layer count in the
00424           * context */
00425           if (layer >= context->svArrays.GetNumLayers()) continue;
00426           g3d->SetWorldToCamera (context->cameraTransform.GetInverse ());
00427           ForEachMeshNode (*context, meshRender);
00428         }
00429       }
00430     }
00431 
00432     void RenderGroupedByMesh (RenderView* rview, size_t firstContext, size_t lastContext)
00433     {
00434       for (size_t i = firstContext; i < lastContext; ++i)
00435       {
00436         typename RenderTree::ContextNode* context = contextStack.Get (i);
00437         g3d->SetWorldToCamera (context->cameraTransform.GetInverse ());
00438         ForEachMeshNode (*context, meshRenderByMesh);
00439       }
00440     }
00441 
00442 
00443     bool IsNew (const typename RenderTree::ContextNode& context)
00444     {
00445       for (int a = 0; a < rtaNumAttachments; a++)
00446       {
00447         if ((lastTarget[a] != context.renderTargets[a].texHandle)
00448             || (lastSubtexture[a] != context.renderTargets[a].subtexture))
00449           return true;
00450       }
00451       return context.renderView != lastRenderView;
00452     }
00453 
00454     ContextTargetSetup<typename RenderTree::ContextNode> targetSetup;
00455     SimpleContextRender<RenderTree> meshRender;
00456     SimpleContextRenderByMesh<RenderTree> meshRenderByMesh;
00457 
00458     iGraphics3D* g3d;
00459     iShaderManager* shaderMgr;
00460 
00461     iTextureHandle* lastTarget[rtaNumAttachments];
00462     int lastSubtexture[rtaNumAttachments];
00463     RenderView* lastRenderView;
00464 
00465     csArray<typename RenderTree::ContextNode*> contextStack;
00466   };
00467 
00468   template<typename RenderTree>
00469   struct OperationTraits<SimpleTreeRenderer<RenderTree> >
00470   {
00471     typedef OperationNumbered Ordering;
00472   };
00473 
00474 
00475 
00476 }
00477 }
00478 
00479 #endif

Generated for Crystal Space 2.0 by doxygen 1.7.6.1