1
0
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-17 10:52:46 +00:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
JWPlatt
2011-03-12 12:34:52 -05:00
commit a20a222fc2
3976 changed files with 1301355 additions and 0 deletions

View File

@ -0,0 +1,186 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plCullPoly.h"
#include "hsMatrix44.h"
#include "hsStream.h"
#include "hsFastMath.h"
plCullPoly& plCullPoly::InitFromVerts(UInt32 f)
{
fFlags = f;
hsAssert(fVerts.GetCount() > 2, "Initializing from degenerate poly");
hsVector3 a;
hsVector3 b;
a.Set(&fVerts[1], &fVerts[0]);
b.Set(&fVerts[2], &fVerts[0]);
fNorm = a % b;
hsFastMath::Normalize(fNorm);
fDist = -(fNorm.InnerProduct(fVerts[0]));
fCenter.Set(0,0,0);
int i;
for( i = 0; i < fVerts.GetCount(); i++ )
{
fCenter += fVerts[i];
}
fCenter *= 1.f / hsScalar(fVerts.GetCount());
fRadius = ICalcRadius();
return *this;
}
hsScalar plCullPoly::ICalcRadius() const
{
hsScalar radSq = 0;
int i;
for( i = 0; i < fVerts.GetCount(); i++ )
{
hsScalar tmpSq = hsVector3(&fVerts[i], &fCenter).MagnitudeSquared();
if( tmpSq > radSq )
radSq = tmpSq;
}
return radSq * hsFastMath::InvSqrt(radSq);
}
plCullPoly& plCullPoly::Flip(const plCullPoly& p)
{
fFlags = p.fFlags;
fNorm = -p.fNorm;
fDist = -p.fDist;
fCenter = p.fCenter;
fRadius = p.fRadius;
int n = p.fVerts.GetCount();
fVerts.SetCount(n);
int i;
for( i = 0; i < n; i++ )
fVerts[n-i-1] = p.fVerts[i];
return *this;
}
plCullPoly& plCullPoly::Transform(const hsMatrix44& l2w, const hsMatrix44& w2l, plCullPoly& dst) const
{
hsMatrix44 tpose;
w2l.GetTranspose(&tpose);
dst.fFlags = fFlags;
dst.fVerts.SetCount(fVerts.GetCount());
int i;
for( i = 0; i < fVerts.GetCount(); i++ )
{
dst.fVerts[i] = l2w * fVerts[i];
}
dst.fCenter = l2w * fCenter;
dst.fNorm = tpose * fNorm;
dst.fDist = -(dst.fNorm .InnerProduct(dst.fVerts[0]));
ICalcRadius();
return dst;
}
void plCullPoly::Read(hsStream* s, hsResMgr* mgr)
{
fFlags = s->ReadSwap32();
fNorm.Read(s);
fDist = s->ReadSwapScalar();
fCenter.Read(s);
fRadius = s->ReadSwapScalar();
int n = s->ReadSwap32();
fVerts.SetCount(n);
int i;
for( i = 0; i < n; i++ )
fVerts[i].Read(s);
}
void plCullPoly::Write(hsStream* s, hsResMgr* mgr)
{
s->WriteSwap32(fFlags);
fNorm.Write(s);
s->WriteSwapScalar(fDist);
fCenter.Write(s);
s->WriteSwapScalar(fRadius);
s->WriteSwap32(fVerts.GetCount());
int i;
for( i = 0; i < fVerts.GetCount(); i++ )
fVerts[i].Write(s);
}
#ifdef HS_DEBUGGING
#define MF_VALIDATE_POLYS
#endif // HS_DEBUGGING
#ifdef MF_VALIDATE_POLYS
hsBool plCullPoly::Validate() const
{
const hsScalar kMinMag = 1.e-8f;
hsScalar magSq = fNorm.MagnitudeSquared();
if( magSq < kMinMag )
return false;
if( fVerts.GetCount() < 3 )
return false;
hsVector3 norm = hsVector3(&fVerts[1], &fVerts[0]) % hsVector3(&fVerts[2], &fVerts[0]);
magSq = norm.MagnitudeSquared();
if( magSq < kMinMag )
return false;
norm *= hsFastMath::InvSqrtAppr(magSq);
int i;
for( i = 3; i < fVerts.GetCount(); i++ )
{
hsVector3 nextNorm = hsVector3(&fVerts[i-1], &fVerts[0]) % hsVector3(&fVerts[i], &fVerts[0]);
magSq = nextNorm.MagnitudeSquared();
if( magSq < kMinMag )
return false;
nextNorm *= hsFastMath::InvSqrtAppr(magSq);
if( nextNorm.InnerProduct(norm) < kMinMag )
return false;
}
return true;
}
#else // MF_VALIDATE_POLYS
hsBool plCullPoly::Validate() const
{
return true;
}
#endif // MF_VALIDATE_POLYS

View File

@ -0,0 +1,82 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plCullPoly_inc
#define plCullPoly_inc
#include "hsTemplates.h"
#include "hsGeometry3.h"
#include "hsBitVector.h"
class hsStream;
class hsResMgr;
struct hsMatrix44;
const hsScalar kCullPolyDegen = 1.e-4f;
class plCullPoly
{
public:
enum {
kNone = 0x0,
kHole = 0x1,
kTwoSided = 0x2
};
UInt32 fFlags;
mutable hsBitVector fClipped; // fClipped[i] => edge(fVerts[i], fVerts[(i+1)%n])
hsTArray<hsPoint3> fVerts;
hsVector3 fNorm;
hsScalar fDist;
hsPoint3 fCenter;
hsScalar fRadius;
const hsPoint3& GetCenter() const { return fCenter; }
hsScalar GetRadius() const { return fRadius; }
void SetHole(hsBool on) { if( on )fFlags |= kHole; else fFlags &= ~kHole; }
void SetTwoSided(hsBool on) { if( on )fFlags |= kTwoSided; else fFlags &= ~kTwoSided; }
hsBool IsHole() const { return fFlags & kHole; } // Assumes kHole is 0x1
hsBool IsTwoSided() const { return 0 != (fFlags & kTwoSided); }
plCullPoly& Init(const plCullPoly& p) { fClipped.Clear(); fVerts.SetCount(0); fFlags = p.fFlags; fNorm = p.fNorm; fDist = p.fDist; fCenter = p.fCenter; return *this; }
plCullPoly& Flip(const plCullPoly& p);
plCullPoly& InitFromVerts(UInt32 f=kNone);
hsScalar ICalcRadius() const;
plCullPoly& Transform(const hsMatrix44& l2w, const hsMatrix44& w2l, plCullPoly& dst) const;
void Read(hsStream* s, hsResMgr* mgr);
void Write(hsStream* s, hsResMgr* mgr);
hsBool DegenerateVert(const hsPoint3& p) const { return fVerts.GetCount() && (kCullPolyDegen > hsVector3(&p, &fVerts[fVerts.GetCount()-1]).MagnitudeSquared()); }
hsBool Validate() const; // no-op, except for special debugging circumstances.
};
#endif // plCullPoly_inc

View File

@ -0,0 +1,221 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
void plOccTree::AddPoly(plPolygon* poly)
{
fBasePolys.Append(*poly);
}
void plOccTree::MakeOccTree()
{
if( !fBasePolys.GetCount() )
return;
ISortBasePolys();
int i;
for( i = 0; i < fBasePolys.GetCount(); i++ )
fRoot = IAddPolyRecur(fRoot, fBasePolys[i], false);
fBasePolys.SetCount(0);
}
plOccNode* poOccTree::IMakeSubTree(plOccPoly* poly)
{
plOccNode* nextNode = nil;
plOccNode* lastNode = nil;
int i;
for( i = 0; i < poly->fVerts.GetCount(); i++ )
{
if( poly->fEdgeFlags[i] & plOccPoly::kEdgeClipped )
continue;
nextNode = fNodePool.Append();
nextNode->fFlags = 0;
nextNode->fOutChild = nil;
int j = i+1 < poly->fVerts.GetCount() ? i+1 : 0;
// Need to set the viewplane here. Calc once per base poly and use
// that for fragments?
nextNode->Init(poly->fVerts[i], poly->fVerts[j], fViewPos);
if( nextNode->fInChild = lastChild )
nextNode->fFlags = plOccNode::kHasInChild;
else
{
nextNode->fInChild = fNodePool.Append();
nextNode->fInChild->Init(poly, false);
}
lastNode = nextNode;
}
// If we have no nextNode, all our edges were clipped. In
// that case, we'll just return an "out" leaf.
if( !nextNode )
{
nextNode = fNodePool.Append();
nextNode->fFlags = 0;
nextNode->fInChild = nextNode->fOutChild = nil;
nextNode->Init(poly, true);
}
return nextNode;
}
void plOccNode::Init(const hsPoint3& p0, const hsPoint3& p1, const hsPoint3& pv)
{
hsVector3 v0, v1;
v0.Set(&p0, &pv);
v1.Set(&p1, &pv);
fPlane.fNormal = v0 % v1;
fPlane.fDist = fPlane.fNormal.InnerProduct(v0);
}
void plOccNode::Init(plOccPoly* poly)
{
fPlane = poly->fPlane;
// set the viewplane
fFlags = kIsLeaf;
}
// Adding a poly to a node
// if the node is nil
// IMakeSubTree(poly) replaces the node
// else
// if the node is a leaf
// pitch the poly
// return node (no replacement)
// else
// if poly is inside the node
// recur on node's inner child
// return node (no replacement)
// else
// if poly is ouside the node
// recur on node's outer child
// return node (no replacement)
// else (node splits poly)
// recur on node's inner child
// recur on node's outer child
// return node (no replacement)
// end
//
// Special case - Degenarate poly's can come
// from ITestPoly if an edge of the input poly
// is on the plane. In that case, the function
// will return kSplit, but either inPoly or outPoly
// will have no vertices. That degenerate poly,
// when added to a node, should just be pitched.
//
// Returns new root, in case it changed.
// This assumes polys are being added front to back.
// This function will break the poly into fragments that fit in the
// current planes within the tree. Planes are added when a final fragment
// is added (in IMakeSubTree).
// We count on ITestPoly to properly mark edges which were created by
// clipping, as those won't generate leaf nodes.
plOccNode* plOccTree::IAddPolyRecur(plOccNode* node, plOccPoly* poly)
{
if( !poly->fVerts.GetCount() )
return node;
if( !node )
{
return IMakeSubTree(poly);
}
plOccPoly* inPoly = nil;
plOccPoly* outPoly = nil;
UInt32 test = ITestPoly(node->fPlane, poly, inPoly, outPoly);
switch( test )
{
case kAllIn:
node->fInChild = IAddPolyRecur(node->fInChild, poly);
break;
case kAllOut:
node->fOutChild = IAddPolyRecur(node->fOutChild, poly);
break;
case kSplit:
node->fInChild = IAddPolyRecur(node->fInChild, inPoly);
node->fOutChild = IAddPolyRecur(node->fOutChild, outPoly);
break;
};
return node;
}
hsBool plOccTree::BoundsVisible(const hsBounds3Ext& bnd) const
{
if( !fRoot )
return true;
return fRoot->IBoundsVisible(bnd);
}
hsBool plOccNode::IInChildBoundsVisible(const hsBounds3Ext& bnd) const
{
return fInChild
? fInChild->IBoundsVisible(bnd)
: false;
}
hsBool plOccNode::IOutChildBoundsVisible(const hsBounds3Ext& bnd) const
{
return fOutChild
? fOutChild->IBoundsVisible(bnd)
: true;
}
hsBool plOccNode::IBoundsVisible(const hsBounds3Ext& bnd) const
{
hsPoint2 depth;
bnd.TestPlane(fPlane.fNormal, depth);
if( depth.fX > fPlane.fDist )
{
return IOutChildVisible(bnd);
}
else if( depth.fY < fPlane.fDist )
{
return IInChildVisible(bnd);
}
// here's where it gets wierd. we pass the bounds in
// both directions. if either says it's visible, it's visible.
// doesn't seem like it would work, but you never know.
return IOutChildVisible(bnd) || IInChildVisible(bnd);
}

View File

@ -0,0 +1,164 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plOccTree_inc
#define plOccTree_inc
#include "hsTemplates.h"
#include "hsGeometry3.h"
class plBoundsHierarchy;
class plOccPlane
{
public:
hsVector3 fNormal;
hsScalar fDist;
};
class plOccPoly
{
public:
enum {
kEdgeClipped = 0x1
};
plOccPlane fPlane;
hsTArray<hsPoint3> fVerts;
hsTArray<UInt8> fEdgeFlags; // flag[i] => edge(fVerts[i], fVerts[(i+1)%n])
};
class plOccNode
{
protected:
enum {
kNone = 0x0,
kIsLeaf = 0x1
};
enum {
kAllIn = 0x0,
kAllOut = 0x1,
kSplit = 0x2
};
UInt32 fFlags;
plOccPlane fPolyPlane; // Plane of the poly we came from
plOccPlane fViewPlane; // Plane perp to view dir.
// For an interior node, ViewPlane is for the nearest (to view) point
// on the poly. A bound closer than that will not be occluded by this
// node or any nodes deeper in the tree.
// For a leaf it's the farthest point on the poly. A bound inside this
// plane OR the PolyPlane is occluded.
plOccNode* fInChild;
plOccNode* fOutChild;
};
class plOccTree
{
protected:
enum {
kNone = 0x0,
kNeedsBuild = 0x1
};
UInt8 fFlags;
// Temp pools for building our trees each frame.
hsTArray<plOccPoly> fPolyPool;
hsTArray<plOccPoly> fBasePolys;
// The BSP used to add our polys front to back. This BSP is constant.
plOccNode* fBSP;
// This current frame's view pos and occluder tree.
plOccNode* fRoot;
hsPoint3 fViewPos;
plOccNode* IAddPolyRecur(plOccNode* n, plOccPoly* poly);
void ITrimPoly(plOccPlane& plane, plOccPoly* polyIn, plOccPoly*& polyIn, plOccPoly*& polyOut);
plOccNode* IBuildOccTree();
public:
plOccTree() : fFlags(kNone), fBSP(nil), fRoot(nil) {}
~plOccTree() {}
// We'll take in the view position (for sorting and building).
// The view direction isn't necessary, but may be useful for
// selecting a subset of occluders (like don't bother with ones parallel to the view dir).
// What we really want is to pass in the viewport walls, or all the clip planes to initialize
// the occtree, then occluders out of view are automatically pruned, and the single test
// does the full view/portal/occluder test.
void SetView(const hsPoint3& pos, const hsVector3& dir);
// The algorithm is:
// if bnd is totally inside this node's plane
// recur bnd on inside child/leaf
// else if bnd is totaly outside this node's plane
// recur bnd on outside child
// else
// recur bnd's children on this node
//
// There's two ways to output the visibility info
// 1) Set a visible/invisible bit for each of the bnd leaves
// 2) output a list of visible bnds.
// The second is preferable, since leaves determined invisible by interior
// node tests never get traversed. But if the rendering pipeline has needs
// to traverse the drawable data in some other order (for depth or material
// sorting for example), then the list of visible bnds needs to be translated
// into the first option anyway.
//
// Notes on the vague algorithm:
// When recurring on the inside child, hitting a leaf checks against the source
// occluder poly, with the usual inside=hidden, outside=visible, split recurs
// the bnd's children on this leaf.
// Hitting a nil outside child == visible
// It's a double recursion, recurring first on the bnd hierarchy, and second on the occluder tree.
// Recursion stops when:
// 1) A bnd is totally in or totally out of a leaf of the occluder tree
// 2) A bnd is a leaf of the bnd hierarchy.
//
void TestHeirarchy(plBoundsHierarchy* bnd);
virtual void Read(hsStream* s, hsResMgr* mgr);
virtual void Write(hsStream* s, hsResMgr* mgr);
// Export only
void AddPoly(plOccPoly* poly);
void BuildBSP();
};
#endif // plOccTree_inc

