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.6.1