/*==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 . 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& idx, plDrawableSpans* addTo) { hsTArray pos; hsTArray norm; hsTArray color; hsTArray tris; plLayer* lay = plLayer::ConvertNoRef(mat->GetLayer(0)->BottomOfStack()); if( lay ) lay->SetMiscFlags(lay->GetMiscFlags() & ~hsGMatState::kMiscTwoSided); const hsTArray& 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& 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& 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& 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& 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& 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& 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(); }