View File

@ -0,0 +1,387 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plOccluder.h"
#include "hsStream.h"
#include "plOccluderProxy.h"
#include "../plDrawable/plDrawableGenerator.h"
#include "../plSurface/hsGMaterial.h"
#include "../plSurface/plLayerInterface.h"
#include "../plSurface/plLayer.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../pnKeyedObject/plKey.h"
#include "hsResMgr.h"
#include "plgDispatch.h"
#include "plVisRegion.h"
#include "plVisMgr.h"
plOccluder::plOccluder()
: fSceneNode(nil)
{
fProxyGen = TRACKED_NEW plOccluderProxy;
fProxyGen->Init(this);
fVisSet.SetBit(0);
}
plOccluder::~plOccluder()
{
delete fProxyGen;
}
hsBool plOccluder::MsgReceive(plMessage* msg)
{
plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef(msg);
if( refMsg )
{
switch( refMsg->fType )
{
case kRefVisRegion:
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
IAddVisRegion(plVisRegion::ConvertNoRef(refMsg->GetRef()));
}
else
{
IRemoveVisRegion(plVisRegion::ConvertNoRef(refMsg->GetRef()));
}
return true;
default:
break;
}
}
return plObjInterface::MsgReceive(msg);
}
void plOccluder::IAddVisRegion(plVisRegion* reg)
{
if( reg )
{
int idx = fVisRegions.Find(reg);
if( fVisRegions.kMissingIndex == idx )
{
fVisRegions.Append(reg);
if( reg->GetProperty(plVisRegion::kIsNot) )
fVisNot.SetBit(reg->GetIndex());
else
{
fVisSet.SetBit(reg->GetIndex());
if( reg->ReplaceNormal() )
fVisSet.ClearBit(plVisMgr::kNormal);
}
}
}
}
void plOccluder::IRemoveVisRegion(plVisRegion* reg)
{
if( reg )
{
int idx = fVisRegions.Find(reg);
if( fVisRegions.kMissingIndex != idx )
{
fVisRegions.Remove(idx);
if( reg->GetProperty(plVisRegion::kIsNot) )
fVisNot.ClearBit(reg->GetIndex());
else
fVisSet.ClearBit(reg->GetIndex());
}
}
}
plDrawableSpans* plOccluder::CreateProxy(hsGMaterial* mat, hsTArray<UInt32>& idx, plDrawableSpans* addTo)
{
hsTArray<hsPoint3> pos;
hsTArray<hsVector3> norm;
hsTArray<hsColorRGBA> color;
hsTArray<UInt16> tris;
plLayer* lay = plLayer::ConvertNoRef(mat->GetLayer(0)->BottomOfStack());
if( lay )
lay->SetMiscFlags(lay->GetMiscFlags() & ~hsGMatState::kMiscTwoSided);
const hsTArray<plCullPoly>& polys = GetLocalPolyList();
int i;
for( i = 0; i < polys.GetCount(); i++ )
{
hsColorRGBA col;
if( polys[i].IsHole() )
col.Set(0,0,0,1.f);
else
col.Set(1.f, 1.f, 1.f, 1.f);
int triStart = tris.GetCount();
int idx0 = pos.GetCount();
pos.Append(polys[i].fVerts[0]);
norm.Append(polys[i].fNorm);
color.Append(col);
pos.Append(polys[i].fVerts[1]);
norm.Append(polys[i].fNorm);
color.Append(col);
int j;
for( j = 2; j < polys[i].fVerts.GetCount(); j++ )
{
int idxCurr = pos.GetCount();
pos.Append(polys[i].fVerts[j]);
norm.Append(polys[i].fNorm);
color.Append(col);
tris.Append(idx0);
tris.Append(idxCurr-1);
tris.Append(idxCurr);
}
#if 1
if( polys[i].IsTwoSided() )
{
int n = tris.GetCount();
while( --n >= triStart )
{
int idx = tris[n];
tris.Append(idx);
}
}
#endif
}
return plDrawableGenerator::GenerateDrawable(pos.GetCount(),
pos.AcquireArray(),
norm.AcquireArray(),
nil, 0,
color.AcquireArray(),
true,
nil,
tris.GetCount(),
tris.AcquireArray(),
mat,
GetLocalToWorld(),
true,
&idx,
addTo);
}
void plOccluder::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
// Commenting out the following asserts. Although they are fundamentally correct,
//essentially identity matrices which aren't so flagged (because of numerical
// precision) are triggering bogus asserts. mf
// hsAssert(l2w.fFlags & hsMatrix44::kIsIdent, "Non-identity transform to non-movable Occluder");
// hsAssert(w2l.fFlags & hsMatrix44::kIsIdent, "Non-identity transform to non-movable Occluder");
}
const hsMatrix44& plOccluder::GetLocalToWorld() const
{
return hsMatrix44::IdentityMatrix();
}
const hsMatrix44& plOccluder::GetWorldToLocal() const
{
return hsMatrix44::IdentityMatrix();
}
void plOccluder::ComputeFromPolys()
{
IComputeBounds();
IComputeSurfaceArea();
}
void plOccluder::IComputeBounds()
{
fWorldBounds.MakeEmpty();
const hsTArray<plCullPoly>& polys = GetLocalPolyList();
int i;
for( i =0 ; i < polys.GetCount(); i++ )
{
int j;
for( j = 0; j < polys[i].fVerts.GetCount(); j++ )
fWorldBounds.Union(&polys[i].fVerts[j]);
}
}
hsScalar plOccluder::IComputeSurfaceArea()
{
hsScalar area = 0;
const hsTArray<plCullPoly>& polys = GetLocalPolyList();
int i;
for( i =0 ; i < polys.GetCount(); i++ )
{
int j;
for( j = 2; j < polys[i].fVerts.GetCount(); j++ )
{
area += (hsVector3(&polys[i].fVerts[j], &polys[i].fVerts[j-2]) % hsVector3(&polys[i].fVerts[j-1], &polys[i].fVerts[j-2])).Magnitude();
}
}
area *= 0.5f;
return fPriority = area;
}
void plOccluder::SetPolyList(const hsTArray<plCullPoly>& list)
{
UInt16 n = list.GetCount();
fPolys.SetCount(n);
int i;
for( i = 0; i < n; i++ )
fPolys[i] = list[i];
}
void plOccluder::ISetSceneNode(plKey node)
{
if( fSceneNode != node )
{
if( node )
{
plNodeRefMsg* refMsg = TRACKED_NEW plNodeRefMsg(node, plRefMsg::kOnCreate, -1, plNodeRefMsg::kOccluder);
hsgResMgr::ResMgr()->AddViaNotify(GetKey(), refMsg, plRefFlags::kPassiveRef);
}
if( fSceneNode )
{
fSceneNode->Release(GetKey());
}
fSceneNode = node;
}
}
void plOccluder::Read(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Read(s, mgr);
fWorldBounds.Read(s);
fPriority = s->ReadSwapScalar();
hsTArray<plCullPoly>& localPolys = IGetLocalPolyList();
UInt16 n = s->ReadSwap16();
localPolys.SetCount(n);
int i;
for( i = 0; i < n; i++ )
localPolys[i].Read(s, mgr);
plKey nodeKey = mgr->ReadKey(s);
ISetSceneNode(nodeKey);
n = s->ReadSwap16();
fVisRegions.SetCountAndZero(n);
for( i = 0; i < n; i++ )
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefVisRegion), plRefFlags::kActiveRef);
}
void plOccluder::Write(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Write(s, mgr);
fWorldBounds.Write(s);
s->WriteSwapScalar(fPriority);
const hsTArray<plCullPoly>& localPolys = IGetLocalPolyList();
s->WriteSwap16(localPolys.GetCount());
int i;
for( i = 0; i < localPolys.GetCount(); i++ )
localPolys[i].Write(s, mgr);
mgr->WriteKey(s, fSceneNode);
s->WriteSwap16(fVisRegions.GetCount());
for( i = 0; i < fVisRegions.GetCount(); i++ )
mgr->WriteKey(s, fVisRegions[i]);
}
plMobileOccluder::plMobileOccluder()
{
fLocalToWorld.Reset();
fWorldToLocal.Reset();
}
plMobileOccluder::~plMobileOccluder()
{
}
void plMobileOccluder::IComputeBounds()
{
plOccluder::IComputeBounds();
fLocalBounds = fWorldBounds;
fWorldBounds.Transform(&fLocalToWorld);
}
void plMobileOccluder::SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
fLocalToWorld = l2w;
fWorldToLocal = w2l;
if( fPolys.GetCount() != fOrigPolys.GetCount() )
fPolys.SetCount(fOrigPolys.GetCount());
int i;
for( i = 0; i < fPolys.GetCount(); i++ )
fOrigPolys[i].Transform(l2w, w2l, fPolys[i]);
if( fProxyGen )
fProxyGen->SetTransform(l2w, w2l);
}
void plMobileOccluder::SetPolyList(const hsTArray<plCullPoly>& list)
{
UInt16 n = list.GetCount();
fOrigPolys.SetCount(n);
fPolys.SetCount(n);
int i;
for( i = 0; i < n; i++ )
{
fPolys[i] = fOrigPolys[i] = list[i];
}
}
void plMobileOccluder::Read(hsStream* s, hsResMgr* mgr)
{
plOccluder::Read(s, mgr);
fLocalToWorld.Read(s);
fWorldToLocal.Read(s);
fLocalBounds.Read(s);
fPolys.SetCount(fOrigPolys.GetCount());
SetTransform(fLocalToWorld, fWorldToLocal);
}
void plMobileOccluder::Write(hsStream* s, hsResMgr* mgr)
{
plOccluder::Write(s, mgr);
fLocalToWorld.Write(s);
fWorldToLocal.Write(s);
fLocalBounds.Write(s);
}
void plMobileOccluder::ComputeFromPolys()
{
SetTransform(fLocalToWorld, fWorldToLocal);
plOccluder::ComputeFromPolys();
}

View File

@ -0,0 +1,153 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plOccluder_inc
#define plOccluder_inc
#include "../pnSceneObject/plObjInterface.h"
#include "hsTemplates.h"
#include "hsMatrix44.h"
#include "plCullPoly.h"
#include "hsBounds.h"
#include "hsBitVector.h"
class plOccluderProxy;
class plDrawableSpans;
class hsGMaterial;
class plVisRegion;
class plOccluder : public plObjInterface
{
public:
enum {
kDisable = 0x0,
kNumProps
};
enum {
kRefVisRegion
};
protected:
hsTArray<plCullPoly> fPolys;
plOccluderProxy* fProxyGen;
hsBitVector fVisSet;
hsTArray<plVisRegion*> fVisRegions;
hsBitVector fVisNot;
hsScalar fPriority;
hsBounds3Ext fWorldBounds;
plKey fSceneNode;
virtual hsScalar IComputeSurfaceArea();
virtual void IComputeBounds();
virtual hsTArray<plCullPoly>& IGetLocalPolyList() { return fPolys; }
virtual void ISetSceneNode(plKey node);
void IAddVisRegion(plVisRegion* reg);
void IRemoveVisRegion(plVisRegion* reg);
public:
plOccluder();
virtual ~plOccluder();
CLASSNAME_REGISTER( plOccluder );
GETINTERFACE_ANY( plOccluder, plObjInterface);
virtual hsBool MsgReceive(plMessage* msg);
virtual hsScalar GetPriority() const { return fPriority; }
hsBool InVisSet(const hsBitVector& visSet) const { return fVisSet.Overlap(visSet); }
hsBool InVisNot(const hsBitVector& visNot) const { return fVisNot.Overlap(visNot); }
virtual const hsBounds3Ext& GetWorldBounds() const { return fWorldBounds; }
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
virtual const hsMatrix44& GetLocalToWorld() const;
virtual const hsMatrix44& GetWorldToLocal() const;
virtual void SetPolyList(const hsTArray<plCullPoly>& list);
virtual const hsTArray<plCullPoly>& GetWorldPolyList() const { return fPolys; }
virtual const hsTArray<plCullPoly>& GetLocalPolyList() const { return fPolys; }
virtual Int32 GetNumProperties() const { return kNumProps; }
virtual void Read(hsStream* s, hsResMgr* mgr);
virtual void Write(hsStream* s, hsResMgr* mgr);
// Visualization
virtual plDrawableSpans* CreateProxy(hsGMaterial* mat, hsTArray<UInt32>& idx, plDrawableSpans* addTo);
// Export only function to initialize.
virtual void ComputeFromPolys();
// These two should only be called internally and on export/convert
virtual plKey GetSceneNode() const { return fSceneNode; }
};
class plMobileOccluder : public plOccluder
{
protected:
hsMatrix44 fLocalToWorld;
hsMatrix44 fWorldToLocal;
hsBounds3Ext fLocalBounds;
hsTArray<plCullPoly> fOrigPolys;
virtual void IComputeBounds();
virtual hsTArray<plCullPoly>& IGetLocalPolyList() { return fOrigPolys; }
public:
plMobileOccluder();
virtual ~plMobileOccluder();
CLASSNAME_REGISTER( plMobileOccluder );
GETINTERFACE_ANY( plMobileOccluder, plOccluder );
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
virtual const hsMatrix44& GetLocalToWorld() const { return fLocalToWorld; }
virtual const hsMatrix44& GetWorldToLocal() const { return fWorldToLocal; }
virtual void SetPolyList(const hsTArray<plCullPoly>& list);
virtual const hsTArray<plCullPoly>& GetLocalPolyList() const { return fOrigPolys; }
virtual void Read(hsStream* s, hsResMgr* mgr);
virtual void Write(hsStream* s, hsResMgr* mgr);
// Export only function to initialize.
virtual void ComputeFromPolys();
};
#endif // plOccluder_inc

