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.
296 lines
7.1 KiB
296 lines
7.1 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 "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; |
|
}
|
|
|