csplugincommon/rendermanager/portalsetup.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/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