View File

@ -0,0 +1,66 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plOccluderProxy.h"
#include "plOccluder.h"
#include "../plDrawable/plDrawableSpans.h"
#include "../plDrawable/plDrawableGenerator.h"
#include "../pnMessage/plProxyDrawMsg.h"
plOccluderProxy::plOccluderProxy()
: plProxyGen(hsColorRGBA().Set(0.2f,0.2f,0.8f,1.f), hsColorRGBA().Set(1.f,0.5f,0.5f,1.f), 0.5f),
fOwner(nil)
{
}
plOccluderProxy::~plOccluderProxy()
{
}
hsBool plOccluderProxy::Init(plOccluder* occluder)
{
plProxyGen::Init(occluder);
fOwner = occluder;
fProxyMsgType = plProxyDrawMsg::kOccluder;
return fOwner != nil;
}
plKey plOccluderProxy::IGetNode() const
{
return fOwner ? fOwner->GetSceneNode() : nil;
}
plDrawableSpans* plOccluderProxy::ICreateProxy(hsGMaterial* mat, hsTArray<UInt32>& idx, plDrawableSpans* addTo)
{
if( fOwner )
{
return fOwner->CreateProxy(mat, idx, addTo);
}
return nil;
}

View File

@ -0,0 +1,51 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plOccluderProxy_inc
#define plOccluderProxy_inc
#include "../plDrawable/plProxyGen.h"
class plOccluder;
class plDrawableSpans;
class hsGMaterial;
class plOccluderProxy : public plProxyGen
{
protected:
plOccluder* fOwner;
virtual plDrawableSpans* ICreateProxy(hsGMaterial* mat, hsTArray<UInt32>& idx, plDrawableSpans* addTo=nil);
virtual plKey IGetNode() const;
public:
plOccluderProxy();
virtual ~plOccluderProxy();
hsBool Init(plOccluder* occluder);
};
#endif // plOccluderProxy_inc

View File

@ -0,0 +1,696 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plPageTreeMgr.h"
#include "../plDrawable/plSpaceTreeMaker.h"
#include "../plDrawable/plSpaceTree.h"
#include "plDrawable.h"
#include "../plScene/plSceneNode.h"
#include "plPipeline.h"
#include "../plMath/hsRadixSort.h"
#include "plCullPoly.h"
#include "plOccluder.h"
#include "hsFastMath.h"
#include "plProfile.h"
#include "plVisMgr.h"
#include "plTweak.h"
static hsTArray<hsRadixSortElem> scratchList;
hsBool plPageTreeMgr::fDisableVisMgr = 0;
plProfile_CreateTimer("Object Sort", "Draw", DrawObjSort);
plProfile_CreateCounter("Objects Sorted", "Draw", DrawObjSorted);
plProfile_CreateTimer("Occluder Sort", "Draw", DrawOccSort);
plProfile_CreateCounter("Occluders Used", "Draw", DrawOccUsed);
plProfile_CreateTimer("Occluder Build", "Draw", DrawOccBuild);
plProfile_CreateCounter("Occluder Polys Processed", "Draw", DrawOccPolyProc);
plProfile_CreateTimer("Occluder Poly Sort", "Draw", DrawOccPolySort);
plPageTreeMgr::plPageTreeMgr()
: fSpaceTree(nil)
{
fVisMgr = plGlobalVisMgr::Instance();
}
plPageTreeMgr::~plPageTreeMgr()
{
delete fSpaceTree;
}
void plPageTreeMgr::AddNode(plSceneNode* node)
{
ITrashSpaceTree();
node->Init();
fNodes.Append(node);
}
void plPageTreeMgr::RemoveNode(plSceneNode* node)
{
ITrashSpaceTree();
int idx = fNodes.Find(node);
if( idx != fNodes.kMissingIndex )
fNodes.Remove(idx);
}
void plPageTreeMgr::Reset()
{
fNodes.Reset();
ITrashSpaceTree();
}
void plPageTreeMgr::ITrashSpaceTree()
{
delete fSpaceTree;
fSpaceTree = nil;
}
hsBool plPageTreeMgr::Harvest(plVolumeIsect* isect, hsTArray<plDrawVisList>& levList)
{
levList.SetCount(0);
if( !(GetSpaceTree() || IBuildSpaceTree()) )
return false;
static hsTArray<Int16> list;
GetSpaceTree()->HarvestLeaves(isect, list);
int i;
for( i = 0; i < list.GetCount(); i++ )
{
fNodes[list[i]]->Harvest(isect, levList);
}
return levList.GetCount() > 0;
}
#include "plProfile.h"
plProfile_CreateTimer("DrawableTime", "Draw", DrawableTime);
plProfile_Extern(RenderScene);
int plPageTreeMgr::Render(plPipeline* pipe)
{
// If we don't have a space tree and can't make one, just bail
if( !(GetSpaceTree() || IBuildSpaceTree()) )
return 0;
static hsTArray<Int16> list;
list.SetCount(0);
plProfile_BeginTiming(RenderScene);
plVisMgr* visMgr = fDisableVisMgr ? nil : fVisMgr;
if( visMgr )
{
plProfile_Extern(VisEval);
plProfile_BeginTiming(VisEval);
visMgr->Eval(pipe->GetViewPositionWorld());
plProfile_EndTiming(VisEval);
}
pipe->BeginVisMgr(visMgr);
IRefreshTree(pipe);
IGetOcclusion(pipe, list);
pipe->HarvestVisible(GetSpaceTree(), list);
static hsTArray<plDrawVisList> levList;
levList.SetCount(0);
int i;
for( i = 0; i < list.GetCount(); i++ )
{
fNodes[list[i]]->CollectForRender(pipe, levList, visMgr);
}
int numDrawn = IRenderVisList(pipe, levList);
IResetOcclusion(pipe);
pipe->EndVisMgr(visMgr);
plProfile_EndTiming(RenderScene);
return numDrawn;
}
int plPageTreeMgr::IRenderVisList(plPipeline* pipe, hsTArray<plDrawVisList>& levList)
{
// Sort levList into sortedDrawList, which is just a list
// of drawable/visList pairs in ascending render priority order.
// visLists are just lists of span indices, but only of the
// spans which are visible (on screen and non-occluded and non-disabled).
static hsTArray<plDrawVisList> sortedDrawList;
if( !ISortByLevel(pipe, levList, sortedDrawList) )
{
return 0;
}
int numDrawn = 0;
plVisMgr* visMgr = fDisableVisMgr ? nil : fVisMgr;
// Going through the list in order, if we hit a drawable which doesn't need
// its spans sorted, we can just draw it.
// If we hit a drawable which does need its spans sorted, we could just draw
// it, but that precludes sorting spans between drawables (like the player avatar
// sorting with normal scene objects). So when we hit a drawable which needs
// span sorting, we sort its spans with the spans of the next N drawables in
// the sorted list which have the same render priority and which also want their
// spans sorted.
int i;
for( i = 0; i < sortedDrawList.GetCount(); i++ )
{
plDrawable* p = sortedDrawList[i].fDrawable;
plProfile_BeginLap(DrawableTime, p->GetKey()->GetUoid().GetObjectName());
if( sortedDrawList[i].fDrawable->GetNativeProperty(plDrawable::kPropSortSpans) )
{
// IPrepForRenderSortingSpans increments "i" to the next index to be drawn (-1 so the i++
// at the top of the loop is correct.
numDrawn += IPrepForRenderSortingSpans(pipe, sortedDrawList, i);
}
else
{
pipe->PrepForRender(sortedDrawList[i].fDrawable, sortedDrawList[i].fVisList, visMgr);
pipe->Render(sortedDrawList[i].fDrawable, sortedDrawList[i].fVisList);
numDrawn += sortedDrawList[i].fVisList.GetCount();
}
plProfile_EndLap(DrawableTime, p->GetKey()->GetUoid().GetObjectName());
}
return numDrawn;
}
hsBool plPageTreeMgr::ISortByLevel(plPipeline* pipe, hsTArray<plDrawVisList>& drawList, hsTArray<plDrawVisList>& sortedDrawList)
{
sortedDrawList.SetCount(0);
if( !drawList.GetCount() )
return false;
scratchList.SetCount(drawList.GetCount());
hsRadixSort::Elem* listTrav = nil;
int i;
for( i = 0; i < drawList.GetCount(); i++ )
{
listTrav = &scratchList[i];
listTrav->fBody = (void*)&drawList[i];
listTrav->fNext = listTrav+1;
listTrav->fKey.fULong = drawList[i].fDrawable->GetRenderLevel().Level();
}
listTrav->fNext = nil;
hsRadixSort rad;
hsRadixSort::Elem* sortedList = rad.Sort(scratchList.AcquireArray(), hsRadixSort::kUnsigned);
listTrav = sortedList;
while( listTrav )
{
plDrawVisList& drawVis = *(plDrawVisList*)listTrav->fBody;
sortedDrawList.Append(drawVis);
listTrav = listTrav->fNext;
}
return true;
}
// Render from iDrawStart in drawVis list all drawables with the sort by spans property, well, sorting
// by spans.
// Returns the index of the last one drawn.
int plPageTreeMgr::IPrepForRenderSortingSpans(plPipeline* pipe, hsTArray<plDrawVisList>& drawVis, int& iDrawStart)
{
UInt32 renderLevel = drawVis[iDrawStart].fDrawable->GetRenderLevel().Level();
int i;
static hsTArray<plDrawVisList*> drawables;
static hsTArray<plDrawSpanPair> pairs;
// Given the input drawVisList (list of drawable/visList pairs), we make two new
// lists. The list "drawables" is just the excerpted sub-list from drawVis starting
// from the input index and going through all compatible drawables (drawables which
// are appropriate to sort (and hence intermix) with the first drawable in the list.
// The second list is the drawableIndex/spanIndex pairs convenient for sorting (where
// drawIndex indexes into drawables and spanIndex indexes into drawVis[iDraw].fVisList.
// So pairs[i] resolves into
// drawables[pairs[i].fDrawable].fDrawable->GetSpan(pairs[i].fSpan)
drawables.Append(&drawVis[iDrawStart]);
for( i = 0; i < drawVis[iDrawStart].fVisList.GetCount(); i++ )
{
plDrawSpanPair* pair = pairs.Push();
pair->fDrawable = 0;
pair->fSpan = drawVis[iDrawStart].fVisList[i];
}
int iDraw;
for( iDraw = iDrawStart+1;
(iDraw < drawVis.GetCount())
&& (drawVis[iDraw].fDrawable->GetRenderLevel().Level() == renderLevel)
&& drawVis[iDraw].fDrawable->GetNativeProperty(plDrawable::kPropSortSpans);
iDraw++ )
{
plDrawable* drawable = drawVis[iDraw].fDrawable;
hsTArray<Int16>& visList = drawVis[iDraw].fVisList;
for( i = 0; i < visList.GetCount(); i++ )
{
plDrawSpanPair* pair = pairs.Push();
pair->fDrawable = drawables.GetCount();
pair->fSpan = visList[i];
}
drawables.Append(&drawVis[iDraw]);
}
// Now that we have them in a more convenient format, sort them and render.
IRenderSortingSpans(pipe, drawables, pairs);
int numDrawn = pairs.GetCount();
drawables.SetCount(0);
pairs.SetCount(0);
iDrawStart = iDraw - 1;
return numDrawn;
}
hsBool plPageTreeMgr::IRenderSortingSpans(plPipeline* pipe, hsTArray<plDrawVisList*>& drawList, hsTArray<plDrawSpanPair>& pairs)
{
if( !pairs.GetCount() )
return false;
hsPoint3 viewPos = pipe->GetViewPositionWorld();
plProfile_BeginTiming(DrawObjSort);
plProfile_IncCount(DrawObjSorted, pairs.GetCount());
hsRadixSort::Elem* listTrav;
scratchList.SetCount(pairs.GetCount());
// First, sort on distance to the camera (squared).
listTrav = nil;
int iSort = 0;
int i;
for( i = 0; i < pairs.GetCount(); i++ )
{
plDrawable* drawable = drawList[pairs[i].fDrawable]->fDrawable;
listTrav = &scratchList[iSort++];
listTrav->fBody = (void*)*(UInt32*)&pairs[i];
listTrav->fNext = listTrav + 1;
if( drawable->GetNativeProperty(plDrawable::kPropSortAsOne) )
{
const hsBounds3Ext& bnd = drawable->GetSpaceTree()->GetNode(drawable->GetSpaceTree()->GetRoot()).fWorldBounds;
plConst(hsScalar) kDistFudge(1.e-1f);
listTrav->fKey.fFloat = -(bnd.GetCenter() - viewPos).MagnitudeSquared() + hsScalar(pairs[i].fSpan) * kDistFudge;
}
else
{
const hsBounds3Ext& bnd = drawable->GetSpaceTree()->GetNode(pairs[i].fSpan).fWorldBounds;
listTrav->fKey.fFloat = -(bnd.GetCenter() - viewPos).MagnitudeSquared();
}
}
if( !listTrav )
{
plProfile_EndTiming(DrawObjSort);
return false;
}
listTrav->fNext = nil;
hsRadixSort rad;
hsRadixSort::Elem* sortedList = rad.Sort(scratchList.AcquireArray(), 0);
plProfile_EndTiming(DrawObjSort);
static hsTArray<Int16> visList;
visList.SetCount(0);
plVisMgr* visMgr = fDisableVisMgr ? nil : fVisMgr;
// Call PrepForRender on each of these bad boys. We only want to call
// PrepForRender once on each drawable, no matter how many times we're
// going to pass it off to be rendered (like if we render span 0 from
// drawable A, span 1 from drawable A, span 0 from drawable B, span 1 from Drawable A, we
// don't want to PrepForRender twice or three times on drawable A).
// So we're going to convert our sorted list back into a list of drawable/visList
// pairs. We could have done this with our original drawable/visList, but we've
// hopefully trimmed out some spans because of the fades. This drawable/visList
// isn't appropriate for rendering (because it doesn't let us switch back and forth
// from a drawable, but it's right for the PrepForRenderCall (which does things like
// face sorting).
for( i = 0; i < drawList.GetCount(); i++ )
drawList[i]->fVisList.SetCount(0);
listTrav = sortedList;
while( listTrav )
{
plDrawSpanPair& curPair = *(plDrawSpanPair*)&listTrav->fBody;
drawList[curPair.fDrawable]->fVisList.Append(curPair.fSpan);
listTrav = listTrav->fNext;
}
for( i = 0; i < drawList.GetCount(); i++ )
{
pipe->PrepForRender(drawList[i]->fDrawable, drawList[i]->fVisList, visMgr);
}
// We'd like to call Render once on a drawable for each contiguous
// set of spans (so we want to render span 0 and span 1 on a single Render
// of drawable A in the above, then render drawable B, then back to A).
// So we go through the sorted drawable/spanIndex pairs list, building
// a visList for as long as the drawable remains the same. When it
// changes, we render what we have so far, and start again with the
// next drawable. Repeat until done.
#if 0
listTrav = sortedList;
plDrawSpanPair& curPair = *(plDrawSpanPair*)&listTrav->fBody;
int curDraw = curPair.fDrawable;
visList.Append(curPair.fSpan);
listTrav = listTrav->fNext;
while( listTrav )
{
curPair = *(plDrawSpanPair*)&listTrav->fBody;
if( curPair.fDrawable != curDraw )
{
pipe->Render(drawList[curDraw]->fDrawable, visList);
curDraw = curPair.fDrawable;
visList.SetCount(0);
visList.Append(curPair.fSpan);
}
else
{
visList.Append(curPair.fSpan);
}
listTrav = listTrav->fNext;
}
pipe->Render(drawList[curDraw]->fDrawable, visList);
#else
listTrav = sortedList;
plDrawSpanPair& curPair = *(plDrawSpanPair*)&listTrav->fBody;
int curDraw = curPair.fDrawable;
listTrav = listTrav->fNext;
static hsTArray<UInt32> numDrawn;
numDrawn.SetCountAndZero(drawList.GetCount());
visList.Append(drawList[curDraw]->fVisList[numDrawn[curDraw]++]);
while( listTrav )
{
curPair = *(plDrawSpanPair*)&listTrav->fBody;
if( curPair.fDrawable != curDraw )
{
pipe->Render(drawList[curDraw]->fDrawable, visList);
curDraw = curPair.fDrawable;
visList.SetCount(0);
}
visList.Append(drawList[curDraw]->fVisList[numDrawn[curDraw]++]);
listTrav = listTrav->fNext;
}
pipe->Render(drawList[curDraw]->fDrawable, visList);
#endif
return true;
}
hsBool plPageTreeMgr::IBuildSpaceTree()
{
if( !fNodes.GetCount() )
return false;
plSpaceTreeMaker maker;
maker.Reset();
int i;
for( i = 0; i < fNodes.GetCount(); i++ )
{
maker.AddLeaf(fNodes[i]->GetSpaceTree()->GetWorldBounds(), fNodes[i]->GetSpaceTree()->IsEmpty());
}
fSpaceTree = maker.MakeTree();
return true;
}
hsBool plPageTreeMgr::IRefreshTree(plPipeline* pipe)
{
int i;
for( i = 0; i < fNodes.GetCount(); i++ )
{
if( fNodes[i]->GetSpaceTree()->IsDirty() )
{
fNodes[i]->GetSpaceTree()->Refresh();
GetSpaceTree()->MoveLeaf(i, fNodes[i]->GetSpaceTree()->GetWorldBounds());
if( !fNodes[i]->GetSpaceTree()->IsEmpty() && fSpaceTree->HasLeafFlag(i, plSpaceTreeNode::kDisabled) )
fSpaceTree->SetLeafFlag(i, plSpaceTreeNode::kDisabled, false);
}
}
GetSpaceTree()->SetViewPos(pipe->GetViewPositionWorld());
GetSpaceTree()->Refresh();
return true;
}
void plPageTreeMgr::AddOccluderList(const hsTArray<plOccluder*> occList)
{
int iStart = fOccluders.GetCount();
fOccluders.Expand(iStart + occList.GetCount());
fOccluders.SetCount(iStart + occList.GetCount());
plVisMgr* visMgr = fDisableVisMgr ? nil : fVisMgr;
if( visMgr )
{
const hsBitVector& visSet = visMgr->GetVisSet();
const hsBitVector& visNot = visMgr->GetVisNot();
int i;
for( i = 0; i < occList.GetCount(); i++ )
{
if( occList[i] && !occList[i]->InVisNot(visNot) && occList[i]->InVisSet(visSet) )
fOccluders[iStart++] = occList[i];
}
}
else
{
int i;
for( i = 0; i < occList.GetCount(); i++ )
{
if( occList[i] )
fOccluders[iStart++] = occList[i];
}
}
fOccluders.SetCount(iStart);
}
void plPageTreeMgr::IAddCullPolyList(const hsTArray<plCullPoly>& polyList)
{
int iStart = fCullPolys.GetCount();
fCullPolys.Expand(iStart + polyList.GetCount());
fCullPolys.SetCount(iStart + polyList.GetCount());
int i;
for( i = 0; i < polyList.GetCount(); i++ )
{
fCullPolys[i + iStart] = &polyList[i];
}
}
void plPageTreeMgr::ISortCullPolys(plPipeline* pipe)
{
fSortedCullPolys.SetCount(0);
if( !fCullPolys.GetCount() )
return;
const int kMaxCullPolys = 300;
int numSubmit = 0;
hsPoint3 viewPos = pipe->GetViewPositionWorld();
hsRadixSort::Elem* listTrav;
scratchList.SetCount(fCullPolys.GetCount());
int i;
for( i = 0; i < fCullPolys.GetCount(); i++ )
{
hsBool backFace = fCullPolys[i]->fNorm.InnerProduct(viewPos) + fCullPolys[i]->fDist <= 0;
if( backFace )
{
if( !fCullPolys[i]->IsHole() && !fCullPolys[i]->IsTwoSided() )
continue;
}
else
{
if( fCullPolys[i]->IsHole() )
continue;
}
listTrav = &scratchList[numSubmit];
listTrav->fBody = (void*)fCullPolys[i];
listTrav->fNext = listTrav + 1;
listTrav->fKey.fFloat = (fCullPolys[i]->GetCenter() - viewPos).MagnitudeSquared();
numSubmit++;
}
if( !numSubmit )
return;
listTrav->fNext = nil;
hsRadixSort rad;
hsRadixSort::Elem* sortedList = rad.Sort(scratchList.AcquireArray(), 0);
listTrav = sortedList;
if( numSubmit > kMaxCullPolys )
numSubmit = kMaxCullPolys;
fSortedCullPolys.SetCount(numSubmit);
for( i = 0; i < numSubmit; i++ )
{
fSortedCullPolys[i] = (const plCullPoly*)listTrav->fBody;
listTrav = listTrav->fNext;
}
}
hsBool plPageTreeMgr::IGetCullPolys(plPipeline* pipe)
{
if( !fOccluders.GetCount() )
return false;
plProfile_BeginTiming(DrawOccSort);
hsRadixSort::Elem* listTrav = nil;
scratchList.SetCount(fOccluders.GetCount());
hsPoint3 viewPos = pipe->GetViewPositionWorld();
// cull test the occluders submitted
int numSubmit = 0;
int i;
for( i = 0; i < fOccluders.GetCount(); i++ )
{
if( pipe->TestVisibleWorld(fOccluders[i]->GetWorldBounds()) )
{
hsScalar invDist = -hsFastMath::InvSqrtAppr((viewPos - fOccluders[i]->GetWorldBounds().GetCenter()).MagnitudeSquared());
listTrav = &scratchList[numSubmit++];
listTrav->fBody = (void*)fOccluders[i];
listTrav->fNext = listTrav+1;
listTrav->fKey.fFloat = fOccluders[i]->GetPriority() * invDist;
}
}
if( !listTrav )
{
plProfile_EndTiming(DrawOccSort);
return false;
}
listTrav->fNext = nil;
// Sort the occluders by priority
hsRadixSort rad;
hsRadixSort::Elem* sortedList = rad.Sort(scratchList.AcquireArray(), 0);
listTrav = sortedList;
const UInt32 kMaxOccluders = 1000;
if( numSubmit > kMaxOccluders )
numSubmit = kMaxOccluders;
plProfile_IncCount(DrawOccUsed, numSubmit);
// Take the polys from the first N of them
for( i = 0; i < numSubmit; i++ )
{
plOccluder* occ = (plOccluder*)listTrav->fBody;
IAddCullPolyList(occ->GetWorldPolyList());
listTrav = listTrav->fNext;
}
plProfile_EndTiming(DrawOccSort);
return fCullPolys.GetCount() > 0;
}
hsBool plPageTreeMgr::IGetOcclusion(plPipeline* pipe, hsTArray<Int16>& list)
{
plProfile_BeginTiming(DrawOccBuild);
fCullPolys.SetCount(0);
fOccluders.SetCount(0);
int i;
for( i = 0; i < fNodes.GetCount(); i++ )
{
fNodes[i]->SubmitOccluders(this);
}
if( !IGetCullPolys(pipe) )
{
plProfile_EndTiming(DrawOccBuild);
return false;
}
plProfile_IncCount(DrawOccPolyProc, fCullPolys.GetCount());
plProfile_BeginTiming(DrawOccPolySort);
ISortCullPolys(pipe);
plProfile_EndTiming(DrawOccPolySort);
if( fSortedCullPolys.GetCount() )
pipe->SubmitOccluders(fSortedCullPolys);
plProfile_EndTiming(DrawOccBuild);
return fSortedCullPolys.GetCount() > 0;
}
void plPageTreeMgr::IResetOcclusion(plPipeline* pipe)
{
fCullPolys.SetCount(0);
fSortedCullPolys.SetCount(0);
}

