/*==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 "plFadeOpacityMod.h" #include "plFadeOpacityLay.h" #include "../plMessage/plRenderMsg.h" #include "../plMessage/plMatRefMsg.h" #include "../plSurface/hsGMaterial.h" #include "../plDrawable/plVisLOSMgr.h" #include "../plDrawable/plAccessGeometry.h" #include "../plDrawable/plAccessSpan.h" #include "../plDrawable/plDrawableSpans.h" #include "../pnSceneObject/plSceneObject.h" #include "../pnSceneObject/plDrawInterface.h" #include "../plScene/plVisMgr.h" #include "plgDispatch.h" #include "plPipeline.h" #include "hsBounds.h" #include "hsTimer.h" #include "hsResMgr.h" /* curr = (t - t0) / fadeUp; curr = 1. - (t - t0) / fadeDown; switch from fadeUp to fadeDown curr = 1 - (t - t0) / fadeDown; t - t0 = (1 - curr) * fadeDown t0 = t - (1 - curr) * fadeDown; switch from fadeDown to fadeUp curr = (t - t0) / fadeUp; curr * fadeUp = t - t0; t0 = t - curr * fadeUp; */ hsBool plFadeOpacityMod::fLOSCheckDisabled = false; const hsScalar kDefFadeUp(5.f); const hsScalar kDefFadeDown(1.f); plFadeOpacityMod::plFadeOpacityMod() : fFadeUp(kDefFadeUp), fFadeDown(kDefFadeDown), fOpCurrent(1.f), fStart(0), fFade(kImmediate), fLastEye(0.f, 0.f, 0.f), fSetup(false) { } plFadeOpacityMod::~plFadeOpacityMod() { } hsBool plFadeOpacityMod::MsgReceive(plMessage* msg) { plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg); if( rend ) { IOnRenderMsg(rend); return true; } return plSingleModifier::MsgReceive(msg); } void plFadeOpacityMod::SetKey(plKey k) { hsKeyedObject::SetKey(k); if( k ) { plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey()); } } void plFadeOpacityMod::Read(hsStream* s, hsResMgr* mgr) { plSingleModifier::Read(s, mgr); fFadeUp = s->ReadSwapScalar(); fFadeDown = s->ReadSwapScalar(); } void plFadeOpacityMod::Write(hsStream* s, hsResMgr* mgr) { plSingleModifier::Write(s, mgr); s->WriteSwapScalar(fFadeUp); s->WriteSwapScalar(fFadeDown); } void plFadeOpacityMod::SetTarget(plSceneObject* so) { plSingleModifier::SetTarget(so); fSetup = false; } hsBool plFadeOpacityMod::IShouldCheck(plPipeline* pipe) { if (pipe->TestVisibleWorld(GetTarget())) return true; fFade = kImmediate; return false; } void plFadeOpacityMod::IOnRenderMsg(plRenderMsg* rend) { // Okay, are we set up enough to proceed? if( !IReady() ) return; // Okay, we're going to check. hsBool hit = false; if( !fLOSCheckDisabled ) { // Should we check to see if we're visible before anything else? if( !IShouldCheck(rend->Pipeline()) ) return; hsPoint3 eyePos = rend->Pipeline()->GetViewPositionWorld(); hsPoint3 ourPos = IGetOurPos(); if( fFade != kImmediate ) { // If we've moved more than 3 feet in a frame, we'll consider this a // camera cut. In that case, don't fade up or down, just go there. const hsScalar kCutMagSquared = 3.f * 3.f; if( hsVector3(&eyePos, &fLastEye).MagnitudeSquared() > kCutMagSquared ) fFade = kImmediate; } fLastEye = eyePos; // Cast the ray from eye to us. plVisHit hitInfo; hit = plVisLOSMgr::Instance()->Check(eyePos, ourPos, hitInfo); } // If the ray made it, fade us up // Else fade us down. if( !hit ) IFadeUp(); else IFadeDown(); ISetOpacity(); } hsBool plFadeOpacityMod::IReady() { plSceneObject* so = GetTarget(); if( !so ) return false; if( !so->GetDrawInterface() ) return false; if( !fSetup ) ISetup(so); if( !fFadeLays.GetCount() ) return false; return true; } hsPoint3 plFadeOpacityMod::IGetOurPos() { hsAssert(GetTarget(), "Weed out target-less earlier"); if( HasFlag(kBoundsCenter) ) { return GetTarget()->GetDrawInterface()->GetWorldBounds().GetCenter(); } else { return GetTarget()->GetLocalToWorld().GetTranslate(); } } void plFadeOpacityMod::ICalcOpacity() { double t = hsTimer::GetSysSeconds(); switch( fFade ) { case kFadeUp: fOpCurrent = (hsScalar)(t - fStart); if( fOpCurrent > fFadeUp ) { fOpCurrent = 1.f; fFade = kUp; } else { fOpCurrent /= fFadeUp; } break; case kFadeDown: fOpCurrent = (hsScalar)(t - fStart); if( fOpCurrent > fFadeDown ) { fOpCurrent = 0.f; fFade = kDown; } else { fOpCurrent = 1.f - fOpCurrent / fFadeDown; } break; case kUp: case kDown: break; case kImmediate: default: hsAssert(false, "Invalid state"); break; }; } void plFadeOpacityMod::ISetOpacity() { ICalcOpacity(); const int num = fFadeLays.GetCount(); int i; for( i = 0; i < num; i++ ) fFadeLays[i]->SetOpacity(fOpCurrent); } void plFadeOpacityMod::IFadeUp() { const double t = hsTimer::GetSysSeconds(); switch( fFade ) { case kImmediate: fOpCurrent = 1.f; fFade = kUp; break; case kFadeDown: { fStart = t - fOpCurrent * fFadeUp; fFade = kFadeUp; } break; case kDown: { fStart = t; fFade = kFadeUp; } break; case kUp: case kFadeUp: break; default: hsAssert(false, "Bad State"); break; }; } void plFadeOpacityMod::IFadeDown() { const double t = hsTimer::GetSysSeconds(); switch( fFade ) { case kImmediate: fOpCurrent = 0.f; fFade = kDown; break; case kFadeUp: { fStart = t - (1.f - fOpCurrent) * fFadeDown; fFade = kFadeDown; } break; case kUp: { fStart = t; fFade = kFadeDown; } case kFadeDown: case kDown: break; default: hsAssert(false, "Bad State"); break; }; } void plFadeOpacityMod::ISetup(plSceneObject* so) { fFadeLays.Reset(); if( !so ) return; const plDrawInterface* di = so->GetDrawInterface(); if( !di ) return; hsTArray src; plAccessGeometry::Instance()->OpenRO(di, src, false); int i; for( i = 0; i < src.GetCount(); i++ ) { hsGMaterial* mat = src[i].GetMaterial(); int j; for( j = 0; j < mat->GetNumLayers(); j++ ) { plLayerInterface* lay = mat->GetLayer(j); if( !j || !(lay->GetZFlags() & hsGMatState::kZNoZWrite) || (lay->GetMiscFlags() & hsGMatState::kMiscRestartPassHere) ) { plFadeOpacityLay* fade = NEW(plFadeOpacityLay); hsgResMgr::ResMgr()->NewKey(lay->GetKey()->GetName(), fade, lay->GetKey()->GetUoid().GetLocation()); fade->AttachViaNotify(lay); // We should add a ref or something here if we're going to hold on to this (even though we created and "own" it). fFadeLays.Append(fade); plMatRefMsg* msg = NEW(plMatRefMsg)(mat->GetKey(), plRefMsg::kOnReplace, i, plMatRefMsg::kLayer); msg->SetOldRef(lay); hsgResMgr::ResMgr()->SendRef(fade, msg, plRefFlags::kActiveRef); plGenRefMsg* toMe = NEW(plGenRefMsg)(GetKey(), plRefMsg::kOnRequest, 0, kRefFadeLay); hsgResMgr::ResMgr()->SendRef(fade, toMe, plRefFlags::kPassiveRef); } } } plAccessGeometry::Instance()->Close(src); fSetup = true; fFade = kImmediate; }