You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
7.8 KiB

/*==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 "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<plAccessSpan> 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;
}