View File

@ -0,0 +1,117 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plPageTreeMgr_inc
#define plPageTreeMgr_inc
#include "hsTemplates.h"
class plSceneNode;
class plSpaceTree;
class plPipeline;
class plCullPoly;
class plOccluder;
class plDrawable;
class plDrawVisList;
class plVolumeIsect;
class plVisMgr;
class plDrawSpanPair
{
public:
plDrawSpanPair() {}
plDrawSpanPair(UInt16 d, UInt16 s) : fDrawable(d), fSpan(s) {}
UInt16 fDrawable;
UInt16 fSpan;
};
class plDrawVisList
{
public:
plDrawVisList() : fDrawable(nil) {}
virtual ~plDrawVisList() {}
plDrawable* fDrawable;
hsTArray<Int16> fVisList;
plDrawVisList& operator=(const plDrawVisList& v) { fDrawable = v.fDrawable; fVisList = v.fVisList; return *this; }
};
class plPageTreeMgr
{
protected:
hsTArray<plSceneNode*> fNodes;
plSpaceTree* fSpaceTree;
plVisMgr* fVisMgr;
static hsBool fDisableVisMgr;
hsTArray<const plOccluder*> fOccluders;
hsTArray<const plCullPoly*> fCullPolys;
hsTArray<const plCullPoly*> fSortedCullPolys;
void ITrashSpaceTree();
hsBool IBuildSpaceTree();
hsBool IRefreshTree(plPipeline* pipe);
void ISortCullPolys(plPipeline* pipe);
hsBool IGetOcclusion(plPipeline* pipe, hsTArray<Int16>& list);
hsBool IGetCullPolys(plPipeline* pipe);
void IResetOcclusion(plPipeline* pipe);
void IAddCullPolyList(const hsTArray<plCullPoly>& polyList);
hsBool ISortByLevel(plPipeline* pipe, hsTArray<plDrawVisList>& drawList, hsTArray<plDrawVisList>& sortedDrawList);
int IPrepForRenderSortingSpans(plPipeline* pipe, hsTArray<plDrawVisList>& drawVis, int& iDrawStart);
hsBool IRenderSortingSpans(plPipeline* pipe, hsTArray<plDrawVisList*>& drawList, hsTArray<plDrawSpanPair>& pairs);
int IRenderVisList(plPipeline* pipe, hsTArray<plDrawVisList>& visList);
public:
plPageTreeMgr();
virtual ~plPageTreeMgr();
const hsTArray<plSceneNode*>& GetNodes() const { return fNodes; }
void AddNode(plSceneNode* node);
void RemoveNode(plSceneNode* node);
virtual void Reset(); // remove all nodes, nuke the space tree
virtual hsBool Empty() const { return !fNodes.GetCount(); }
virtual int Render(plPipeline* pipe);
hsBool Harvest(plVolumeIsect* isect, hsTArray<plDrawVisList>& levList);
void AddOccluderList(const hsTArray<plOccluder*> occList);
plSpaceTree* GetSpaceTree() { if( !fSpaceTree ) IBuildSpaceTree(); return fSpaceTree; }
void SetVisMgr(plVisMgr* visMgr) { fVisMgr = visMgr; }
plVisMgr* GetVisMgr() const { return fVisMgr; }
static void EnableVisMgr(hsBool on) { fDisableVisMgr = !on; }
static hsBool VisMgrEnabled() { return !fDisableVisMgr; }
};
#endif // plPageTreeMgr_inc

View File

