CrystalSpace

Public API Reference

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