csplugincommon/rendermanager/portalsetup.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_PORTALSETUP_H__ 00020 #define __CS_CSPLUGINCOMMON_RENDERMANAGER_PORTALSETUP_H__ 00021 00026 #include "iengine/movable.h" 00027 #include "iengine/portal.h" 00028 #include "iengine/portalcontainer.h" 00029 #include "iengine/sector.h" 00030 #include "csgeom/math3d.h" 00031 #include "csgeom/polyclip.h" 00032 #include "csgfx/renderbuffer.h" 00033 #include "csgfx/shadervarcontext.h" 00034 #include "cstool/rbuflock.h" 00035 00036 #include "csplugincommon/rendermanager/renderview.h" 00037 #include "csplugincommon/rendermanager/svsetup.h" 00038 #include "csplugincommon/rendermanager/texturecache.h" 00039 00040 namespace CS 00041 { 00042 namespace RenderManager 00043 { 00049 class CS_CRYSTALSPACE_EXPORT StandardPortalSetup_Base 00050 { 00051 public: 00057 struct CS_CRYSTALSPACE_EXPORT PersistentData 00058 { 00059 00063 struct PortalBuffers 00064 { 00065 csRef<iRenderBuffer> coordBuf; 00066 csRef<iRenderBuffer> tcBuf; 00067 csRef<iRenderBuffer> indexBuf; 00068 csRef<csRenderBufferHolder> holder; 00069 }; 00070 00074 struct CS_CRYSTALSPACE_EXPORT PortalBufferConstraint 00075 { 00076 typedef size_t KeyType; 00077 00078 static bool IsEqual (const PortalBuffers& b1, 00079 const PortalBuffers& b2); 00080 static bool IsLargerEqual (const PortalBuffers& b1, 00081 const PortalBuffers& b2); 00082 00083 static bool IsEqual (const PortalBuffers& b1, 00084 const KeyType& s2); 00085 static bool IsLargerEqual (const PortalBuffers& b1, 00086 const KeyType& s2); 00087 static bool IsLargerEqual (const KeyType& s1, 00088 const PortalBuffers& b2); 00089 }; 00090 CS::Utility::GenericResourceCache<PortalBuffers, csTicks, 00091 PortalBufferConstraint> bufCache; 00092 00093 struct BoxClipperCacheRefCounted; 00097 struct CS_CRYSTALSPACE_EXPORT csBoxClipperCached : public csBoxClipper 00098 { 00099 BoxClipperCacheRefCounted* owningCache; 00100 00101 csBoxClipperCached (BoxClipperCacheRefCounted* owningCache, 00102 const csBox2& box) : csBoxClipper (box), 00103 owningCache (owningCache) 00104 { } 00105 00106 void operator delete (void* p, void* q); 00107 void operator delete (void* p); 00108 }; 00109 struct csBoxClipperCachedStore 00110 { 00111 uint bytes[(sizeof(csBoxClipperCached) + sizeof (uint) - 1)/sizeof(uint)]; 00112 00113 csBoxClipperCachedStore() 00114 { 00115 // Avoid gcc complaining about uninitialised use 00116 memset (bytes, 0, sizeof (bytes)); 00117 } 00118 }; 00119 typedef CS::Utility::GenericResourceCache<csBoxClipperCachedStore, csTicks, 00120 CS::Utility::ResourceCache::SortingNone, 00121 CS::Utility::ResourceCache::ReuseConditionFlagged> BoxClipperCacheType; 00122 struct BoxClipperCacheRefCounted : public BoxClipperCacheType, 00123 public CS::Utility::FastRefCount<BoxClipperCacheRefCounted> 00124 { 00125 BoxClipperCacheRefCounted ( 00126 const CS::Utility::ResourceCache::ReuseConditionFlagged& reuse, 00127 const CS::Utility::ResourceCache::PurgeConditionAfterTime<uint>& purge) 00128 : BoxClipperCacheType (reuse, purge) {} 00129 00130 void FreeCachedClipper (csBoxClipperCached* bcc); 00131 }; 00132 csRef<BoxClipperCacheRefCounted> boxClipperCache; 00133 00134 CS::ShaderVarStringID svNameTexPortal; 00135 #ifdef CS_DEBUG 00136 csFrameDataHolder<csStringBase> stringHolder; 00137 #endif 00138 00139 TextureCache texCache; 00140 00141 /* Set these values to a positive value to fix the width and/or height of textures 00142 * queried from the texture cache. */ 00143 int fixedTexCacheWidth; 00144 int fixedTexCacheHeight; 00145 00147 iTextureHandle* QueryUnusedTexture (int width, int height, 00148 int& real_w, int& real_h) 00149 { 00150 if (fixedTexCacheWidth > 0) 00151 width = fixedTexCacheWidth; 00152 if (fixedTexCacheHeight > 0) 00153 height = fixedTexCacheHeight; 00154 00155 return texCache.QueryUnusedTexture (width, height, 00156 real_w, real_h); 00157 } 00158 00159 uint dbgDrawPortalOutlines; 00160 uint dbgDrawPortalPlanes; 00161 uint dbgShowPortalTextures; 00162 00164 PersistentData(int textCachOptions = TextureCache::tcachePowerOfTwo); 00165 00170 void Initialize (iShaderManager* shmgr, iGraphics3D* g3d, 00171 RenderTreeBase::DebugPersistent& dbgPersist); 00172 00177 void UpdateNewFrame () 00178 { 00179 csTicks time = csGetTicks (); 00180 texCache.AdvanceFrame (time); 00181 bufCache.AdvanceTime (time); 00182 boxClipperCache->AdvanceTime (time); 00183 } 00184 }; 00185 00186 StandardPortalSetup_Base (PersistentData& persistentData) 00187 : persistentData (persistentData) 00188 {} 00189 protected: 00190 PersistentData& persistentData; 00191 00192 void PortalDebugDraw (RenderTreeBase& renderTree, 00193 iPortal* portal, 00194 size_t count, const csVector2* portalVerts2d, 00195 const csVector3* portalVerts3d, 00196 int screenH, 00197 bool isSimple, int skipRec); 00198 00200 csPtr<iClipper2D> CreateBoxClipper(const csBox2& box); 00201 00203 void SetupProjectionShift (iCustomMatrixCamera* newCam, 00204 iCamera* inewcam, 00205 int sb_minX, int sb_minY, 00206 int txt_h, 00207 int real_w, int real_h, 00208 int screenW, int screenH); 00213 void FudgeTargetCamera (iCamera* inewcam, iCamera* cam, 00214 iPortal* portal, const csFlags& portalFlags, 00215 size_t count, const csVector2* portalVerts2d, 00216 const csVector3* portalVerts3d, 00217 int screenW, int screenH); 00218 00220 csPtr<csRenderBufferHolder> GetPortalBuffers (size_t count, 00221 const csVector2* portalVerts2d, 00222 const csVector3* portalVerts3d, 00223 bool withTCs = false, 00224 int txt_h = 0, 00225 int real_w = 0, int real_h = 0, 00226 int sb_minX = 0, int sb_minY = 0); 00227 00229 csRenderMesh* SetupPortalRM (csRenderMesh* rm, 00230 iPortal* portal, iSector* sector, 00231 size_t count, RenderView* rview); 00232 }; 00233 00278 template<typename RenderTreeType, typename ContextSetup> 00279 class StandardPortalSetup : public StandardPortalSetup_Base 00280 { 00281 public: 00282 typedef StandardPortalSetup<RenderTreeType, ContextSetup> ThisType; 00283 00288 struct ContextSetupData 00289 { 00290 typename RenderTreeType::ContextNode* lastSimplePortalCtx; 00291 00293 ContextSetupData (typename RenderTreeType::ContextNode* last = 0) 00294 : lastSimplePortalCtx (last) 00295 {} 00296 }; 00297 00299 StandardPortalSetup (PersistentData& persistentData, ContextSetup& cfun) 00300 : StandardPortalSetup_Base (persistentData), contextFunction (cfun) 00301 {} 00302 00307 void operator() (typename RenderTreeType::ContextNode& context, 00308 ContextSetupData& setupData) 00309 { 00310 RenderView* rview = context.renderView; 00311 RenderTreeType& renderTree = context.owner; 00312 int screenW, screenH; 00313 if (!context.GetTargetDimensions (screenW, screenH)) 00314 { 00315 screenW = rview->GetGraphics3D()->GetWidth(); 00316 screenH = rview->GetGraphics3D()->GetHeight(); 00317 } 00318 00319 bool debugDraw = 00320 renderTree.IsDebugFlagEnabled (persistentData.dbgDrawPortalOutlines) 00321 || renderTree.IsDebugFlagEnabled (persistentData.dbgDrawPortalPlanes); 00322 00323 csDirtyAccessArray<csVector2> allPortalVerts2d (64); 00324 csDirtyAccessArray<csVector3> allPortalVerts3d (64); 00325 csDirtyAccessArray<size_t> allPortalVertsNums; 00326 // Handle all portals 00327 for (size_t pc = 0; pc < context.allPortals.GetSize (); ++pc) 00328 { 00329 typename RenderTreeType::ContextNode::PortalHolder& holder = context.allPortals[pc]; 00330 const size_t portalCount = holder.portalContainer->GetPortalCount (); 00331 00332 size_t allPortalVertices = holder.portalContainer->GetTotalVertexCount (); 00333 allPortalVerts2d.SetSize (allPortalVertices * 3); 00334 allPortalVerts3d.SetSize (allPortalVertices * 3); 00335 allPortalVertsNums.SetSize (portalCount); 00336 00337 csVector2* portalVerts2d = allPortalVerts2d.GetArray(); 00338 csVector3* portalVerts3d = allPortalVerts3d.GetArray(); 00339 /* Get clipped screen space and camera space vertices */ 00340 holder.portalContainer->ComputeScreenPolygons (rview, 00341 portalVerts2d, portalVerts3d, 00342 allPortalVerts2d.GetSize(), allPortalVertsNums.GetArray(), 00343 screenW, screenH); 00344 00345 for (size_t pi = 0; pi < portalCount; ++pi) 00346 { 00347 iPortal* portal = holder.portalContainer->GetPortal (int (pi)); 00348 const csFlags portalFlags (portal->GetFlags()); 00349 00350 // Finish up the sector 00351 if (!portal->CompleteSector (rview)) 00352 continue; 00353 00354 size_t count = allPortalVertsNums[pi]; 00355 if (count == 0) continue; 00356 00357 iSector* sector = portal->GetSector (); 00358 bool skipRec = sector->GetRecLevel() >= portal->GetMaximumSectorVisit(); 00359 00360 if (debugDraw) 00361 { 00362 bool isSimple = IsSimplePortal (portalFlags); 00363 PortalDebugDraw (renderTree, portal, 00364 count, portalVerts2d, portalVerts3d, 00365 screenH, isSimple, skipRec); 00366 } 00367 00368 if (!skipRec) 00369 { 00370 sector->IncRecLevel(); 00371 if (IsSimplePortal (portalFlags)) 00372 { 00373 SetupSimplePortal (context, setupData, portal, sector, 00374 portalVerts2d, portalVerts3d, count, screenW, screenH, holder); 00375 } 00376 else 00377 { 00378 SetupHeavyPortal (context, setupData, portal, sector, 00379 portalVerts2d, portalVerts3d, count, screenW, screenH, holder); 00380 } 00381 sector->DecRecLevel(); 00382 } 00383 00384 portalVerts2d += count; 00385 portalVerts3d += count; 00386 } 00387 } 00388 } 00389 00390 private: 00391 ContextSetup& contextFunction; 00392 00393 bool IsSimplePortal (const csFlags& portalFlags) 00394 { 00395 return (portalFlags.Get() & (CS_PORTAL_CLIPDEST 00396 | CS_PORTAL_CLIPSTRADDLING 00397 | CS_PORTAL_ZFILL 00398 | CS_PORTAL_MIRROR 00399 | CS_PORTAL_FLOAT)) == 0; 00400 } 00401 00402 void ComputeVector2BoundingBox (const csVector2* verts, size_t count, 00403 csBox2& box) 00404 { 00405 if (count == 0) 00406 { 00407 box.StartBoundingBox (); 00408 return; 00409 } 00410 box.StartBoundingBox (verts[0]); 00411 for (size_t i = 1; i < count; i++) 00412 box.AddBoundingVertexSmart (verts[i]); 00413 } 00414 00415 void SetupWarp (iCamera* inewcam, iMovable* movable, iPortal* portal) 00416 { 00417 const csReversibleTransform& movtrans = movable->GetFullTransform(); 00418 bool mirror = inewcam->IsMirrored (); 00419 csReversibleTransform warp_wor; 00420 portal->ObjectToWorld (movtrans, warp_wor); 00421 portal->WarpSpace (warp_wor, inewcam->GetTransform (), mirror); 00422 inewcam->SetMirrored (mirror); 00423 } 00424 00425 void SetupSimplePortal ( 00426 typename RenderTreeType::ContextNode& context, 00427 ContextSetupData& setupData, iPortal* portal, iSector* sector, 00428 const csVector2* portalVerts2d, const csVector3* portalVerts3d, size_t count, 00429 int screenW, int screenH, 00430 typename RenderTreeType::ContextNode::PortalHolder& holder) 00431 { 00432 RenderView* rview = context.renderView; 00433 RenderTreeType& renderTree = context.owner; 00434 const csFlags portalFlags (portal->GetFlags()); 00435 00436 // Setup simple portal 00437 rview->CreateRenderContext (); 00438 rview->SetLastPortal (portal); 00439 rview->SetPreviousSector (rview->GetThisSector ()); 00440 rview->SetThisSector (sector); 00441 csPolygonClipper newView (portalVerts2d, count); 00442 rview->SetViewDimensions (screenW, screenH); 00443 rview->SetClipper (&newView); 00444 00445 if (portalFlags.Check (CS_PORTAL_WARP)) 00446 { 00447 iCamera *inewcam = rview->CreateNewCamera (); 00448 SetupWarp (inewcam, holder.meshWrapper->GetMovable(), portal); 00449 } 00450 00451 typename RenderTreeType::ContextNode* portalCtx = 00452 renderTree.CreateContext (rview, setupData.lastSimplePortalCtx); 00453 setupData.lastSimplePortalCtx = portalCtx; 00454 00455 // Copy the target from last portal 00456 for (int a = 0; a < rtaNumAttachments; a++) 00457 portalCtx->renderTargets[a] = context.renderTargets[a]; 00458 portalCtx->perspectiveFixup = context.perspectiveFixup; 00459 00460 // Setup the new context 00461 contextFunction (*portalCtx, setupData); 00462 00463 rview->RestoreRenderContext (); 00464 00465 /* Create render mesh for the simple portal. Required to so simple 00466 * portals in fogged sectors look right. */ 00467 if (rview->GetThisSector()->HasFog()) 00468 { 00469 // Synthesize a render mesh for the portal plane 00470 bool meshCreated; 00471 csRenderMesh* rm = renderTree.GetPersistentData().rmHolder.GetUnusedMesh ( 00472 meshCreated, rview->GetCurrentFrameNumber()); 00473 SetupPortalRM (rm, portal, sector, count, rview); 00474 rm->buffers = GetPortalBuffers (count, portalVerts2d, portalVerts3d, 00475 false); 00476 rm->variablecontext.Invalidate(); 00477 00478 typename RenderTreeType::MeshNode::SingleMesh sm; 00479 sm.meshObjSVs = 0; 00480 00481 CS::Graphics::RenderPriority renderPrio = 00482 holder.meshWrapper->GetRenderPriority (); 00483 context.AddRenderMesh (rm, renderPrio, sm); 00484 } 00485 } 00486 00487 void SetupHeavyPortal ( 00488 typename RenderTreeType::ContextNode& context, 00489 ContextSetupData& setupData, iPortal* portal, iSector* sector, 00490 csVector2* portalVerts2d, csVector3* portalVerts3d, size_t count, 00491 int screenW, int screenH, 00492 typename RenderTreeType::ContextNode::PortalHolder& holder) 00493 { 00494 RenderView* rview = context.renderView; 00495 RenderTreeType& renderTree = context.owner; 00496 const csFlags portalFlags (portal->GetFlags()); 00497 00498 // Setup a bounding box, in screen-space 00499 csBox2 screenBox; 00500 ComputeVector2BoundingBox (portalVerts2d, count, screenBox); 00501 00502 // Obtain a texture handle for the portal to render to 00503 int sb_minX = int (screenBox.MinX()); 00504 int sb_minY = int (screenBox.MinY()); 00505 int txt_w = int (ceil (screenBox.MaxX() - screenBox.MinX())); 00506 int txt_h = int (ceil (screenBox.MaxY() - screenBox.MinY())); 00507 int real_w, real_h; 00508 csRef<iTextureHandle> tex = persistentData.QueryUnusedTexture (txt_w, txt_h, 00509 real_w, real_h); 00510 00511 if (renderTree.IsDebugFlagEnabled (persistentData.dbgShowPortalTextures)) 00512 renderTree.AddDebugTexture (tex, (float)real_w/(float)real_h); 00513 00514 iCamera* cam = rview->GetCamera(); 00515 // Create a new view 00516 csRef<CS::RenderManager::RenderView> newRenderView; 00517 csRef<iCustomMatrixCamera> newCam (rview->GetEngine()->CreateCustomMatrixCamera (cam)); 00518 iCamera* inewcam = newCam->GetCamera(); 00519 newRenderView = renderTree.GetPersistentData().renderViews.GetRenderView (rview, portal, inewcam); 00520 newRenderView->SetEngine (rview->GetEngine ()); 00521 00522 if (portalFlags.Check (CS_PORTAL_WARP)) 00523 { 00524 SetupWarp (inewcam, holder.meshWrapper->GetMovable(), portal); 00525 } 00526 00527 SetupProjectionShift (newCam, inewcam, sb_minX, sb_minY, txt_h, 00528 real_w, real_h, screenW, screenH); 00529 FudgeTargetCamera (inewcam, cam, 00530 portal, portalFlags, count, portalVerts2d, portalVerts3d, 00531 screenW, screenH); 00532 00533 // Add a new context with the texture as the target 00534 // Setup simple portal 00535 newRenderView->SetLastPortal (portal); 00536 newRenderView->SetPreviousSector (rview->GetThisSector ()); 00537 newRenderView->SetThisSector (sector); 00538 newRenderView->SetViewDimensions (real_w, real_h); 00539 /* @@@ FIXME Without the +1 pixels of the portal stay unchanged upon 00540 * rendering */ 00541 csBox2 clipBox (0, real_h - (txt_h+1), txt_w+1, real_h); 00542 csRef<iClipper2D> newView (CreateBoxClipper (clipBox)); 00543 /* @@@ Consider PolyClipper? 00544 A box has an advantage when the portal tex is rendered 00545 distorted: texels from outside the portal area still have a 00546 good color. May not be the case with a (more exact) poly 00547 clipper. */ 00548 newRenderView->SetClipper (newView); 00549 00550 typename RenderTreeType::ContextNode* portalCtx = 00551 renderTree.CreateContext (newRenderView); 00552 portalCtx->renderTargets[rtaColor0].texHandle = tex; 00553 00554 // Setup the new context 00555 ContextSetupData newSetup (portalCtx); 00556 contextFunction (*portalCtx, newSetup); 00557 00558 // Synthesize a render mesh for the portal plane 00559 csRef<csShaderVariableContext> svc; 00560 svc.AttachNew (new csShaderVariableContext); 00561 csRef<csShaderVariable> svTexPortal = 00562 svc->GetVariableAdd (persistentData.svNameTexPortal); 00563 svTexPortal->SetValue (tex); 00564 00565 bool meshCreated; 00566 csRenderMesh* rm = renderTree.GetPersistentData().rmHolder.GetUnusedMesh ( 00567 meshCreated, rview->GetCurrentFrameNumber()); 00568 SetupPortalRM (rm, portal, sector, count, rview); 00569 rm->buffers = GetPortalBuffers (count, portalVerts2d, portalVerts3d, 00570 true, txt_h, real_w, real_h, 00571 sb_minX, sb_minY); 00572 rm->variablecontext = svc; 00573 00574 typename RenderTreeType::MeshNode::SingleMesh sm; 00575 sm.meshObjSVs = 0; 00576 00577 CS::Graphics::RenderPriority renderPrio = 00578 holder.meshWrapper->GetRenderPriority (); 00579 context.AddRenderMesh (rm, renderPrio, sm); 00580 } 00581 00582 }; 00583 00584 } // namespace RenderManager 00585 } // namespace CS 00586 00587 #endif // __CS_CSPLUGINCOMMON_RENDERMANAGER_CONTEXT_H__ 00588
Generated for Crystal Space 2.0 by doxygen 1.6.1