@ -0,0 +1,321 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plPostEffectMod.h"
#include "plPageTreeMgr.h"
#include "plSceneNode.h"
#include "plRenderRequest.h"
#include "../plPipeline/plRenderTarget.h"
#include "../plMessage/plRenderRequestMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plMessage/plRenderMsg.h"
#include "../pnMessage/plRefMsg.h"
#include "../pnSceneObject/plSceneObject.h"
#include "plDrawable.h"
#include "plPipeline.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
plPostEffectMod::plPostEffectMod()
: fHither(1.f),
fYon(100.f),
fFovX(hsScalarPI * 0.25f),
fFovY(hsScalarPI * 0.25f * 0.75f),
fPageMgr(nil),
fRenderTarget(nil),
fRenderRequest(nil)
{
fDefaultW2C = hsMatrix44::IdentityMatrix();
fDefaultC2W = hsMatrix44::IdentityMatrix();
ISetupRenderRequest();
}
plPostEffectMod::~plPostEffectMod()
{
IDestroyRenderRequest();
}
void plPostEffectMod::ISetupRenderRequest()
{
UInt32 rtFlags = 0;
// If we go to rendering to sub-window, we'll want to explicitly set width and height
UInt32 width = 0;
UInt32 height = 0;
UInt32 colorDepth = 0;
UInt32 zDepth = 0;
UInt32 stencilDepth = 0;
fRenderRequest = TRACKED_NEW plRenderRequest;
UInt32 renderState = plPipeline::kRenderNormal
| plPipeline::kRenderNoProjection
| plPipeline::kRenderNoLights
| plPipeline::kRenderClearDepth;
fRenderRequest->SetRenderState(renderState);
fRenderRequest->SetDrawableMask(plDrawable::kNormal);
fRenderRequest->SetSubDrawableMask(plDrawable::kSubAllTypes);
fRenderRequest->SetPerspective();
fRenderRequest->SetRenderTarget(fRenderTarget);
fPageMgr = TRACKED_NEW plPageTreeMgr;
fRenderRequest->SetPageTreeMgr(fPageMgr);
fRenderRequest->SetPriority(1.f);
IUpdateRenderRequest();
}
void plPostEffectMod::EnableLightsOnRenderRequest( void )
{
fRenderRequest->SetRenderState( fRenderRequest->GetRenderState() & ~plPipeline::kRenderNoLights );
}
void plPostEffectMod::IDestroyRenderRequest()
{
delete fRenderTarget;
fRenderTarget = nil;
delete fRenderRequest;
fRenderRequest = nil;
delete fPageMgr;
fPageMgr = nil;
}
void plPostEffectMod::IRegisterForRenderMsg(hsBool on)
{
if( on )
plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey());
else
plgDispatch::Dispatch()->UnRegisterForExactType(plRenderMsg::Index(), GetKey());
}
void plPostEffectMod::ISetEnable(hsBool on)
{
if( on )
{
IRegisterForRenderMsg(true);
fState.SetBit(kEnabled);
}
else
{
IRegisterForRenderMsg(false);
fState.ClearBit(kEnabled);
}
}
hsBool plPostEffectMod::IIsEnabled() const
{
return /*GetTarget() &&*/ !fPageMgr->Empty() && fState.IsBitSet(kEnabled);
}
hsBool plPostEffectMod::IEval(double secs, hsScalar del, UInt32 dirty)
{
return false;
}
void plPostEffectMod::IUpdateRenderRequest()
{
fRenderRequest->SetHither(fHither);
fRenderRequest->SetYon(fYon);
fRenderRequest->SetFovX(fFovX);
fRenderRequest->SetFovY(fFovY);
if( GetTarget() )
{
hsMatrix44 w2c = GetTarget()->GetWorldToLocal();
hsMatrix44 c2w = GetTarget()->GetLocalToWorld();
int i;
for( i = 0; i < 4; i++ )
{
w2c.fMap[2][i] *= -1.f;
c2w.fMap[i][2] *= -1.f;
}
w2c.NotIdentity();
c2w.NotIdentity();
fRenderRequest->SetCameraTransform(w2c, c2w);
}
else
fRenderRequest->SetCameraTransform( fDefaultW2C, fDefaultC2W );
// fRenderRequest->SetCameraTransform(hsMatrix44::IdentityMatrix(), hsMatrix44::IdentityMatrix());
}
// If translating from a scene object, send WorldToLocal() and LocalToWorld(), in that order
void plPostEffectMod::SetWorldToCamera( hsMatrix44 &w2c, hsMatrix44 &c2w )
{
int i;
fDefaultW2C = w2c;
fDefaultC2W = c2w;
for( i = 0; i < 4; i++ )
{
fDefaultW2C.fMap[2][i] *= -1.f;
fDefaultC2W.fMap[i][2] *= -1.f;
}
fDefaultW2C.NotIdentity();
fDefaultC2W.NotIdentity();
}
void plPostEffectMod::GetDefaultWorldToCamera( hsMatrix44 &w2c, hsMatrix44 &c2w )
{
w2c = fDefaultW2C;
c2w = fDefaultC2W;
}
void plPostEffectMod::ISubmitRequest()
{
hsAssert(fState.IsBitSet(kEnabled), "Submitting request when not active");
// No target is now valid...
// hsAssert(GetTarget(), "Submitting request without target loaded");
IUpdateRenderRequest();
plRenderRequestMsg* req = TRACKED_NEW plRenderRequestMsg(GetKey(), fRenderRequest);
plgDispatch::MsgSend(req);
}
void plPostEffectMod::IAddToPageMgr(plSceneNode* node)
{
fPageMgr->AddNode(node);
}
void plPostEffectMod::IRemoveFromPageMgr(plSceneNode* node)
{
fPageMgr->RemoveNode(node);
}
#include "plProfile.h"
plProfile_CreateTimer("PostEffect", "RenderSetup", PostEffect);
hsBool plPostEffectMod::MsgReceive(plMessage* msg)
{
plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg);
if( rend && IIsEnabled() )
{
plProfile_BeginLap(PostEffect, this->GetKey()->GetUoid().GetObjectName());
ISubmitRequest();
plProfile_EndLap(PostEffect, this->GetKey()->GetUoid().GetObjectName());
return true;
}
plAnimCmdMsg* anim = plAnimCmdMsg::ConvertNoRef(msg);
if( anim )
{
if( anim->Cmd(plAnimCmdMsg::kContinue) )
ISetEnable(true);
else if( anim->Cmd(plAnimCmdMsg::kStop) )
ISetEnable(false);
else if( anim->Cmd(plAnimCmdMsg::kToggleState) )
ISetEnable(!fState.IsBitSet(kEnabled));
return true;
}
plGenRefMsg* ref = plGenRefMsg::ConvertNoRef(msg);
if( ref )
{
switch( ref->fType )
{
case kNodeRef:
if( ref->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest) )
{
IAddToPageMgr(plSceneNode::ConvertNoRef(ref->GetRef()));
}
else if( ref->GetContext() & plRefMsg::kOnReplace )
{
IRemoveFromPageMgr(plSceneNode::ConvertNoRef(ref->GetOldRef()));
IAddToPageMgr(plSceneNode::ConvertNoRef(ref->GetRef()));
}
else if( ref->GetContext() & (plRefMsg::kOnRemove | plRefMsg::kOnDestroy) )
{
IRemoveFromPageMgr(plSceneNode::ConvertNoRef(ref->GetRef()));
}
break;
}
return true;
}
return plSingleModifier::MsgReceive(msg);
}
void plPostEffectMod::Read(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Read(s, mgr);
fState.Read(s);
#if 0 // FORCE ENABLE ON LOAD - ONLY FOR DEBUGGING
ISetEnable(true);
#endif // FORCE ENABLE ON LOAD - ONLY FOR DEBUGGING
fHither = s->ReadSwapScalar();
fYon = s->ReadSwapScalar();
fFovX = s->ReadSwapScalar();
fFovY = s->ReadSwapScalar();
fNodeKey = mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, -1, kNodeRef), plRefFlags::kPassiveRef);
fDefaultW2C.Read( s );
fDefaultC2W.Read( s );
IUpdateRenderRequest();
}
void plPostEffectMod::Write(hsStream* s, hsResMgr* mgr)
{
plSingleModifier::Write(s, mgr);
fState.Write(s);
s->WriteSwapScalar(fHither);
s->WriteSwapScalar(fYon);
s->WriteSwapScalar(fFovX);
s->WriteSwapScalar(fFovY);
mgr->WriteKey(s, fNodeKey);
fDefaultW2C.Write( s );
fDefaultC2W.Write( s );
}
const plViewTransform& plPostEffectMod::GetViewTransform()
{
IUpdateRenderRequest();
return fRenderRequest->GetViewTransform();
}

View File

@ -0,0 +1,126 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plPostEffectMod_inc
#define plPostEffectMod_inc
#include "../pnModifier/plSingleModifier.h"
#include "hsMatrix44.h"
#include "hsBitVector.h"
class plSceneNode;
class plPageTreeMgr;
class plMessage;
class plRenderTarget;
class plRenderRequest;
class plViewTransform;
class plPostEffectMod : public plSingleModifier
{
public:
enum plPostEffectModStates {
kEnabled = 0
};
enum {
kNodeRef = 0x0
};
protected:
hsBitVector fState;
hsScalar fHither;
hsScalar fYon;
hsScalar fFovX;
hsScalar fFovY;
plKey fNodeKey;
plPageTreeMgr* fPageMgr;
plRenderTarget* fRenderTarget;
plRenderRequest* fRenderRequest;
hsMatrix44 fDefaultW2C, fDefaultC2W;
virtual hsBool IEval(double secs, hsScalar del, UInt32 dirty); // called only by owner object's Eval()
void ISetupRenderRequest();
void IDestroyRenderRequest();
void IUpdateRenderRequest();
void IRegisterForRenderMsg(hsBool on);
void ISubmitRequest();
void IAddToPageMgr(plSceneNode* node);
void IRemoveFromPageMgr(plSceneNode* node);
void ISetEnable(hsBool on);
hsBool IIsEnabled() const;
public:
plPostEffectMod();
virtual ~plPostEffectMod();
CLASSNAME_REGISTER( plPostEffectMod );
GETINTERFACE_ANY( plPostEffectMod, plSingleModifier );
virtual hsBool MsgReceive(plMessage* pMsg);
virtual void Read(hsStream* s, hsResMgr* mgr);
virtual void Write(hsStream* s, hsResMgr* mgr);
void GetDefaultWorldToCamera( hsMatrix44 &w2c, hsMatrix44 &c2w );
// Export only
void SetNodeKey(plKey key) { fNodeKey = key; }
plKey GetNodeKey() const { return fNodeKey; }
void SetHither(hsScalar h) { fHither = h; }
void SetYon(hsScalar y) { fYon = y; }
void SetFovX(hsScalar f) { fFovX = f; }
void SetFovY(hsScalar f) { fFovY = f; }
hsScalar GetHither() const { return fHither; }
hsScalar GetYon() const { return fYon; }
hsScalar GetFovX() const { return fFovX; }
hsScalar GetFovY() const { return fFovY; }
plPageTreeMgr* GetPageMgr() const { return fPageMgr; }
const plViewTransform& GetViewTransform();
// If translating from a scene object, send WorldToLocal() and LocalToWorld(), in that order
void SetWorldToCamera( hsMatrix44 &w2c, hsMatrix44 &c2w );
// Very bad
void EnableLightsOnRenderRequest( void );
};
#endif // plPostEffectMod_inc

View File

@ -0,0 +1,255 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "plRelevanceMgr.h"
#include "plRelevanceRegion.h"
#include "../plIntersect/plRegionBase.h"
#include "hsStream.h"
#include "hsStringTokenizer.h"
plRelevanceMgr* plRelevanceMgr::fInstance = nil;
plRelevanceMgr::plRelevanceMgr() : fEnabled(true)
{
}
void plRelevanceMgr::Init()
{
fInstance = TRACKED_NEW plRelevanceMgr;
fInstance->RegisterAs(kRelevanceMgr_KEY);
}
void plRelevanceMgr::DeInit()
{
if (fInstance)
{
fInstance->UnRegisterAs(kRelevanceMgr_KEY);
fInstance = nil;
}
}
void plRelevanceMgr::IAddRegion(plRelevanceRegion *region)
{
int i;
int dstIdx = fRegions.GetCount();
for (i = 0; i < fRegions.GetCount(); i++)
{
if (fRegions[i] == nil)
{
dstIdx = i;
break;
}
}
if (dstIdx == fRegions.GetCount())
fRegions.Append(region);
else
fRegions[i] = region;
region->SetMgrIndex(dstIdx + 1);
}
void plRelevanceMgr::IRemoveRegion(plRelevanceRegion *region)
{
fRegions[region->fMgrIdx - 1] = nil;
}
void plRelevanceMgr::SetRegionVectors(const hsPoint3 &pos, hsBitVector &regionsImIn, hsBitVector &regionsICareAbout)
{
regionsImIn.Clear();
regionsICareAbout.Clear();
regionsICareAbout.SetBit(0, true); // Always care about region zero, the special "No region" node
hsBool inAnyRegion = false;
int i;
for (i = 0; i < fRegions.GetCount(); i++)
{
if (fRegions[i] && fRegions[i]->fRegion->IsInside(pos))
{
regionsImIn.SetBit(i + 1, true);
regionsICareAbout |= fRegions[i]->fRegionsICareAbout;
inAnyRegion = true;
}
}
// If I'm not in any region, that means I'm in the special zero region and care about everything.
if (!inAnyRegion)
{
regionsImIn.SetBit(0, true);
regionsICareAbout.Set(fRegions.GetCount());
}
}
UInt32 plRelevanceMgr::GetNumRegions() const
{
int i;
for (i = fRegions.GetCount(); i > 0 && fRegions[i - 1] == nil; i--);
return i + 1; // Add 1 for the special zero-region
}
hsBool plRelevanceMgr::MsgReceive(plMessage* msg)
{
plGenRefMsg *genMsg = plGenRefMsg::ConvertNoRef(msg);
if (genMsg)
{
plRelevanceRegion *region = plRelevanceRegion::ConvertNoRef(genMsg->GetRef());
if( genMsg->GetContext() & (plRefMsg::kOnCreate) )
{
IAddRegion(region);
}
else if( genMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
IRemoveRegion(region);
}
return true;
}
return hsKeyedObject::MsgReceive(msg);
}
UInt32 plRelevanceMgr::GetIndex(char *regionName)
{
int i;
for (i = 0; i < fRegions.GetCount(); i++)
{
if (fRegions[i] && !stricmp(regionName, fRegions[i]->GetKeyName()))
return i + 1;
}
return -1;
}
void plRelevanceMgr::MarkRegion(UInt32 localIdx, UInt32 remoteIdx, hsBool doICare)
{
if (localIdx == (UInt32)-1 || remoteIdx == (UInt32)-1)
return;
if (localIdx - 1 >= fRegions.GetCount() || remoteIdx - 1 >= fRegions.GetCount() || fRegions[localIdx - 1] == nil)
return;
fRegions[localIdx - 1]->fRegionsICareAbout.SetBit(remoteIdx, doICare);
}
// tiny class for the function below
class plRegionInfo
{
public:
char *fName;
int fIndex;
plRegionInfo() : fName(nil), fIndex(-1) {}
~plRegionInfo() { delete [] fName; }
};
/*
* This function expects a CSV file representing the matrix
*
* name1 name2 name3
* name1 value value value
* name2 value value value
* name3 value value value
*
* where the value determines how much the that row's region cares about the region in the current column.
* (Currently, the possible values are:
* 0: Doesn't care
* 1 or greater: row cares about column
*/
void plRelevanceMgr::ParseCsvInput(hsStream *s)
{
const int kBufSize = 512;
char buff[kBufSize];
hsTArray<plRegionInfo*> regions;
hsStringTokenizer toke;
hsBool firstLine = true;
while (!s->AtEnd())
{
if (!s->ReadLn(buff, kBufSize))
break;
if (firstLine)
{
firstLine = false;
toke.Reset(buff, ",");
while (toke.Next(buff, kBufSize))
{
if (strcmp(buff, "") == 0)
continue; // ignore the initial blank one
plRegionInfo *info = TRACKED_NEW plRegionInfo;
regions.Append(info);
info->fName = hsStrcpy(buff);
info->fIndex = GetIndex(buff);
}
}
else // parsing actual settings.
{
toke.Reset(buff, ",");
if (!toke.Next(buff, kBufSize))
continue;
int rowIndex = GetIndex(buff);
int column = 0;
while (toke.Next(buff, kBufSize) && column < regions.GetCount())
{
int value = atoi(buff);
MarkRegion(rowIndex, regions[column]->fIndex, value != 0);
column++;
}
}
}
int i;
for (i = regions.GetCount() - 1; i >= 0; i--)
delete regions[i];
}
std::string plRelevanceMgr::GetRegionNames(hsBitVector regions)
{
std::string retVal = "";
if (regions.IsBitSet(0))
retVal = "-Nowhere (0)-";
for (int i = 0; i < fRegions.GetCount(); ++i)
{
if (regions.IsBitSet(i + 1))
{
if (retVal.length() != 0)
retVal += ", ";
if (fRegions[i])
retVal += fRegions[i]->GetKeyName();
}
}
if (retVal.length() == 0)
retVal = "<NONE>";
return retVal;
}

