csplugincommon/rendermanager/render.h Source File (Crystal Space 2.0 Public API Reference)

| ## Public API Reference

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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