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.
203 lines
5.5 KiB
203 lines
5.5 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 "plPointShadowMaster.h" |
|
#include "plShadowSlave.h" |
|
#include "plShadowCaster.h" |
|
#include "../plMessage/plShadowCastMsg.h" |
|
|
|
#include "plLightInfo.h" |
|
|
|
#include "hsMatrix44.h" |
|
#include "hsBounds.h" |
|
#include "hsFastMath.h" |
|
|
|
static const hsScalar kMinMinZ = 1.f; // totally random arbitrary number (has to be > 0). |
|
|
|
static inline void QuickNorm( hsVector3& a, hsScalar& b ) |
|
{ |
|
hsScalar len = hsFastMath::InvSqrtAppr((a).MagnitudeSquared()); |
|
a *= len; |
|
b *= len; |
|
} |
|
|
|
static inline hsVector3 CrossProd(const hsVector3& a, const hsPoint3& b) |
|
{ |
|
return hsVector3(a.fY*b.fZ - a.fZ*b.fY, a.fZ*b.fX - a.fX*b.fZ, a.fX*b.fY - a.fY*b.fX); |
|
} |
|
|
|
static inline void InverseOfPureRotTran(const hsMatrix44& src, hsMatrix44& inv) |
|
{ |
|
inv = src; |
|
|
|
// We know this is a pure rotation and translation matrix, so |
|
// we won't have to do a full inverse. Okay kids, don't try this |
|
// at home. |
|
inv.fMap[0][1] = src.fMap[1][0]; |
|
inv.fMap[0][2] = src.fMap[2][0]; |
|
|
|
inv.fMap[1][0] = src.fMap[0][1]; |
|
inv.fMap[1][2] = src.fMap[2][1]; |
|
|
|
inv.fMap[2][0] = src.fMap[0][2]; |
|
inv.fMap[2][1] = src.fMap[1][2]; |
|
|
|
hsPoint3 newTran(-src.fMap[0][3], -src.fMap[1][3], -src.fMap[2][3]); |
|
inv.fMap[0][3] = newTran.InnerProduct((hsVector3*)&inv.fMap[0][0]); |
|
inv.fMap[1][3] = newTran.InnerProduct((hsVector3*)&inv.fMap[1][0]); |
|
inv.fMap[2][3] = newTran.InnerProduct((hsVector3*)&inv.fMap[2][0]); |
|
} |
|
|
|
//////////////////////////////////////////////////////////////////////////////////// |
|
// Point first |
|
//////////////////////////////////////////////////////////////////////////////////// |
|
plPointShadowMaster::plPointShadowMaster() |
|
{ |
|
fLastUp.Set(0,0,0); |
|
} |
|
|
|
plPointShadowMaster::~plPointShadowMaster() |
|
{ |
|
fIsectPool.SetCount(fIsectPool.GetNumAlloc()); |
|
int i; |
|
for( i = 0; i < fIsectPool.GetCount(); i++ ) |
|
delete fIsectPool[i]; |
|
} |
|
|
|
plShadowSlave* plPointShadowMaster::INewSlave(const plShadowCaster* caster) |
|
{ |
|
return TRACKED_NEW plPointShadowSlave; |
|
} |
|
|
|
void plPointShadowMaster::IBeginRender() |
|
{ |
|
plShadowMaster::IBeginRender(); |
|
|
|
fIsectPool.SetCount(0); |
|
} |
|
|
|
void plPointShadowMaster::IComputeWorldToLight(const hsBounds3Ext& bnd, plShadowSlave* slave) const |
|
{ |
|
const hsScalar kMinMag = 0.5f; |
|
hsPoint3 from = fLightInfo->GetLightToWorld().GetTranslate(); |
|
hsPoint3 at = bnd.GetCenter(); |
|
|
|
hsVector3 atToFrom(&from, &at); |
|
hsScalar distSq = atToFrom.MagnitudeSquared(); |
|
atToFrom *= hsFastMath::InvSqrtAppr(distSq); |
|
|
|
hsPoint2 depth; |
|
bnd.TestPlane(atToFrom, depth); |
|
|
|
hsScalar fromDepth = atToFrom.InnerProduct(from); |
|
|
|
hsScalar dist = fromDepth - depth.fY; |
|
|
|
static hsScalar kMinDist = 3.f; |
|
if( dist < kMinDist ) |
|
{ |
|
atToFrom *= kMinDist - dist; |
|
from += atToFrom; |
|
} |
|
|
|
hsVector3 up(0,0,1.f); |
|
if( CrossProd(up, (at - from)).MagnitudeSquared() < kMinMag ) |
|
{ |
|
up.Set(0, 1.f, 0); |
|
} |
|
hsMatrix44 w2light; |
|
w2light.MakeCamera(&from, &at, &up); // mf_flip_up - mf |
|
|
|
hsMatrix44 light2w; |
|
InverseOfPureRotTran(w2light, light2w); |
|
|
|
#ifdef CHECK_INVERSE |
|
hsMatrix44 inv; |
|
w2light.GetInverse(&inv); |
|
#endif // CHECK_INVERSE |
|
|
|
slave->fWorldToLight = w2light; |
|
slave->fLightToWorld = light2w; |
|
} |
|
|
|
void plPointShadowMaster::IComputeProjections(plShadowCastMsg* castMsg, plShadowSlave* slave) const |
|
{ |
|
|
|
slave->fView.SetPerspective(true); |
|
|
|
|
|
} |
|
|
|
void plPointShadowMaster::IComputeISect(const hsBounds3Ext& bnd, plShadowSlave* slave) const |
|
{ |
|
int iIsect = fIsectPool.GetCount(); |
|
fIsectPool.ExpandAndZero(iIsect+1); |
|
if( !fIsectPool[iIsect] ) |
|
{ |
|
fIsectPool[iIsect] = TRACKED_NEW plBoundsIsect; |
|
} |
|
plBoundsIsect* isect = fIsectPool[iIsect]; |
|
|
|
const hsBounds3Ext& wBnd = slave->fWorldBounds; |
|
|
|
isect->SetBounds(wBnd); |
|
|
|
slave->fIsect = isect; |
|
} |
|
|
|
void plPointShadowMaster::IComputeBounds(const hsBounds3Ext& wBnd, plShadowSlave* slave) const |
|
{ |
|
// Plan here is to look at the bounds in the slave's local space. |
|
// Our slave's bounds will clearly contain the shadow caster's bounds. It will also |
|
// contain the bnd's corners projected out along the ray from the slave's position |
|
// through each corner. They will extend fAttenDist farther than the center point |
|
// of the bound. |
|
|
|
hsBounds3Ext sBnd = wBnd; |
|
sBnd.Transform(&slave->fWorldToLight); |
|
|
|
hsBounds3Ext bnd = sBnd; |
|
|
|
hsScalar dist = sBnd.GetCenter().fZ; |
|
dist += slave->fAttenDist; |
|
|
|
hsScalar minZ = sBnd.GetMaxs().fZ; |
|
|
|
hsPoint3 p(sBnd.GetMins().fX * dist / minZ, sBnd.GetMins().fY * dist / minZ, dist); |
|
bnd.Union(&p); |
|
|
|
p.Set(sBnd.GetMaxs().fX * dist / minZ, sBnd.GetMaxs().fY * dist / minZ, dist); |
|
bnd.Union(&p); |
|
|
|
bnd.Transform(&slave->fLightToWorld); |
|
|
|
slave->fWorldBounds = bnd; |
|
|
|
} |
|
|
|
|
|
|