View File

@ -0,0 +1,76 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plRelevanceMgr_inc
#define plRelevanceMgr_inc
#include "../pnKeyedObject/hsKeyedObject.h"
#include "hsGeometry3.h"
#include "hsTemplates.h"
#include "hsBitVector.h"
#include "hsStlUtils.h"
class plRelevanceRegion;
class hsStream;
class plRelevanceMgr : public hsKeyedObject
{
protected:
static plRelevanceMgr *fInstance;
public:
static plRelevanceMgr *Instance() { return fInstance; }
static void Init();
static void DeInit();
protected:
hsTArray<plRelevanceRegion*> fRegions;
hsBool fEnabled;
void IAddRegion(plRelevanceRegion *);
void IRemoveRegion(plRelevanceRegion *);
public:
plRelevanceMgr();
CLASSNAME_REGISTER( plRelevanceMgr );
GETINTERFACE_ANY( plRelevanceMgr, hsKeyedObject );
virtual hsBool MsgReceive(plMessage* msg);
hsBool GetEnabled() { return fEnabled; }
void SetEnabled(hsBool val) { fEnabled = val; }
UInt32 GetIndex(char *regionName);
void MarkRegion(UInt32 localIdx, UInt32 remoteIdx, hsBool doICare);
void SetRegionVectors(const hsPoint3 &pos, hsBitVector &regionsImIn, hsBitVector &regionsICareAbout);
UInt32 GetNumRegions() const; // includes the secret 0 region in its count
void ParseCsvInput(hsStream *s);
std::string GetRegionNames(hsBitVector regions);
};
#endif // plRelevanceMgr_inc

View File

@ -0,0 +1,82 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsResMgr.h"
#include "plRelevanceRegion.h"
#include "plRelevanceMgr.h"
#include "../plIntersect/plRegionBase.h"
void plRelevanceRegion::Read(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Read(s, mgr);
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, 0), plRefFlags::kActiveRef);
// Added to the manager when read in.
// Removed when paged out, due to passive ref.
if (plRelevanceMgr::Instance())
{
plGenRefMsg *msg = TRACKED_NEW plGenRefMsg(plRelevanceMgr::Instance()->GetKey(), plRefMsg::kOnCreate, -1, -1);
hsgResMgr::ResMgr()->AddViaNotify(GetKey(), msg, plRefFlags::kPassiveRef);
}
}
void plRelevanceRegion::Write(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Write(s, mgr);
mgr->WriteKey(s, fRegion);
}
hsBool plRelevanceRegion::MsgReceive(plMessage* msg)
{
plGenRefMsg *genMsg = plGenRefMsg::ConvertNoRef(msg);
if (genMsg)
{
plRegionBase *base = plRegionBase::ConvertNoRef(genMsg->GetRef());
if( genMsg->GetContext() & (plRefMsg::kOnCreate) )
{
fRegion = base;
}
else if( genMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
{
fRegion = nil;
}
return true;
}
return plObjInterface::MsgReceive(msg);
}
void plRelevanceRegion::SetMgrIndex(UInt32 index)
{
if (fMgrIdx != (UInt32)-1)
fRegionsICareAbout.SetBit(fMgrIdx, false);
fMgrIdx = index;
fRegionsICareAbout.SetBit(index, true); // I care about myself. Awww...
}

View File

@ -0,0 +1,61 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plRelevanceRegion_inc
#define plRelevanceRegion_inc
#include "../pnSceneObject/plObjInterface.h"
class plRelevanceMgr;
class plRegionBase;
class plRelevanceRegion : public plObjInterface
{
friend class plRelevanceMgr;
protected:
plRegionBase *fRegion;
hsBitVector fRegionsICareAbout;
UInt32 fMgrIdx;
public:
plRelevanceRegion() : fRegion(nil), fMgrIdx((UInt32)-1) {}
virtual ~plRelevanceRegion() {}
CLASSNAME_REGISTER( plRelevanceRegion );
GETINTERFACE_ANY( plRelevanceRegion, plObjInterface );
virtual hsBool MsgReceive(plMessage* msg);
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) {}
virtual Int32 GetNumProperties() const { return 1; }
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void SetMgrIndex(UInt32 idx);
};
#endif // plRelevanceRegion_inc

View File

@ -0,0 +1,154 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plRenderRequest.h"
#include "plPageTreeMgr.h"
#include "../plPipeline/plRenderTarget.h"
#include "hsFastMath.h"
#include "hsStream.h"
#include "plPipeline.h"
#include "../plMessage/plRenderRequestMsg.h"
#include "plgDispatch.h"
#include "plVisMgr.h"
plRenderRequest::plRenderRequest()
: fRenderTarget(nil),
fPageMgr(nil),
fAck(nil),
fOverrideMat(nil),
fEraseMat(nil),
fDrawableMask(UInt32(-1)),
fSubDrawableMask(UInt32(-1)),
fRenderState(0),
fClearDepth(1.f),
fFogStart(-1.f),
fClearDrawable(nil),
fPriority(-1.e6f),
fUserData(0),
fIgnoreOccluders(false)
{
fClearColor.Set(0,0,0,1.f);
fLocalToWorld.Reset();
fWorldToLocal.Reset();
}
plRenderRequest::~plRenderRequest()
{
}
void plRenderRequest::SetLocalTransform(const hsMatrix44& l2w, const hsMatrix44& w2l)
{
fLocalToWorld = l2w;
fWorldToLocal = w2l;
}
void plRenderRequest::Read(hsStream* s, hsResMgr* mgr)
{
fClearDrawable = nil;
fRenderTarget = nil;
fPageMgr = nil;
fDrawableMask = s->ReadSwap32();
fSubDrawableMask = s->ReadSwap32();
fRenderState = s->ReadSwap32();
fLocalToWorld.Read(s);
fWorldToLocal.Read(s);
fPriority = s->ReadSwapScalar();
}
void plRenderRequest::Write(hsStream* s, hsResMgr* mgr)
{
s->WriteSwap32(fDrawableMask);
s->WriteSwap32(fSubDrawableMask);
s->WriteSwap32(fRenderState);
fLocalToWorld.Write(s);
fWorldToLocal.Write(s);
s->WriteSwapScalar(fPriority);
}
void plRenderRequest::Render(plPipeline* pipe, plPageTreeMgr* pageMgr)
{
if( !fVisForce.Empty() )
{
plGlobalVisMgr::Instance()->DisableNormal();
plGlobalVisMgr::Instance()->ForceVisSets(fVisForce, false);
}
pipe->PushRenderRequest(this);
pipe->ClearRenderTarget(GetClearDrawable());
int numDrawn = 0;
if( GetPageTreeMgr() )
numDrawn = GetPageTreeMgr()->Render(pipe);
else
numDrawn = pageMgr->Render(pipe);
pipe->PopRenderRequest(this);
if( GetAck() )
{
plRenderRequestAck* ack = TRACKED_NEW plRenderRequestAck( GetAck(), GetUserData() );
ack->SetNumDrawn(numDrawn);
plgDispatch::MsgSend( ack );
}
}
void plRenderRequest::SetRenderTarget(plRenderTarget* t)
{
if( t != fRenderTarget )
{
fRenderTarget = t;
if( fRenderTarget )
{
fViewTransform.SetWidth(t->GetWidth());
fViewTransform.SetHeight(t->GetHeight());
}
}
}
void plRenderRequest::SetVisForce(const hsBitVector& b)
{
if( b.Empty() )
fVisForce.Reset();
else
fVisForce = b;
}
hsBool plRenderRequest::GetRenderCharacters() const
{
return fVisForce.IsBitSet(plVisMgr::kCharacter);
}

View File

@ -0,0 +1,191 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plRenderRequest_inc
#define plRenderRequest_inc
#include "hsMatrix44.h"
#include "hsColorRGBA.h"
#include "plViewTransform.h"
#include "hsRefCnt.h"
#include "hsBitVector.h"
#include "../pnKeyedObject/plKey.h"
#include "../plMessage/plRenderRequestMsg.h"
class plRenderTarget;
class plPageTreeMgr;
class hsStream;
class hsResMgr;
class plDrawable;
class hsGMaterial;
class plPipeline;
class plRenderRequest : public plRenderRequestBase
{
public:
protected:
UInt32 fRenderState; // Or'ed from plPipeline::RenderStateSettings::kRender*
plDrawable* fClearDrawable;
plRenderTarget* fRenderTarget;
plPageTreeMgr* fPageMgr;
hsGMaterial* fOverrideMat;
hsGMaterial* fEraseMat;
plKey fAck;
hsScalar fPriority;
UInt32 fDrawableMask;
UInt32 fSubDrawableMask;
hsColorRGBA fClearColor;
hsScalar fClearDepth;
hsScalar fFogStart;
hsMatrix44 fLocalToWorld;
hsMatrix44 fWorldToLocal;
plViewTransform fViewTransform;
hsBitVector fVisForce;
UInt32 fUserData;
hsBool fIgnoreOccluders;
public:
plRenderRequest();
~plRenderRequest();
hsBool GetRenderSelect() const { return !fVisForce.Empty(); }
hsBool GetRenderCharacters() const;
void SetRenderState(UInt32 st) { fRenderState = st; }
UInt32 GetRenderState() const { return fRenderState; }
void SetDrawableMask(UInt32 m) { fDrawableMask = m; }
UInt32 GetDrawableMask() const { return fDrawableMask; }
void SetSubDrawableMask(UInt32 m) { fSubDrawableMask = m; }
UInt32 GetSubDrawableMask() const { return fSubDrawableMask; }
void RequestAck(plKey key) { fAck = key; }
plKey GetAck() const { return fAck; }
plDrawable* GetClearDrawable() const { return fClearDrawable; }
void SetClearDrawable(plDrawable* d) { fClearDrawable = d; }
hsGMaterial* GetOverrideMat() const { return fOverrideMat; }
void SetOverrideMat(hsGMaterial* m) { fOverrideMat = m; }
hsGMaterial* GetEraseMat() const { return fEraseMat; }
void SetEraseMat(hsGMaterial* m) { fEraseMat = m; }
plRenderTarget* GetRenderTarget() const { return fRenderTarget; }
void SetRenderTarget(plRenderTarget* t);
plPageTreeMgr* GetPageTreeMgr() const { return fPageMgr; }
void SetPageTreeMgr(plPageTreeMgr* mgr) { fPageMgr = mgr; }
const hsBitVector& GetVisForce() const { return fVisForce; }
void SetVisForce(const hsBitVector& b);
const hsMatrix44& GetLocalToWorld() const { return fLocalToWorld; }
const hsMatrix44& GetWorldToLocal() const { return fWorldToLocal; }
const hsMatrix44& GetWorldToCamera() const { return fViewTransform.GetWorldToCamera(); }
const hsMatrix44& GetCameraToWorld() const { return fViewTransform.GetCameraToWorld(); }
const plViewTransform& GetViewTransform() const { return fViewTransform; }
hsScalar GetHither() const { return fViewTransform.GetHither(); }
hsScalar GetYon() const { return fViewTransform.GetYon(); }
hsScalar GetFovX() const { return fViewTransform.GetFovXDeg(); }
hsScalar GetFovY() const { return fViewTransform.GetFovYDeg(); }
hsScalar GetSizeX() const { return fViewTransform.GetOrthoWidth(); }
hsScalar GetSizeY() const { return fViewTransform.GetOrthoHeight(); }
UInt16 GetScreenWidth() const { return fViewTransform.GetScreenWidth(); }
UInt16 GetScreenHeight() const { return fViewTransform.GetScreenHeight(); }
const hsColorRGBA& GetClearColor() const { return fClearColor; }
hsScalar GetClearDepth() const { return fClearDepth; }
// FogStart
// negative => use current settings (default)
// 0 => no fog == fog starts at yon
// 1 => fog starts at camera.
// Fog start greater than 1 is legal. Fog always linear.
hsScalar GetFogStart() const { return fFogStart; }
hsScalar GetPriority() const { return fPriority; }
void SetLocalTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
void SetViewTransform(const plViewTransform& v) { fViewTransform = v; }
void SetCameraTransform(const hsMatrix44& w2c, const hsMatrix44& c2w) { fViewTransform.SetCameraTransform(w2c, c2w); }
void SetPerspective(hsBool on=true) { fViewTransform.SetPerspective(on); }
void SetOrthogonal(hsBool on=true) { fViewTransform.SetOrthogonal(on); }
void SetHither(hsScalar f) { fViewTransform.SetHither(f); }
void SetYon(hsScalar f) { fViewTransform.SetYon(f); }
void SetFovX(hsScalar f) { fViewTransform.SetFovXDeg(f); }
void SetFovY(hsScalar f) { fViewTransform.SetFovYDeg(f); }
void SetSizeX(hsScalar f) { fViewTransform.SetWidth(f); }
void SetSizeY(hsScalar f) { fViewTransform.SetHeight(f); }
void SetClearColor(const hsColorRGBA& c) { fClearColor = c; }
void SetClearDepth(hsScalar d) { fClearDepth = d; }
// FogStart
// negative => use current settings (default)
// 0 => no fog == fog starts at yon
// 1 => fog starts at camera.
// Fog start greater than 1 is legal. Fog always linear.
void SetFogStart(hsScalar d) { fFogStart = d; }
void SetPriority(hsScalar p) { fPriority = p; }
virtual void Read(hsStream* s, hsResMgr* mgr);
virtual void Write(hsStream* s, hsResMgr* mgr);
void SetUserData(UInt32 n) { fUserData = n; }
UInt32 GetUserData() const { return fUserData; }
void SetIgnoreOccluders(hsBool b) { fIgnoreOccluders = b; }
hsBool GetIgnoreOccluders() { return fIgnoreOccluders; }
// This function is called after the render request is processed by the client
virtual void Render(plPipeline* pipe, plPageTreeMgr* pageMgr);
};
#endif // plRenderRequest_inc

View File

