/*==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 "plDynamicEnvMap.h" #include "plPipeline.h" #include "plPipeDebugFlags.h" #include "plDrawable.h" #include "plgDispatch.h" #include "hsResMgr.h" #include "hsTimer.h" #include "hsStream.h" #include "../plMessage/plRenderRequestMsg.h" #include "../plMessage/plDynamicEnvMapMsg.h" #include "../pfCamera/plCameraModifier.h" #include "../pfCamera/plVirtualCamNeu.h" #include "../plMessage/plRenderMsg.h" #include "../plMessage/plAgeLoadedMsg.h" #include "../plMessage/plLayRefMsg.h" #include "../pnMessage/plPipeResMakeMsg.h" #include "../pnMessage/plRefMsg.h" #include "../plScene/plVisRegion.h" #include "../plScene/plVisMgr.h" #include "../plResMgr/plKeyFinder.h" #include "../plSurface/plLayer.h" plDynamicEnvMap::plDynamicEnvMap() : fPos(0,0,0), fHither(0.3f), fYon(1000.f), fFogStart(1000.f), fRefreshRate(0.f), fLastRefresh(0.0), fLastRender(0), fOutStanding(0), fIncCharacters(false), fRootNode(nil) { fColor.Set(0,0,0,1.f); int i; for( i = 0; i < 6; i++ ) fReqMsgs[i] = TRACKED_NEW plRenderRequestMsg(nil, &fReqs[i]);; SetPosition(fPos); } plDynamicEnvMap::plDynamicEnvMap(UInt16 width, UInt16 height, UInt8 bitDepth, UInt8 zDepth, UInt8 sDepth) : fPos(0,0,0), fHither(0.3f), fYon(0.f), // yon < hither means ignore and use current settings fFogStart(-1.f), // - fog start means use current settings fRefreshRate(0.f), fLastRefresh(0.0), fLastRender(0), fOutStanding(0), fIncCharacters(false), fRootNode(nil), plCubicRenderTarget(plRenderTarget::kIsTexture, width, height, bitDepth, zDepth, sDepth) { fColor.Set(0,0,0,1.f); int i; for( i = 0; i < 6; i++ ) fReqMsgs[i] = TRACKED_NEW plRenderRequestMsg(nil, &fReqs[i]);; SetPosition(fPos); } plDynamicEnvMap::~plDynamicEnvMap() { SetDeviceRef(nil); int i; for( i = 0; i < 6; i++ ) delete fReqMsgs[i]; } void plDynamicEnvMap::Init() { plgDispatch::Dispatch()->RegisterForExactType(plPipeRTMakeMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plAgeLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey()); ISetupRenderRequests(); } hsPoint3 plDynamicEnvMap::GetPosition() const { if (fRootNode) { // This is to catch export issues where we've got a root node, but its iface // hasn't fully been set up yet. if (fRootNode->GetCoordinateInterface()) return fRootNode->GetLocalToWorld().GetTranslate(); } return fPos; } void plDynamicEnvMap::SetPosition(const hsPoint3& pos) { hsAssert(fRootNode == nil, "Trying to override a cube map's root node."); fPos = pos; SetCameraMatrix(fPos); } void plDynamicEnvMap::IUpdatePosition() { hsPoint3 pos = GetPosition(); if (pos != fPos) SetCameraMatrix(fPos); } void plDynamicEnvMap::SetHither(hsScalar f) { fHither = f; } void plDynamicEnvMap::SetYon(hsScalar f) { fYon = f; } void plDynamicEnvMap::SetFogStart(hsScalar f) { fFogStart = f; } void plDynamicEnvMap::SetColor(const hsColorRGBA& col) { fColor = col; } void plDynamicEnvMap::SetRefreshRate(hsScalar secs) { fRefreshRate = secs / 6.f; plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey()); } void plDynamicEnvMap::ISetupRenderRequests() { UInt32 renderState = plPipeline::kRenderNormal | plPipeline::kRenderClearColor | plPipeline::kRenderClearDepth; int i; for( i = 0; i < 6; i++ ) { fReqs[i].SetRenderState(renderState); fReqs[i].SetDrawableMask(plDrawable::kNormal); fReqs[i].SetSubDrawableMask(plDrawable::kSubAllTypes); fReqs[i].SetHither(fHither); fReqs[i].SetYon(fYon); fReqs[i].SetFogStart(fFogStart); fReqs[i].SetFovX(90.f); fReqs[i].SetFovY(90.f); fReqs[i].SetClearColor(fColor); fReqs[i].SetClearDepth(1.f); fReqs[i].SetClearDrawable(nil); fReqs[i].SetRenderTarget(GetFace(i)); fReqs[i].SetCameraTransform(GetWorldToCamera(i), GetCameraToWorld(i)); fReqs[i].SetVisForce(fVisSet); fReqs[i].RequestAck(GetKey()); } } void plDynamicEnvMap::ISubmitRenderRequest(int i) { IUpdatePosition(); fReqMsgs[i]->SendAndKeep(); fLastRender = i; fOutStanding++; } void plDynamicEnvMap::ISubmitRenderRequests() { IUpdatePosition(); int i; for( i = 0; i < 6; i++ ) fReqMsgs[i]->SendAndKeep(); fLastRefresh = hsTimer::GetSysSeconds(); fOutStanding += 6; } void plDynamicEnvMap::ICheckForRefresh(double t, plPipeline *pipe) { if( fLastRefresh <= 0 ) { ISubmitRenderRequests(); return; } if( fRefreshRate <= 0 ) return; #ifndef PLASMA_EXTERNAL_RELEASE if (pipe->IsDebugFlagSet(plPipeDbg::kFlagNVPerfHUD) && hsTimer::GetDelSysSeconds() == 0) { ISubmitRenderRequests(); return; } #endif // PLASMA_EXTERNAL_RELEASE if( t > fLastRefresh + 6.f * fRefreshRate ) { ISubmitRenderRequests(); return; } while( t > fLastRefresh + fRefreshRate ) { int nextRender = fLastRender+1; if( nextRender > 5 ) nextRender = 0; ISubmitRenderRequest(nextRender); fLastRefresh += fRefreshRate; } } void plDynamicEnvMap::ReRender() { ISetupRenderRequests(); ISubmitRenderRequests(); } hsBool plDynamicEnvMap::INeedReRender() { fOutStanding = 0; fLastRefresh = 0; return true; } hsBool plDynamicEnvMap::MsgReceive(plMessage* msg) { plRenderRequestAck* ack = plRenderRequestAck::ConvertNoRef(msg); if( ack ) { fOutStanding--; return true; } plRenderMsg* rendMsg = plRenderMsg::ConvertNoRef(msg); if( rendMsg ) { if( fOutStanding ) INeedReRender(); ICheckForRefresh(hsTimer::GetSysSeconds(), rendMsg->Pipeline()); return true; } if( plPipeRTMakeMsg::ConvertNoRef(msg) ) { INeedReRender(); plCubicRenderTarget::MsgReceive(msg); return true; } plAgeLoadedMsg* ageLoaded = plAgeLoadedMsg::ConvertNoRef(msg); if( ageLoaded && ageLoaded->fLoaded ) return INeedReRender(); if( plInitialAgeStateLoadedMsg::ConvertNoRef(msg) ) return INeedReRender(); plDynamicEnvMapMsg* cmd = plDynamicEnvMapMsg::ConvertNoRef(msg); if( cmd ) { if( cmd->fCmd & plDynamicEnvMapMsg::kSetPosition ) SetPosition(cmd->fPos); if( cmd->fCmd & plDynamicEnvMapMsg::kSetHither ) SetHither(cmd->fHither); if( cmd->fCmd & plDynamicEnvMapMsg::kSetFogStart ) SetFogStart(cmd->fFogStart); if( cmd->fCmd & plDynamicEnvMapMsg::kSetYon ) SetYon(cmd->fYon); if( cmd->fCmd & plDynamicEnvMapMsg::kSetColor ) SetColor(cmd->fColor); if( cmd->fCmd & plDynamicEnvMapMsg::kSetRefresh ) SetRefreshRate(cmd->fRefresh); // If we're going to ReRender, make sure we've gotten any // parameter changes first. if( cmd->fCmd & plDynamicEnvMapMsg::kReRender ) { ISetupRenderRequests(); INeedReRender(); } return true; } plGenRefMsg* refMsg = plGenRefMsg::ConvertNoRef(msg); if( refMsg ) { if( IOnRefMsg(refMsg) ) return true; } return plCubicRenderTarget::MsgReceive(msg); } hsBool plDynamicEnvMap::IOnRefMsg(plGenRefMsg* refMsg) { switch( refMsg->fType) { case kRefVisSet: if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) ) { plVisRegion* reg = plVisRegion::ConvertNoRef(refMsg->GetRef()); int idx = fVisRegions.Find(reg); if( reg && (fVisRegions.kMissingIndex == idx) ) { fVisRegions.Append(reg); fVisSet.SetBit(reg->GetIndex()); } ISetupRenderRequests(); return true; } else { plVisRegion* reg = plVisRegion::ConvertNoRef(refMsg->GetRef()); int idx = fVisRegions.Find(reg); if( reg && (fVisRegions.kMissingIndex != idx) ) { fVisRegions.Remove(idx); fVisSet.ClearBit(reg->GetIndex()); } ISetupRenderRequests(); return true; } break; case kRefRootNode: plSceneObject *so = plSceneObject::ConvertNoRef(refMsg->GetRef()); if( refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace) ) fRootNode = so; else fRootNode = nil; return true; } return false; } void plDynamicEnvMap::SetIncludeCharacters(hsBool b) { fIncCharacters = b; if( b ) fVisSet.SetBit(plVisMgr::kCharacter); else fVisSet.ClearBit(plVisMgr::kCharacter); } void plDynamicEnvMap::AddVisRegion(plVisRegion* reg) { plGenRefMsg* msg = TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnRequest, 0, kRefVisSet); hsgResMgr::ResMgr()->AddViaNotify(reg->GetKey(), msg, plRefFlags::kActiveRef); } void plDynamicEnvMap::Read(hsStream* s, hsResMgr* mgr) { hsKeyedObject::Read(s, mgr); UInt32 sz = plCubicRenderTarget::Read(s); fPos.Read(s); fHither = s->ReadSwapScalar(); fYon = s->ReadSwapScalar(); fFogStart = s->ReadSwapScalar(); fColor.Read(s); fRefreshRate = s->ReadSwapScalar(); SetPosition(fPos); sz += sizeof(fPos) + sizeof(fHither) + sizeof(fYon) + sizeof(fFogStart) + sizeof(fColor) + sizeof(fRefreshRate); fIncCharacters = s->ReadByte(); SetIncludeCharacters(fIncCharacters); int nVis = s->ReadSwap32(); int i; for( i = 0; i < nVis; i++ ) mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, -1, kRefVisSet), plRefFlags::kActiveRef); nVis = s->ReadSwap32(); for( i = 0; i < nVis; i++) { char *name = s->ReadSafeString(); plKey key = plKeyFinder::Instance().StupidSearch(nil, nil, plVisRegion::Index(), name); delete[] name; if (key) hsgResMgr::ResMgr()->AddViaNotify(key, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, -1, kRefVisSet), plRefFlags::kActiveRef); } mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, -1, kRefRootNode), plRefFlags::kActiveRef); Init(); } void plDynamicEnvMap::Write(hsStream* s, hsResMgr* mgr) { hsKeyedObject::Write(s, mgr); UInt32 sz = plCubicRenderTarget::Write(s); fPos.Write(s); s->WriteSwapScalar(fHither); s->WriteSwapScalar(fYon); s->WriteSwapScalar(fFogStart); fColor.Write(s); s->WriteSwapScalar(fRefreshRate); sz += sizeof(fPos) + sizeof(fHither) + sizeof(fYon) + sizeof(fFogStart) + sizeof(fColor) + sizeof(fRefreshRate); s->WriteByte(fIncCharacters); s->WriteSwap32(fVisRegions.GetCount()); int i; for( i = 0; i < fVisRegions.GetCount(); i++ ) mgr->WriteKey(s, fVisRegions[i]); s->WriteSwap32(fVisRegionNames.Count()); for( i = 0; i < fVisRegionNames.Count(); i++) { s->WriteSafeString(fVisRegionNames[i]); } mgr->WriteKey(s, fRootNode); } ////////////////////////////////////////////////////////////////////////////////////////////////////// UInt8 plDynamicCamMap::fFlags = kReflectionEnabled | kReflectionCapable; plDynamicCamMap::plDynamicCamMap() : fHither(0.3f), fYon(500.f), fFogStart(1000.f), fRefreshRate(0.f), fLastRefresh(0.0), fOutStanding(0), fCamera(nil), fRootNode(nil), fIncCharacters(false), fDisableTexture(nil) { fColor.Set(0,0,0,1.f); fReqMsg = TRACKED_NEW plRenderRequestMsg(nil, &fReq); } plDynamicCamMap::plDynamicCamMap(UInt16 width, UInt16 height, UInt8 bitDepth, UInt8 zDepth, UInt8 sDepth) : fHither(0.3f), fYon(-1.f), fFogStart(-1.f), fRefreshRate(0.f), fLastRefresh(0.0), fOutStanding(0), fCamera(nil), fRootNode(nil), fIncCharacters(false), fDisableTexture(nil), plRenderTarget(plRenderTarget::kIsTexture, width, height, bitDepth, zDepth, sDepth) { fColor.Set(0,0,0,1.f); fReqMsg = TRACKED_NEW plRenderRequestMsg(nil, &fReq); } plDynamicCamMap::~plDynamicCamMap() { plgDispatch::Dispatch()->UnRegisterForExactType(plPipeRTMakeMsg::Index(), GetKey()); plgDispatch::Dispatch()->UnRegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->UnRegisterForExactType(plAgeLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->UnRegisterForExactType(plRenderMsg::Index(), GetKey()); SetDeviceRef(nil); delete fReqMsg; } void plDynamicCamMap::Init() { plgDispatch::Dispatch()->RegisterForExactType(plPipeRTMakeMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plInitialAgeStateLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plAgeLoadedMsg::Index(), GetKey()); plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey()); } void plDynamicCamMap::SetRefreshRate(hsScalar secs) { fRefreshRate = secs; plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey()); } void plDynamicCamMap::ISetupRenderRequest(plPipeline *pipe) { fReq.SetRenderState(plPipeline::kRenderNormal | plPipeline::kRenderClearColor | plPipeline::kRenderClearDepth); fReq.SetDrawableMask(plDrawable::kNormal); fReq.SetSubDrawableMask(plDrawable::kSubAllTypes); fReq.SetHither(fHither); fReq.SetYon(fYon); fReq.SetFogStart(fFogStart); // For a reflection map, this must match the camera FOV, or else the camera based // texture coordinates for the reflection texture will be off. // // For a fixed camera, you might want to use the height in both params, so that // you're rendering a square FOV into your square texture. In practice, the artists // don't mind the visual results when just scaling their UVs, so I'll leave it the // same for both cases. fReq.SetFovX(fCamera ? fCamera->GetFOVw() : plVirtualCam1::Instance()->GetFOVw()); fReq.SetFovY(fCamera ? fCamera->GetFOVh() : plVirtualCam1::Instance()->GetFOVh()); fReq.SetClearColor(fColor); fReq.SetClearDepth(1.f); fReq.SetClearDrawable(nil); fReq.SetRenderTarget(this); fReq.SetVisForce(fVisSet); fReq.SetIgnoreOccluders(true); fReq.RequestAck(GetKey()); hsMatrix44 w2c, c2w; if (fCamera) { w2c.MakeCamera(&fCamera->GetTargetPos(), &fCamera->GetTargetPOA(), &hsVector3(0.f, 0.f, 1.f)); w2c.GetInverse(&c2w); } else { if (!fRootNode) return; // Could be optimized, but the matrix construction work here seems cheap relative to the cost // of rerendering all this stuff to a separate target, so I doubt we'd notice. hsMatrix44 invert; invert.MakeScaleMat(&(hsVector3(1.f, 1.f, -1.f))); w2c = pipe->GetWorldToCamera(); c2w = pipe->GetCameraToWorld(); w2c = w2c * fRootNode->GetLocalToWorld() * invert * fRootNode->GetWorldToLocal(); c2w = fRootNode->GetWorldToLocal() * invert * fRootNode->GetLocalToWorld() * c2w; } fReq.SetCameraTransform(w2c, c2w); } void plDynamicCamMap::ISubmitRenderRequest(plPipeline *pipe) { ISetupRenderRequest(pipe); fReqMsg->SendAndKeep(); fOutStanding++; fLastRefresh = hsTimer::GetSysSeconds(); } void plDynamicCamMap::ICheckForRefresh(double t, plPipeline *pipe) { int i; hsBool useRefl = (fFlags & kReflectionMask) == kReflectionMask; if (!fCamera) { if ((useRefl && fMatLayers[0]->GetTexture() != this) || (!useRefl && fMatLayers[0]->GetTexture() != fDisableTexture)) IPrepTextureLayers(); } // So no one's using us, eh? Hitting this condition is likely a bug, // but an assert every frame would be annoying. We'll notice when // the render target never updates. if (fTargetNodes.GetCount() == 0) return; // If dynamic planar reflections are disabled and we're using our substitute // texture, don't update. Otherwise, this particular reflection is forced to // always display. if (!useRefl && fDisableTexture) return; hsBool inView = false; for (i = 0; i < fTargetNodes.GetCount(); i++) { if (pipe->TestVisibleWorld(fTargetNodes[i])) { inView = true; break; } } if (!inView) return; if( fLastRefresh <= 0 ) { ISubmitRenderRequest(pipe); return; } if( fRefreshRate <= 0 ) return; #ifndef PLASMA_EXTERNAL_RELEASE if (pipe->IsDebugFlagSet(plPipeDbg::kFlagNVPerfHUD) && hsTimer::GetDelSysSeconds() == 0) { ISubmitRenderRequest(pipe); } #endif // PLASMA_EXTERNAL_RELEASE if (t > fLastRefresh + fRefreshRate) { ISubmitRenderRequest(pipe); return; } } hsBool plDynamicCamMap::INeedReRender() { fOutStanding = 0; fLastRefresh = 0; return true; } hsBool plDynamicCamMap::MsgReceive(plMessage* msg) { plRenderRequestAck* ack = plRenderRequestAck::ConvertNoRef(msg); if( ack ) { fOutStanding--; return true; } plRenderMsg* rendMsg = plRenderMsg::ConvertNoRef(msg); if( rendMsg ) { if( fOutStanding ) INeedReRender(); ICheckForRefresh(hsTimer::GetSysSeconds(), rendMsg->Pipeline()); return true; } if( plPipeRTMakeMsg::ConvertNoRef(msg) ) { INeedReRender(); plRenderTarget::MsgReceive(msg); return true; } plAgeLoadedMsg* ageLoaded = plAgeLoadedMsg::ConvertNoRef(msg); if( ageLoaded && ageLoaded->fLoaded ) return INeedReRender(); if( plInitialAgeStateLoadedMsg::ConvertNoRef(msg) ) return INeedReRender(); plDynamicEnvMapMsg* cmd = plDynamicEnvMapMsg::ConvertNoRef(msg); if( cmd ) { if( cmd->fCmd & plDynamicEnvMapMsg::kSetFogStart ) fFogStart = cmd->fFogStart; if( cmd->fCmd & plDynamicEnvMapMsg::kSetColor ) fColor = cmd->fColor; if( cmd->fCmd & plDynamicEnvMapMsg::kSetRefresh ) SetRefreshRate(cmd->fRefresh); return true; } plRefMsg* refMsg = plRefMsg::ConvertNoRef(msg); if( refMsg ) { if( IOnRefMsg(refMsg) ) return true; } return plRenderTarget::MsgReceive(msg); } void plDynamicCamMap::IPrepTextureLayers() { if (fDisableTexture) { int i; for (i = 0; i < fMatLayers.GetCount(); i++) { if ((fFlags & kReflectionMask) == kReflectionMask) { fMatLayers[i]->SetUVWSrc(plLayerInterface::kUVWPosition); fMatLayers[i]->SetMiscFlags(hsGMatState::kMiscCam2Screen | hsGMatState::kMiscPerspProjection); hsgResMgr::ResMgr()->SendRef(GetKey(), TRACKED_NEW plGenRefMsg(fMatLayers[i]->GetKey(), plRefMsg::kOnRequest, 0, plLayRefMsg::kTexture), plRefFlags::kActiveRef); } else { fMatLayers[i]->SetUVWSrc(0); fMatLayers[i]->SetMiscFlags(0); hsgResMgr::ResMgr()->SendRef(fDisableTexture->GetKey(), TRACKED_NEW plGenRefMsg(fMatLayers[i]->GetKey(), plRefMsg::kOnRequest, 0, plLayRefMsg::kTexture), plRefFlags::kActiveRef); } } } } hsBool plDynamicCamMap::IOnRefMsg(plRefMsg* refMsg) { plGenRefMsg* genRefMsg = plGenRefMsg::ConvertNoRef(refMsg); if (genRefMsg) { if (genRefMsg->fType == kRefVisSet) { plVisRegion* reg = plVisRegion::ConvertNoRef(refMsg->GetRef()); if (reg) { int idx = fVisRegions.Find(reg); if ((refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace)) && fVisRegions.kMissingIndex == idx) { fVisRegions.Append(reg); fVisSet.SetBit(reg->GetIndex()); } else if (!(refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace)) && fVisRegions.kMissingIndex != idx) { fVisRegions.Remove(idx); fVisSet.ClearBit(reg->GetIndex()); } return true; } } else if (genRefMsg->fType == kRefCamera) { plCameraModifier1 *cam = plCameraModifier1::ConvertNoRef(refMsg->GetRef()); if (cam) { if (refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace)) fCamera = cam; else fCamera = nil; return true; } } else if (genRefMsg->fType == kRefRootNode) { plSceneObject *so = plSceneObject::ConvertNoRef(refMsg->GetRef()); if (so) { if (refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace)) fRootNode = so; else fRootNode = nil; return true; } } else if (genRefMsg->fType == kRefTargetNode) { plSceneObject *so = plSceneObject::ConvertNoRef(refMsg->GetRef()); if (so) { if (refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace)) { if (fTargetNodes.Find(so) == fTargetNodes.kMissingIndex) fTargetNodes.Append(so); } else { fTargetNodes.RemoveItem(so); } return true; } } else if (genRefMsg->fType == kRefDisableTexture) { plBitmap *bitmap = plBitmap::ConvertNoRef(refMsg->GetRef()); if (bitmap) { if (refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace)) fDisableTexture = bitmap; else fDisableTexture = nil; return true; } } else if (genRefMsg->fType == kRefMatLayer) { plLayer *lay = plLayer::ConvertNoRef(refMsg->GetRef()); if (lay) { if (refMsg->GetContext() & (plRefMsg::kOnCreate|plRefMsg::kOnRequest|plRefMsg::kOnReplace)) { if (fMatLayers.Find(lay) == fMatLayers.kMissingIndex) fMatLayers.Append(lay); } else { fMatLayers.RemoveItem(lay); } return true; } } } return false; } void plDynamicCamMap::SetIncludeCharacters(hsBool b) { fIncCharacters = b; if( b ) fVisSet.SetBit(plVisMgr::kCharacter); else fVisSet.ClearBit(plVisMgr::kCharacter); } void plDynamicCamMap::AddVisRegion(plVisRegion* reg) { hsgResMgr::ResMgr()->AddViaNotify( reg->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plGenRefMsg::kOnReplace, -1, kRefVisSet ), plRefFlags::kActiveRef ); } void plDynamicCamMap::SetEnabled(hsBool enable) { if (enable) fFlags |= kReflectionEnabled; else fFlags &= ~kReflectionEnabled; } void plDynamicCamMap::SetCapable(hsBool capable) { if (capable) fFlags |= kReflectionCapable; else fFlags &= ~kReflectionCapable; } void plDynamicCamMap::Read(hsStream* s, hsResMgr* mgr) { hsKeyedObject::Read(s, mgr); plRenderTarget::Read(s); fHither = s->ReadSwapScalar(); fYon = s->ReadSwapScalar(); fFogStart = s->ReadSwapScalar(); fColor.Read(s); fRefreshRate = s->ReadSwapScalar(); fIncCharacters = s->ReadBool(); SetIncludeCharacters(fIncCharacters); mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefCamera), plRefFlags::kPassiveRef); mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefRootNode), plRefFlags::kActiveRef); int numTargs = s->ReadByte(); int i; for (i = 0; i < numTargs; i++) mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, i, kRefTargetNode), plRefFlags::kPassiveRef); int nVis = s->ReadSwap32(); for( i = 0; i < nVis; i++ ) mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefVisSet), plRefFlags::kActiveRef); nVis = s->ReadSwap32(); for( i = 0; i < nVis; i++) { char *name = s->ReadSafeString(); plKey key = plKeyFinder::Instance().StupidSearch(nil, nil, plVisRegion::Index(), name); delete[] name; if (key) hsgResMgr::ResMgr()->AddViaNotify(key, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, -1, kRefVisSet), plRefFlags::kActiveRef); } mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefDisableTexture), plRefFlags::kActiveRef); UInt8 numLayers = s->ReadByte(); for (i = 0; i < numLayers; i++) { mgr->ReadKeyNotifyMe(s, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefMatLayer), plRefFlags::kPassiveRef); } Init(); } void plDynamicCamMap::Write(hsStream* s, hsResMgr* mgr) { hsKeyedObject::Write(s, mgr); plRenderTarget::Write(s); s->WriteSwapScalar(fHither); s->WriteSwapScalar(fYon); s->WriteSwapScalar(fFogStart); fColor.Write(s); s->WriteSwapScalar(fRefreshRate); s->WriteByte(fIncCharacters); mgr->WriteKey(s, (fCamera ? fCamera->GetKey() : nil)); mgr->WriteKey(s, (fRootNode ? fRootNode->GetKey() : nil)); s->WriteByte(fTargetNodes.GetCount()); int i; for (i = 0; i < fTargetNodes.GetCount(); i++) mgr->WriteKey(s, fTargetNodes[i]); s->WriteSwap32(fVisRegions.GetCount()); for( i = 0; i < fVisRegions.GetCount(); i++ ) mgr->WriteKey(s, fVisRegions[i]); s->WriteSwap32(fVisRegionNames.Count()); for( i = 0; i < fVisRegionNames.Count(); i++) { s->WriteSafeString(fVisRegionNames[i]); } mgr->WriteKey(s, fDisableTexture ? fDisableTexture->GetKey() : nil); s->WriteByte(fMatLayers.GetCount()); for (i = 0; i < fMatLayers.GetCount(); i++) { mgr->WriteKey(s, fMatLayers[i]->GetKey()); } }