|
|
|
/*==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/>.
|
|
|
|
|
|
|
|
Additional permissions under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
If you modify this Program, or any covered work, by linking or
|
|
|
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
|
|
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
|
|
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
|
|
|
(or a modified version of those libraries),
|
|
|
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
|
|
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
|
|
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
|
|
|
licensors of this Program grant you additional
|
|
|
|
permission to convey the resulting work. Corresponding Source for a
|
|
|
|
non-source form of such a combination shall include the source code for
|
|
|
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
|
|
|
work.
|
|
|
|
|
|
|
|
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 "plDistOpacityMod.h"
|
|
|
|
|
|
|
|
#include "plFadeOpacityLay.h"
|
|
|
|
#include "../plSurface/hsGMaterial.h"
|
|
|
|
|
|
|
|
#include "../plDrawable/plAccessGeometry.h"
|
|
|
|
#include "../plDrawable/plAccessSpan.h"
|
|
|
|
|
|
|
|
#include "../plMessage/plMatRefMsg.h"
|
|
|
|
|
|
|
|
// If we're tracking the camera
|
|
|
|
#include "../plMessage/plRenderMsg.h"
|
|
|
|
#include "plPipeline.h"
|
|
|
|
|
|
|
|
// If we're tracking the avater
|
|
|
|
#include "../plMessage/plAvatarMsg.h"
|
|
|
|
#include "../plAvatar/plArmatureMod.h"
|
|
|
|
|
|
|
|
#include "plgDispatch.h"
|
|
|
|
#include "hsResMgr.h"
|
|
|
|
#include "hsQuat.h"
|
|
|
|
|
|
|
|
plDistOpacityMod::plDistOpacityMod()
|
|
|
|
: fSetup(false)
|
|
|
|
{
|
|
|
|
fDists[kNearTrans] = 0;
|
|
|
|
fDists[kNearOpaq] = 0;
|
|
|
|
fDists[kFarOpaq] = 0;
|
|
|
|
fDists[kFarTrans] = 0;
|
|
|
|
|
|
|
|
fRefPos.Set(0, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
plDistOpacityMod::~plDistOpacityMod()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void plDistOpacityMod::SetKey(plKey k)
|
|
|
|
{
|
|
|
|
plSingleModifier::SetKey(k);
|
|
|
|
|
|
|
|
plgDispatch::Dispatch()->RegisterForExactType(plRenderMsg::Index(), GetKey());
|
|
|
|
plgDispatch::Dispatch()->RegisterForExactType(plArmatureUpdateMsg::Index(), GetKey());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hsScalar plDistOpacityMod::ICalcOpacity(const hsPoint3& targPos, const hsPoint3& refPos) const
|
|
|
|
{
|
|
|
|
hsScalar dist = hsVector3(&targPos, &refPos).Magnitude();
|
|
|
|
|
|
|
|
if( dist > fDists[kFarTrans] )
|
|
|
|
return 0;
|
|
|
|
if( dist < fDists[kNearTrans] )
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if( dist > fDists[kFarOpaq] )
|
|
|
|
{
|
|
|
|
dist -= fDists[kFarOpaq];
|
|
|
|
dist /= (fDists[kFarTrans] - fDists[kFarOpaq]);
|
|
|
|
hsAssert(dist >= 0, "unexpected interpolation param - neg");
|
|
|
|
hsAssert(dist <= 1.f, "unexpected interpolation param - > one");
|
|
|
|
|
|
|
|
return 1.f - dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
if( dist < fDists[kNearOpaq] )
|
|
|
|
{
|
|
|
|
dist -= fDists[kNearTrans];
|
|
|
|
dist /= (fDists[kNearOpaq] - fDists[kNearTrans]);
|
|
|
|
hsAssert(dist >= 0, "unexpected interpolation param - neg");
|
|
|
|
hsAssert(dist <= 1.f, "unexpected interpolation param - > one");
|
|
|
|
|
|
|
|
return dist;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1.f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plDistOpacityMod::ISetOpacity()
|
|
|
|
{
|
|
|
|
if( !GetTarget() )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if( !fSetup )
|
|
|
|
ISetup();
|
|
|
|
|
|
|
|
hsScalar opacity = ICalcOpacity(GetTarget()->GetLocalToWorld().GetTranslate(), fRefPos);
|
|
|
|
|
|
|
|
const int num = fFadeLays.GetCount();
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < num; i++ )
|
|
|
|
fFadeLays[i]->SetOpacity(opacity);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
hsBool plDistOpacityMod::MsgReceive(plMessage* msg)
|
|
|
|
{
|
|
|
|
plArmatureUpdateMsg* arm = plArmatureUpdateMsg::ConvertNoRef(msg);
|
|
|
|
if( arm && arm->IsLocal() )
|
|
|
|
{
|
|
|
|
arm->fArmature->GetPositionAndRotationSim(&fRefPos, nil);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
plRenderMsg* rend = plRenderMsg::ConvertNoRef(msg);
|
|
|
|
if( rend )
|
|
|
|
{
|
|
|
|
if( HasFlag(kTrackCamera) )
|
|
|
|
fRefPos = rend->Pipeline()->GetViewPositionWorld();
|
|
|
|
|
|
|
|
ISetOpacity();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
plGenRefMsg* ref = plGenRefMsg::ConvertNoRef(msg);
|
|
|
|
if( ref )
|
|
|
|
{
|
|
|
|
switch(ref->fType)
|
|
|
|
{
|
|
|
|
case kRefFadeLay:
|
|
|
|
if( ref->GetContext() & (plRefMsg::kOnDestroy|plRefMsg::kOnRemove) )
|
|
|
|
{
|
|
|
|
plFadeOpacityLay* lay = plFadeOpacityLay::ConvertNoRef(ref->GetRef());
|
|
|
|
int idx = fFadeLays.Find(lay);
|
|
|
|
if( idx != fFadeLays.kMissingIndex )
|
|
|
|
fFadeLays.Remove(idx);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return plSingleModifier::MsgReceive(msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plDistOpacityMod::Read(hsStream* s, hsResMgr* mgr)
|
|
|
|
{
|
|
|
|
plSingleModifier::Read(s, mgr);
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < kNumDists; i++ )
|
|
|
|
fDists[i] = s->ReadSwapScalar();
|
|
|
|
|
|
|
|
ICheckDists();
|
|
|
|
|
|
|
|
fSetup = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plDistOpacityMod::Write(hsStream* s, hsResMgr* mgr)
|
|
|
|
{
|
|
|
|
plSingleModifier::Write(s, mgr);
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for( i = 0; i < kNumDists; i++ )
|
|
|
|
s->WriteSwapScalar(fDists[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void plDistOpacityMod::SetTarget(plSceneObject* so)
|
|
|
|
{
|
|
|
|
plSingleModifier::SetTarget(so);
|
|
|
|
|
|
|
|
fSetup = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void plDistOpacityMod::SetFarDist(hsScalar opaque, hsScalar transparent)
|
|
|
|
{
|
|
|
|
fDists[kFarOpaq] = opaque;
|
|
|
|
fDists[kFarTrans] = transparent;
|
|
|
|
|
|
|
|
ICheckDists();
|
|
|
|
}
|
|
|
|
|
|
|
|
void plDistOpacityMod::SetNearDist(hsScalar transparent, hsScalar opaque)
|
|
|
|
{
|
|
|
|
fDists[kNearOpaq] = opaque;
|
|
|
|
fDists[kNearTrans] = transparent;
|
|
|
|
|
|
|
|
ICheckDists();
|
|
|
|
}
|
|
|
|
|
|
|
|
class MatLayer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
hsGMaterial* fMat;
|
|
|
|
plLayerInterface* fLay;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
void plDistOpacityMod::ISetup()
|
|
|
|
{
|
|
|
|
fFadeLays.Reset();
|
|
|
|
|
|
|
|
plSceneObject* so = GetTarget();
|
|
|
|
if( !so )
|
|
|
|
return;
|
|
|
|
|
|
|
|
const plDrawInterface* di = so->GetDrawInterface();
|
|
|
|
if( !di )
|
|
|
|
return;
|
|
|
|
|
|
|
|
hsTArray<MatLayer> todo;
|
|
|
|
|
|
|
|
hsTArray<plAccessSpan> src;
|
|
|
|
plAccessGeometry::Instance()->OpenRO(di, src, false);
|
|
|
|
|
|
|
|
// We are guaranteed that each Max object will be given a unique
|
|
|
|
// copy of materials and associated layers. But within an object,
|
|
|
|
// a given layer may be shared across materials.
|
|
|
|
// So we'll build a list of the layers that need a FadeOpacityLay applied,
|
|
|
|
// making sure we don't include any layer more than once (strip repeats).
|
|
|
|
// This would be grossly inefficient if the numbers involved weren't all
|
|
|
|
// very small. So an n^2 search isn't bad if n <= 2.
|
|
|
|
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) )
|
|
|
|
{
|
|
|
|
int k;
|
|
|
|
for( k = 0; k < todo.GetCount(); k++ )
|
|
|
|
{
|
|
|
|
if( lay == todo[k].fLay )
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if( k == todo.GetCount() )
|
|
|
|
{
|
|
|
|
MatLayer* push = todo.Push();
|
|
|
|
push->fMat = mat;
|
|
|
|
push->fLay = lay;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
plAccessGeometry::Instance()->Close(src);
|
|
|
|
|
|
|
|
for( i = 0; i < todo.GetCount(); i++ )
|
|
|
|
{
|
|
|
|
hsGMaterial* mat = todo[i].fMat;
|
|
|
|
plLayerInterface* lay = todo[i].fLay;
|
|
|
|
|
|
|
|
plFadeOpacityLay* fade = TRACKED_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 = TRACKED_NEW plMatRefMsg(mat->GetKey(), plRefMsg::kOnReplace, i, plMatRefMsg::kLayer);
|
|
|
|
msg->SetOldRef(lay);
|
|
|
|
hsgResMgr::ResMgr()->SendRef(fade, msg, plRefFlags::kActiveRef);
|
|
|
|
|
|
|
|
plGenRefMsg* toMe = TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnRequest, 0, kRefFadeLay);
|
|
|
|
hsgResMgr::ResMgr()->SendRef(fade, toMe, plRefFlags::kPassiveRef);
|
|
|
|
}
|
|
|
|
|
|
|
|
fSetup = true;
|
|
|
|
}
|