@ -0,0 +1,61 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plSceneCreatable_inc
#define plSceneCreatable_inc
#include "../pnFactory/plCreatable.h"
#include "plSceneNode.h"
REGISTER_CREATABLE( plSceneNode );
#include "plOccluder.h"
REGISTER_CREATABLE( plOccluder );
REGISTER_CREATABLE( plMobileOccluder );
#include "plPostEffectMod.h"
REGISTER_CREATABLE( plPostEffectMod );
#include "plVisMgr.h"
REGISTER_CREATABLE( plVisMgr );
#include "plVisRegion.h"
REGISTER_CREATABLE( plVisRegion );
#include "plRelevanceMgr.h"
REGISTER_CREATABLE( plRelevanceMgr );
#include "plRelevanceRegion.h"
REGISTER_CREATABLE( plRelevanceRegion );
#endif // plSceneCreatable_inc

View File

@ -0,0 +1,507 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plSceneNode.h"
#include "../pnDispatch/plDispatch.h"
#include "../plMessage/plNodeCleanupMsg.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "hsStream.h"
#include "hsResMgr.h"
#include "../pnSceneObject/plSceneObject.h"
#include "plDrawable.h"
#include "plPhysical.h"
#include "plAudible.h"
#include "../plGLight/plLightInfo.h"
#include "../pnMessage/plRefMsg.h"
#include "plPipeline.h"
#include "../pnKeyedObject/plKey.h"
#include "../plDrawable/plSpaceTreeMaker.h"
#include "../plDrawable/plSpaceTree.h"
#include "plPageTreeMgr.h"
#include "plOccluder.h"
//MFHORSE
//BLACK
// temp hack for debugging
#include "../plDrawable/plDrawableSpans.h"
#include "../pnKeyedObject/plKeyImp.h"
plSceneNode::plSceneNode()
: fDepth(0),
fSpaceTree(nil),
fFilterGenerics(false)
{
}
plSceneNode::~plSceneNode()
{
plgDispatch::Dispatch()->UnRegisterForExactType(plNodeCleanupMsg::Index(), GetKey());
delete fSpaceTree;
}
//// Init ////////////////////////////////////////////////////////////////////
// Because we can't register for messages on construction. Doh.
void plSceneNode::Init()
{
/// :P
plgDispatch::Dispatch()->RegisterForExactType(plNodeCleanupMsg::Index(), GetKey());
}
void plSceneNode::Read(hsStream* s, hsResMgr* mgr)
{
hsKeyedObject::Read(s, mgr);
UInt32 n;
int i;
n = s->ReadSwap32();
fSceneObjects.Reset();
for( i = 0; i < n; i++ )
{
plNodeRefMsg* refMsg = TRACKED_NEW plNodeRefMsg(GetKey(), plRefMsg::kOnCreate, i, plNodeRefMsg::kObject);
plKey key = mgr->ReadKeyNotifyMe(s, refMsg, plRefFlags::kActiveRef);
}
n = s->ReadSwap32();
fGenericPool.Reset();
for( i = 0; i < n; i++ )
{
plNodeRefMsg* refMsg = TRACKED_NEW plNodeRefMsg(GetKey(), plRefMsg::kOnCreate, -1, plNodeRefMsg::kGeneric);
mgr->ReadKeyNotifyMe(s, refMsg, plRefFlags::kActiveRef);
}
}
void plSceneNode::Write(hsStream* s, hsResMgr* mgr)
{
hsKeyedObject::Write(s, mgr);
int i;
s->WriteSwap32(fSceneObjects.GetCount());
for( i = 0; i < fSceneObjects.GetCount(); i++ )
mgr->WriteKey(s,fSceneObjects[i]);
s->WriteSwap32(fGenericPool.GetCount());
for( i = 0; i < fGenericPool.GetCount(); i++ )
mgr->WriteKey(s, fGenericPool[i]);
}
void plSceneNode::Harvest(plVolumeIsect* isect, hsTArray<plDrawVisList>& levList)
{
static hsTArray<Int16> visList;
visList.SetCount(0);
GetSpaceTree()->HarvestLeaves(isect, visList);
static hsTArray<Int16> visSpans;
visSpans.SetCount(0);
int i;
for( i = 0; i < visList.GetCount(); i++ )
{
int idx = visList[i];
fDrawPool[idx]->GetSpaceTree()->HarvestLeaves(isect, visSpans);
if( visSpans.GetCount() )
{
plDrawVisList* drawVis = levList.Push();
drawVis->fDrawable = fDrawPool[idx];
drawVis->fVisList.Swap(visSpans);
}
}
}
void plSceneNode::CollectForRender(plPipeline* pipe, hsTArray<plDrawVisList>& levList, plVisMgr* visMgr)
{
static hsTArray<Int16> visList;
visList.SetCount(0);
pipe->HarvestVisible(GetSpaceTree(), visList);
static hsTArray<Int16> visSpans;
visSpans.SetCount(0);
int i;
for( i = 0; i < visList.GetCount(); i++ )
{
int idx = visList[i];
if( pipe->PreRender(fDrawPool[idx], visSpans, visMgr) )
{
plDrawVisList* drawVis = levList.Push();
drawVis->fDrawable = fDrawPool[idx];
drawVis->fVisList.Swap(visSpans);
}
}
}
void plSceneNode::SubmitOccluders(plPageTreeMgr* pageMgr) const
{
pageMgr->AddOccluderList(fOccluders);
}
plSpaceTree* plSceneNode::IBuildSpaceTree()
{
plSpaceTreeMaker maker;
maker.Reset();
hsBounds3Ext bnd;
bnd.Reset(&hsPoint3(0,0,0));
int i;
for( i = 0; i < fDrawPool.GetCount(); i++ )
{
if( fDrawPool[i] )
maker.AddLeaf(fDrawPool[i]->GetSpaceTree()->GetWorldBounds());
else
maker.AddLeaf(bnd, true);
}
fSpaceTree = maker.MakeTree();
fSpaceTree->MakeDirty();
return fSpaceTree;
}
plSpaceTree* plSceneNode::ITrashSpaceTree()
{
delete fSpaceTree;
return fSpaceTree = nil;
}
void plSceneNode::IDirtySpaceTree()
{
int i;
for( i = 0; i < fDrawPool.GetCount(); i++ )
{
if( fDrawPool[i] && fDrawPool[i]->GetSpaceTree()->IsDirty() )
{
fDrawPool[i]->GetSpaceTree()->Refresh();
fSpaceTree->MoveLeaf(i, fDrawPool[i]->GetSpaceTree()->GetWorldBounds());
}
}
}
plSpaceTree* plSceneNode::GetSpaceTree()
{
if( !fSpaceTree )
{
IBuildSpaceTree();
}
IDirtySpaceTree();
return fSpaceTree;
}
void plSceneNode::ISetDrawable(plDrawable* d)
{
if( !d )
return;
if (fDrawPool.Find(d) == fDrawPool.kMissingIndex)
{
fDrawPool.Append(d);
}
ITrashSpaceTree();
}
void plSceneNode::ISetAudible(plAudible* a)
{
if( !a )
return;
if( fAudioPool.kMissingIndex == fAudioPool.Find(a) )
{
fAudioPool.Append(a);
}
}
void plSceneNode::ISetPhysical(plPhysical* p)
{
if( !p )
return;
if( fSimulationPool.kMissingIndex == fSimulationPool.Find(p) )
{
fSimulationPool.Append(p);
}
}
void plSceneNode::ISetObject(plSceneObject* o)
{
if( o && (fSceneObjects.kMissingIndex == fSceneObjects.Find(o)) )
{
fSceneObjects.Append(o);
// MF_NET_GROUPS_TEST
// This will have no effect on members of NetGroupConstants
o->SetNetGroup(o->SelectNetGroup(GetKey()));
o->SetSceneNode(GetKey());
}
}
void plSceneNode::ISetLight(plLightInfo* l)
{
if( fLightPool.kMissingIndex == fLightPool.Find(l) )
fLightPool.Append( l );
}
void plSceneNode::ISetOccluder(plOccluder* o)
{
if( fOccluders.kMissingIndex == fOccluders.Find(o) )
{
fOccluders.Append(o);
}
}
void plSceneNode::ISetGeneric(hsKeyedObject* k)
{
if( fGenericPool.kMissingIndex == fGenericPool.Find(k) )
fGenericPool.Append(k);
}
void plSceneNode::IRemoveDrawable(plDrawable* d)
{
int idx = fDrawPool.Find(d);
if( idx != fDrawPool.kMissingIndex )
fDrawPool.Remove(idx);
ITrashSpaceTree();
}
void plSceneNode::IRemoveAudible(plAudible* a)
{
int idx = fAudioPool.Find(a);
if( idx != fAudioPool.kMissingIndex )
fAudioPool.Remove(idx);
}
void plSceneNode::IRemovePhysical(plPhysical* p)
{
hsAssert(p, "Removing nil physical");
#ifdef HS_DEBUGGING
if (p)
{
plKey oldNodeKey = p->GetSceneNode();
if (oldNodeKey && oldNodeKey != GetKey())
{
char buf[256];
sprintf(buf, "Trying to remove physical %s from scenenode %s,\nbut it's actually in %s",
p->GetKeyName(), GetKeyName(), oldNodeKey->GetName());
hsAssert(0, buf);
}
}
#endif
int idx = fSimulationPool.Find(p);
if( idx != fSimulationPool.kMissingIndex )
fSimulationPool.Remove(idx);
}
void plSceneNode::IRemoveObject(plSceneObject* o)
{
int idx = fSceneObjects.Find(o);
if( idx != fSceneObjects.kMissingIndex )
fSceneObjects.Remove(idx);
}
void plSceneNode::IRemoveLight(plLightInfo* l)
{
hsAssert(l, "Removing nil light");
int idx = fLightPool.Find(l);
if( idx != fLightPool.kMissingIndex )
{
fLightPool.Remove(idx);
}
}
void plSceneNode::IRemoveOccluder(plOccluder* o)
{
int idx = fOccluders.Find(o);
if( idx != fOccluders.kMissingIndex )
fOccluders.Remove(idx);
}
void plSceneNode::IRemoveGeneric(hsKeyedObject* k)
{
int idx = fGenericPool.Find(k);
if( idx != fGenericPool.kMissingIndex )
fGenericPool.Remove(idx);
}
hsBool plSceneNode::IOnRemove(plNodeRefMsg* refMsg)
{
switch( refMsg->fType )
{
case plNodeRefMsg::kDrawable:
IRemoveDrawable(plDrawable::ConvertNoRef(refMsg->GetRef()));
break;
case plNodeRefMsg::kPhysical:
IRemovePhysical(plPhysical::ConvertNoRef(refMsg->GetRef()));
break;
case plNodeRefMsg::kAudible:
IRemoveAudible(plAudible::ConvertNoRef(refMsg->GetRef()));
break;
case plNodeRefMsg::kObject:
IRemoveObject(plSceneObject::ConvertNoRef(refMsg->GetRef()));
break;
case plNodeRefMsg::kLight:
IRemoveLight(plLightInfo::ConvertNoRef(refMsg->GetRef()));
break;
case plNodeRefMsg::kOccluder:
IRemoveOccluder(plOccluder::ConvertNoRef(refMsg->GetRef()));
break;
case plNodeRefMsg::kGeneric:
IRemoveGeneric(refMsg->GetRef());
break;
}
if( refMsg->GetRef() && (refMsg->GetContext() & plRefMsg::kOnRemove) )
GetKey()->Release(refMsg->GetRef()->GetKey());
return true;
}
hsBool plSceneNode::IOnAdd(plNodeRefMsg* refMsg)
{
int which = refMsg->fWhich;
switch( refMsg->fType )
{
case plNodeRefMsg::kDrawable:
ISetDrawable(plDrawable::ConvertNoRef(refMsg->GetRef()));
return true;
case plNodeRefMsg::kPhysical:
ISetPhysical(plPhysical::ConvertNoRef(refMsg->GetRef()));
return true;
case plNodeRefMsg::kAudible:
ISetAudible(plAudible::ConvertNoRef(refMsg->GetRef()));
return true;
case plNodeRefMsg::kObject:
ISetObject(plSceneObject::ConvertNoRef(refMsg->GetRef()));
return true;
case plNodeRefMsg::kLight:
ISetLight(plLightInfo::ConvertNoRef(refMsg->GetRef()));
return true;
case plNodeRefMsg::kOccluder:
ISetOccluder(plOccluder::ConvertNoRef(refMsg->GetRef()));
return true;
case plNodeRefMsg::kGeneric:
ISetGeneric(refMsg->GetRef());
}
return true;
}
hsBool plSceneNode::MsgReceive(plMessage* msg)
{
plNodeCleanupMsg *cleanMsg = plNodeCleanupMsg::ConvertNoRef( msg );
if( cleanMsg )
{
ICleanUp();
return true;
}
plNodeRefMsg* refMsg = plNodeRefMsg::ConvertNoRef(msg);
if( refMsg )
{
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
return IOnAdd(refMsg);
else if( refMsg->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
return IOnRemove(refMsg);
}
return hsKeyedObject::MsgReceive(msg);
}
//// ICleanUp ////////////////////////////////////////////////////////////////
// Export only: Clean up the scene node (i.e. make sure drawables optimize)
void plSceneNode::ICleanUp( void )
{
int i;
/// Go find drawables to delete
for( i = 0; i < fDrawPool.GetCount(); i++ )
fDrawPool[ i ]->Optimize();
if (fFilterGenerics)
{
for( i = fSceneObjects.GetCount() - 1; i >= 0; i--)
GetKey()->Release(fSceneObjects[i]->GetKey());
for( i = fDrawPool.GetCount() - 1; i >= 0; i--)
GetKey()->Release(fDrawPool[i]->GetKey());
for( i = fSimulationPool.GetCount() - 1; i >= 0; i--)
GetKey()->Release(fSimulationPool[i]->GetKey());
for( i = fAudioPool.GetCount() - 1; i >= 0; i--)
GetKey()->Release(fAudioPool[i]->GetKey());
for( i = fOccluders.GetCount() - 1; i >= 0; i--)
GetKey()->Release(fOccluders[i]->GetKey());
for( i = fLightPool.GetCount() - 1; i >= 0; i--)
GetKey()->Release(fLightPool[i]->GetKey());
}
ITrashSpaceTree();
}
//// GetMatchingDrawable /////////////////////////////////////////////////////
// Export only: Query for a given drawable.
plDrawable *plSceneNode::GetMatchingDrawable( const plDrawableCriteria& crit )
{
int i;
for( i = 0; i < fDrawPool.GetCount(); i++ )
{
if( fDrawPool[ i ]->DoIMatch( crit ) )
return fDrawPool[ i ];
}
return nil;
}
//// OptimizeDrawables ///////////////////////////////////////////////////////
// Loops through all the drawables and calls Optimize on each one. For the
// export side, to be called right before writing the drawables to disk.
void plSceneNode::OptimizeDrawables( void )
{
int i;
for( i = 0; i < fDrawPool.GetCount(); i++ )
fDrawPool[ i ]->Optimize();
}

View File

@ -0,0 +1,139 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plSceneNode_inc
#define plSceneNode_inc
#include "../pnKeyedObject/hsKeyedObject.h"
#include "hsTemplates.h"
class plSceneObject;
class plDrawable;
class plPhysical;
class plAudible;
class plLightInfo;
class plPipeline;
class plNodeRefMsg;
class plDispatchBase;
class plSpaceTree;
class plDrawSpanPair;
class plDrawVisList;
class plOccluder;
class plPageTreeMgr;
class plDrawableCriteria;
class plVolumeIsect;
class plVisMgr;
class plSceneNode : public hsKeyedObject
{
public:
enum {
kMaxSceneDepth = 4
};
protected:
hsBool fFilterGenerics; // Export only
Int16 fDepth;
hsTArray<plSceneObject*> fSceneObjects;
hsTArray<plDrawable*> fDrawPool;
hsTArray<plPhysical*> fSimulationPool;
hsTArray<plAudible*> fAudioPool;
hsTArray<plOccluder*> fOccluders;
hsTArray<plLightInfo*> fLightPool;
hsTArray<hsKeyedObject*> fGenericPool;
plSpaceTree* fSpaceTree;
void IDirtySpaceTree();
plSpaceTree* ITrashSpaceTree();
plSpaceTree* IBuildSpaceTree();
void IRemoveDrawable(plDrawable* d);
void IRemoveAudible(plAudible* a);
void IRemovePhysical(plPhysical* p);
void IRemoveObject(plSceneObject* o);
void IRemoveLight(plLightInfo* l);
void IRemoveOccluder(plOccluder* o);
void IRemoveGeneric(hsKeyedObject* k);
void ISetObject(plSceneObject* o);
void ISetPhysical(plPhysical* p);
void ISetAudible(plAudible* a);
void ISetDrawable(plDrawable* d);
void ISetLight(plLightInfo* l);
void ISetOccluder(plOccluder* o);
void ISetGeneric(hsKeyedObject* k);
hsBool IOnRemove(plNodeRefMsg* refMsg);
hsBool IOnAdd(plNodeRefMsg* refMsg);
// Export only: Clean up empty drawables
void ICleanUp( void );
public:
plSceneNode();
virtual ~plSceneNode();
CLASSNAME_REGISTER( plSceneNode );
GETINTERFACE_ANY( plSceneNode, hsKeyedObject );
virtual void Read(hsStream* s, hsResMgr* mgr);
virtual void Write(hsStream* s, hsResMgr* mgr);
virtual void Harvest(plVolumeIsect* isect, hsTArray<plDrawVisList>& levList);
virtual void CollectForRender(plPipeline* pipe, hsTArray<plDrawVisList>& levList, plVisMgr* visMgr);
virtual void SubmitOccluders(plPageTreeMgr* pageMgr) const;
virtual hsBool MsgReceive(plMessage* msg);
Int16 GetDepth() { return fDepth; }
Int16 IncDepth() { return ++fDepth; }
Int16 DecDepth() { return --fDepth; }
void Init( void );
plSpaceTree* GetSpaceTree();
// Export only: Query for a given drawable
virtual plDrawable *GetMatchingDrawable( const plDrawableCriteria& crit );
// Export only: Optimize all my stinkin' drawables
virtual void OptimizeDrawables( void );
void SetFilterGenericsOnly(hsBool b) { fFilterGenerics = b; }
const hsTArray<plDrawable*>& GetDrawPool() const { return fDrawPool; }
};
#endif // plSceneNode_inc

View File

@ -0,0 +1,207 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plVisMgr.h"
#include "plVisRegion.h"
hsBitVector plVisMgr::fIdxSet;
hsBitVector plVisMgr::fIdxNot;
plVisMgr::plVisMgr()
: fMaxSet(kCharacter),
fMaxNot(-1)
{
ResetNormal();
}
plVisMgr::~plVisMgr()
{
}
hsBool plVisMgr::MsgReceive(plMessage* msg)
{
return hsKeyedObject::MsgReceive(msg);
}
void plVisMgr::Read(hsStream* s, hsResMgr* mgr)
{
hsKeyedObject::Read(s, mgr);
}
void plVisMgr::Write(hsStream* s, hsResMgr* mgr)
{
hsKeyedObject::Write(s, mgr);
}
void plVisMgr::Register(plVisRegion* reg, hsBool not)
{
// This should happen pretty infrequently, or
// I wouldn't be doing it so cloth-headed-ly.
hsTArray<plVisRegion*>& regions = not ? fNotRegions : fRegions;
hsBitVector& indices = not ? fIdxNot : fIdxSet;
int& maxIdx = not ? fMaxNot : fMaxSet;
int i;
for( i = kNumReserved; ; i++ )
{
if( !indices.IsBitSet(i) )
{
if( i > maxIdx )
maxIdx = i;
indices.SetBit(i);
reg->SetIndex(i);
regions.Append(reg);
return;
}
}
hsAssert(false, "Infinite bitvector has all bits set?");
}
void plVisMgr::UnRegister(plVisRegion* reg, hsBool not)
{
// Mark our index for recycling
hsBitVector& indices= not ? fIdxNot : fIdxSet;
indices.ClearBit(reg->GetIndex());
// Nuke the region from our list.
hsTArray<plVisRegion*>& regions = not ? fNotRegions : fRegions;
int idx = regions.Find(reg);
if( regions.kMissingIndex != idx )
regions.Remove(idx);
}
void plVisMgr::Eval(const hsPoint3& pos)
{
fVisSet = fOnBitSet;
int i;
for( i = 0; i < fRegions.GetCount(); i++ )
{
hsAssert(fRegions[i], "Nil region in list");
if( !fOffBitSet.IsBitSet(fRegions[i]->GetIndex()) )
{
if( fRegions[i]->Eval(pos) )
{
fVisSet.SetBit(fRegions[i]->GetIndex());
if( fRegions[i]->DisableNormal() )
{
fVisSet.ClearBit(kNormal);
fVisSet.SetBit(kCharacter);
}
}
}
}
fVisNot = fOnBitNot;
for( i = 0; i < fNotRegions.GetCount(); i++ )
{
hsAssert(fNotRegions[i], "Nil region in list");
if( !fOffBitNot.IsBitSet(fNotRegions[i]->GetIndex()) )
{
if( fNotRegions[i]->Eval(pos) )
{
fVisNot.SetBit(fNotRegions[i]->GetIndex());
}
}
}
ResetNormal();
}
void plVisMgr::ResetNormal()
{
fOnBitSet.Clear();
fOnBitSet.SetBit(kNormal);
fOffBitSet.Clear();
fOnBitNot.Clear();
fOffBitNot.Clear();
}
void plVisMgr::DisableNormal()
{
fOnBitSet.Clear();
if( fMaxSet > 0 )
fOffBitSet.Set(fMaxSet);
fOnBitNot.Clear();
if( fMaxNot > 0 )
fOffBitNot.Set(fMaxNot);
}
void plVisMgr::EnableVisSet(int idx, hsBool isNot)
{
hsBitVector& offs = isNot ? fOffBitNot : fOffBitSet;
offs.ClearBit(idx);
}
void plVisMgr::EnableVisSets(const hsBitVector& enabled, hsBool isNot)
{
hsBitVector& offs = isNot ? fOffBitNot : fOffBitSet;
offs -= enabled;
}
void plVisMgr::ForceVisSet(int idx, hsBool isNot)
{
EnableVisSet(idx, isNot);
hsBitVector& ons = isNot ? fOnBitNot : fOnBitSet;
ons.SetBit(idx);
}
void plVisMgr::ForceVisSets(const hsBitVector& enabled, hsBool isNot)
{
EnableVisSets(enabled, isNot);
hsBitVector& ons = isNot ? fOnBitNot : fOnBitSet;
ons |= enabled;
}
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
plVisMgr* plGlobalVisMgr::fInstance = nil;
void plGlobalVisMgr::Init()
{
fInstance = TRACKED_NEW plVisMgr;
fInstance->RegisterAs(kGlobalVisMgr_KEY);
}
void plGlobalVisMgr::DeInit()
{
if (fInstance)
{
fInstance->UnRegisterAs(kGlobalVisMgr_KEY);
fInstance = nil;
}
}

View File

@ -0,0 +1,122 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plVisMgr_inc
#define plVisMgr_inc
#include "../pnKeyedObject/hsKeyedObject.h"
#include "hsTemplates.h"
#include "hsBitVector.h"
class hsStream;
class hsResMgr;
class plVisRegion;
class plMessage;
struct hsPoint3;
class plVisMgr : public hsKeyedObject
{
public:
enum RsvBits
{
kNormal,
kCharacter,
kNumReserved
};
protected:
hsTArray<plVisRegion*> fRegions;
hsTArray<plVisRegion*> fNotRegions;
hsBitVector fVisSet;
hsBitVector fVisNot;
int fMaxSet;
int fMaxNot;
hsBitVector fOnBitSet; // Forces a true response from that enabling region
hsBitVector fOffBitSet; // Forces a false response from that enabling region
hsBitVector fOnBitNot; // Forces a true response from that disabling region
hsBitVector fOffBitNot; // Forces a falseresponse from that disabling region
static hsBitVector fIdxSet;
static hsBitVector fIdxNot;
// There's currently no reason why you would call ResetNormal
// because it's called after every Eval.
void ResetNormal();
public:
plVisMgr();
virtual ~plVisMgr();
CLASSNAME_REGISTER( plVisMgr );
GETINTERFACE_ANY( plVisMgr, hsKeyedObject );
virtual hsBool MsgReceive(plMessage* msg);
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
void Register(plVisRegion* reg, hsBool not);
void UnRegister(plVisRegion* reg, hsBool not);
void Eval(const hsPoint3& pos);
const hsBitVector& GetVisSet() const { return fVisSet; }
const hsBitVector& GetVisNot() const { return fVisNot; }
// All the following persist only through the next Eval. So a normal
// use would be to call DisableNormal() in your RenderRequest's Render method,
// then Enable a few vissets of personal interest, then call the base RenderRequest::Render().
//
// Turns all regions off, so NOTHING gets drawn. That includes Normal and Character.
void DisableNormal();
// Enable drawing of selected sets. Either one index at a time or pass in a bitvector.
// The regions are just enabled, they can still say no.
void EnableVisSet(int idx, hsBool isNot = false);
void EnableVisSets(const hsBitVector& enabled, hsBool isNot = false);
// Make specified regions say yes, no matter where the camera is.
// This will implicitly call EnableVisSet for you.
void ForceVisSet(int idx, hsBool isNot = false);
void ForceVisSets(const hsBitVector& enabled, hsBool isNot = false);
};
class plGlobalVisMgr
{
protected:
static plVisMgr* fInstance;
public:
static plVisMgr* Instance() { return fInstance; }
static void Init();
static void DeInit();
};
#endif // plVisMgr_inc

View File

@ -0,0 +1,129 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "hsTypes.h"
#include "plVisRegion.h"
#include "hsStream.h"
#include "hsResMgr.h"
#include "plVisMgr.h"
#include "../pnMessage/plEnableMsg.h"
#include "../plIntersect/plRegionBase.h"
plVisRegion::plVisRegion()
: fIndex(0),
fRegion(nil),
fMgr(nil)
{
fMgr = plGlobalVisMgr::Instance();
SetProperty(kReplaceNormal, true);
}
plVisRegion::~plVisRegion()
{
if( fMgr )
fMgr->UnRegister(this, GetProperty(kIsNot));
}
hsBool plVisRegion::Eval(const hsPoint3& pos) const
{
if( GetProperty(kDisable) )
return false;
if( !fRegion )
return true;
return fRegion->IsInside(pos);
}
hsBool plVisRegion::MsgReceive(plMessage* msg)
{
plEnableMsg* enaMsg = plEnableMsg::ConvertNoRef(msg);
if( enaMsg )
{
SetProperty(kDisable, enaMsg->Cmd(plEnableMsg::kDisable));
return true;
}
plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef(msg);
if( refMsg )
{
switch( refMsg->fType )
{
case kRefRegion:
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
fRegion = plRegionBase::ConvertNoRef(refMsg->GetRef());
}
else
{
fRegion = nil;
}
return true;
case kRefVisMgr:
if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) )
{
if( fMgr )
fMgr->UnRegister(this, GetProperty(kIsNot));
fMgr = plVisMgr::ConvertNoRef(refMsg->GetRef());
hsAssert(fMgr, "Just set my manager to nil.");
fMgr->Register(this, GetProperty(kIsNot));
}
else
{
fMgr = nil;
}
return true;
default:
break;
}
}
return plObjInterface::MsgReceive(msg);
}
void plVisRegion::Read(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Read(s, mgr);
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefRegion), plRefFlags::kActiveRef);
mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefVisMgr), plRefFlags::kActiveRef);
if( fMgr )
fMgr->Register(this, GetProperty(kIsNot));
}
void plVisRegion::Write(hsStream* s, hsResMgr* mgr)
{
plObjInterface::Write(s, mgr);
mgr->WriteKey(s, fRegion);
mgr->WriteKey(s, fMgr);
}

View File

@ -0,0 +1,93 @@
/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#ifndef plVisRegion_inc
#define plVisRegion_inc
#include "../pnSceneObject/plObjInterface.h"
class hsStream;
class hsResMgr;
class plMessage;
class plVisMgr;
class plRegionBase;
struct hsPoint3;
class plVisRegion : public plObjInterface
{
public:
enum
{
kRefRegion,
kRefVisMgr
};
enum
{
kDisable = 0, // Always disable is zero
kIsNot,
kReplaceNormal, // Defaults to true
kDisableNormal
};
protected:
plRegionBase* fRegion;
plVisMgr* fMgr;
Int32 fIndex;
void SetIndex(Int32 i) { fIndex = i; }
friend class plVisMgr;
public:
plVisRegion();
virtual ~plVisRegion();
CLASSNAME_REGISTER( plVisRegion );
GETINTERFACE_ANY( plVisRegion, plObjInterface );
virtual Int32 GetNumProperties() const { return 3; } // This is stupid.
virtual hsBool MsgReceive(plMessage* msg);
// Set transform doesn't do anything, because the regions themselves are
// object interfaces, so they'll move when their sceneobjects move.
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l) {}
virtual void Read(hsStream* stream, hsResMgr* mgr);
virtual void Write(hsStream* stream, hsResMgr* mgr);
hsBool Eval(const hsPoint3& pos) const;
Int32 GetIndex() const { return fIndex; }
hsBool Registered() const { return GetIndex() > 0; }
hsBool IsNot() const { return GetProperty(kIsNot); }
hsBool ReplaceNormal() const { return GetProperty(kReplaceNormal); }
hsBool DisableNormal() const { return GetProperty(kDisableNormal); }
};
#endif // plVisRegion_inc