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.
1371 lines
35 KiB
1371 lines
35 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 "plCutter.h" |
|
#include "plAccessSpan.h" |
|
#include "hsFastMath.h" |
|
#include "plAccessGeometry.h" |
|
|
|
#include "hsStream.h" |
|
|
|
// Test hack |
|
#include "plDrawableSpans.h" |
|
#include "plDrawableGenerator.h" |
|
#include "../pnSceneObject/plSceneObject.h" |
|
#include "../pnSceneObject/plDrawInterface.h" |
|
#include "../plScene/plSceneNode.h" |
|
#include "../plScene/plPageTreeMgr.h" |
|
#include "../plSurface/hsGMaterial.h" |
|
#include "../plSurface/plLayerInterface.h" |
|
|
|
void plCutter::Read(hsStream* stream, hsResMgr* mgr) |
|
{ |
|
plCreatable::Read(stream, mgr); |
|
|
|
fLengthU = stream->ReadSwapScalar(); |
|
fLengthV = stream->ReadSwapScalar(); |
|
fLengthW = stream->ReadSwapScalar(); |
|
} |
|
|
|
void plCutter::Write(hsStream* stream, hsResMgr* mgr) |
|
{ |
|
plCreatable::Write(stream, mgr); |
|
|
|
stream->WriteSwapScalar(fLengthU); |
|
stream->WriteSwapScalar(fLengthV); |
|
stream->WriteSwapScalar(fLengthW); |
|
} |
|
|
|
|
|
void plCutter::Set(const hsPoint3& pos, const hsVector3& dir, const hsVector3& out, hsBool flip) |
|
{ |
|
hsVector3 du = dir % out; |
|
hsVector3 dv = out % du; |
|
hsVector3 dw = out; |
|
|
|
hsFastMath::NormalizeAppr(du); |
|
hsFastMath::NormalizeAppr(dv); |
|
hsFastMath::NormalizeAppr(dw); |
|
|
|
fBackDir = dw; |
|
|
|
if( flip ) |
|
du = -du; |
|
|
|
fDirU = du / fLengthU; |
|
fDirV = dv / -fLengthV; |
|
fDirW = dw / fLengthW; |
|
|
|
du *= fLengthU * 0.5f; |
|
dv *= fLengthV * 0.5f; |
|
dw *= fLengthW * 0.5f; |
|
|
|
hsPoint3 corner = pos; |
|
corner += -du; |
|
corner += dv; |
|
corner += -dw; |
|
|
|
fDistU = corner.InnerProduct(fDirU); |
|
fDistV = corner.InnerProduct(fDirV); |
|
fDistW = corner.InnerProduct(fDirW); |
|
|
|
hsMatrix44 l2w; |
|
l2w.NotIdentity(); |
|
int i; |
|
for( i = 0; i < 3; i++ ) |
|
{ |
|
l2w.fMap[i][0] = du[i]; |
|
l2w.fMap[i][1] = dv[i]; |
|
l2w.fMap[i][2] = dw[i]; |
|
l2w.fMap[i][3] = pos[i]; |
|
} |
|
l2w.fMap[3][0] = l2w.fMap[3][1] = l2w.fMap[3][2] = 0; |
|
l2w.fMap[3][3] = 1.f; |
|
|
|
|
|
hsPoint3 p; |
|
p.Set(1.f, 1.f, 1.f); |
|
fWorldBounds.Reset(&p); |
|
p.Set(-1.f, -1.f, -1.f); |
|
fWorldBounds.Union(&p); |
|
fWorldBounds.Transform(&l2w); |
|
|
|
fIsect.SetBounds(fWorldBounds); |
|
} |
|
|
|
|
|
inline void plCutter::ISetPosNorm(hsScalar parm, const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
dst.fPos = outVtx.fPos; |
|
dst.fPos += parm * (inVtx.fPos - outVtx.fPos); |
|
|
|
dst.fNorm = outVtx.fNorm; |
|
dst.fNorm += parm * (inVtx.fNorm - outVtx.fNorm); |
|
|
|
dst.fColor = outVtx.fColor; |
|
dst.fColor += parm * (inVtx.fColor - outVtx.fColor); |
|
} |
|
|
|
// A note on where the interpolation parameter is coming from. |
|
// |
|
// For the lower cases, we're looking for the point where Dot(pos, fDir) - fDist = 0. |
|
// Starting with p = outVtx + parm * (inVtx - outVtx) and Dot(p, fDir) == fDist, we get: |
|
// parm = (fDist - Dot(fDir,outVtx.fPos)) / (Dot(fDir, invVtx.fPos) - Dot(fDir, outVtx.fPos)) |
|
// |
|
// UVW = Dot(fDir, fPos) - fDist |
|
// Dot(fDir, fPos) = UVW + fDist |
|
// So: |
|
// parm = (fDist - (outVtx.fUVW - fDist)) / ((invVtx.fUVW - fDist) - (outVtx.fUVW - fDist)) |
|
// = -outVtx.fUVW / (inVtx.fUVW - outVtx.fUVW) |
|
// = outVtx.fUVW / (outVtx.fUVW - inVtx.fUVW) |
|
|
|
inline void plCutter::ICutoutVtxLoU(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = outVtx.fUVW.fX / (outVtx.fUVW.fX - inVtx.fUVW.fX); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fX = 0; |
|
dst.fUVW.fY = outVtx.fUVW.fY + parm * (inVtx.fUVW.fY - outVtx.fUVW.fY); |
|
dst.fUVW.fZ = outVtx.fUVW.fZ + parm * (inVtx.fUVW.fZ - outVtx.fUVW.fZ); |
|
} |
|
|
|
inline void plCutter::ICutoutVtxLoV(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = outVtx.fUVW.fY / (outVtx.fUVW.fY - inVtx.fUVW.fY); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fX = outVtx.fUVW.fX + parm * (inVtx.fUVW.fX - outVtx.fUVW.fX); |
|
dst.fUVW.fY = 0; |
|
dst.fUVW.fZ = outVtx.fUVW.fZ + parm * (inVtx.fUVW.fZ - outVtx.fUVW.fZ); |
|
} |
|
|
|
inline void plCutter::ICutoutVtxLoW(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = outVtx.fUVW.fZ / (outVtx.fUVW.fZ - inVtx.fUVW.fZ); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fX = outVtx.fUVW.fX + parm * (inVtx.fUVW.fX - outVtx.fUVW.fX); |
|
dst.fUVW.fY = outVtx.fUVW.fY + parm * (inVtx.fUVW.fY - outVtx.fUVW.fY); |
|
dst.fUVW.fZ = 0; |
|
} |
|
|
|
// Now for the upper cases, we start with Dot(pos, fDir) - fDist = 1.f |
|
// So parm = (fDist + 1.f - Dot(fDir, outVtx.fPos) / (Dot(fDir, invVtx.fPos) - Dot(fDir, outVtx.fPos)) |
|
// and doing the same substitution gets |
|
// parm = (outVtx.fUVW - 1.f) / (outVtx.fUVW - inVtx.fUVW) |
|
inline void plCutter::ICutoutVtxHiU(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = (outVtx.fUVW.fX - 1.f) / (outVtx.fUVW.fX - inVtx.fUVW.fX); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fX = 1.f; |
|
dst.fUVW.fY = outVtx.fUVW.fY + parm * (inVtx.fUVW.fY - outVtx.fUVW.fY); |
|
dst.fUVW.fZ = outVtx.fUVW.fZ + parm * (inVtx.fUVW.fZ - outVtx.fUVW.fZ); |
|
} |
|
|
|
inline void plCutter::ICutoutVtxHiV(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = (outVtx.fUVW.fY - 1.f) / (outVtx.fUVW.fY - inVtx.fUVW.fY); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fX = outVtx.fUVW.fX + parm * (inVtx.fUVW.fX - outVtx.fUVW.fX); |
|
dst.fUVW.fY = 1.f; |
|
dst.fUVW.fZ = outVtx.fUVW.fZ + parm * (inVtx.fUVW.fZ - outVtx.fUVW.fZ); |
|
} |
|
|
|
inline void plCutter::ICutoutVtxHiW(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = (outVtx.fUVW.fZ - 1.f) / (outVtx.fUVW.fZ - inVtx.fUVW.fZ); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fX = outVtx.fUVW.fX + parm * (inVtx.fUVW.fX - outVtx.fUVW.fX); |
|
dst.fUVW.fY = outVtx.fUVW.fY + parm * (inVtx.fUVW.fY - outVtx.fUVW.fY); |
|
dst.fUVW.fZ = 1.f; |
|
} |
|
|
|
|
|
// Now for the split down the middle cases, we start with Dot(pos, fDir) - fDist = 0.5f |
|
// So parm = (fDist + 0.5f - Dot(fDir, outVtx.fPos) / (Dot(fDir, invVtx.fPos) - Dot(fDir, outVtx.fPos)) |
|
// and doing the same substitution gets |
|
// parm = (outVtx.fUVW - 0.5f) / (outVtx.fUVW - inVtx.fUVW) |
|
inline void plCutter::ICutoutVtxMidU(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = (outVtx.fUVW.fX - 0.5f) / (outVtx.fUVW.fX - inVtx.fUVW.fX); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fX = outVtx.fUVW.fX + parm * (inVtx.fUVW.fX - outVtx.fUVW.fX); // TEST |
|
|
|
dst.fUVW.fX = 0.5f; |
|
dst.fUVW.fY = outVtx.fUVW.fY + parm * (inVtx.fUVW.fY - outVtx.fUVW.fY); |
|
dst.fUVW.fZ = outVtx.fUVW.fZ + parm * (inVtx.fUVW.fZ - outVtx.fUVW.fZ); |
|
} |
|
|
|
inline void plCutter::ICutoutVtxMidV(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = (outVtx.fUVW.fY - 0.5f) / (outVtx.fUVW.fY - inVtx.fUVW.fY); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fY = outVtx.fUVW.fY + parm * (inVtx.fUVW.fY - outVtx.fUVW.fY); // TEST |
|
|
|
dst.fUVW.fX = outVtx.fUVW.fX + parm * (inVtx.fUVW.fX - outVtx.fUVW.fX); |
|
dst.fUVW.fY = 0.5f; |
|
dst.fUVW.fZ = outVtx.fUVW.fZ + parm * (inVtx.fUVW.fZ - outVtx.fUVW.fZ); |
|
} |
|
|
|
inline void plCutter::ICutoutVtxMidW(const plCutoutVtx& inVtx, const plCutoutVtx& outVtx, plCutoutVtx& dst) const |
|
{ |
|
hsScalar parm = (outVtx.fUVW.fZ - 0.5f) / (outVtx.fUVW.fZ - inVtx.fUVW.fZ); |
|
|
|
ISetPosNorm(parm, inVtx, outVtx, dst); |
|
|
|
dst.fUVW.fZ = outVtx.fUVW.fZ + parm * (inVtx.fUVW.fZ - outVtx.fUVW.fZ); // TEST |
|
|
|
dst.fUVW.fX = outVtx.fUVW.fX + parm * (inVtx.fUVW.fX - outVtx.fUVW.fX); |
|
dst.fUVW.fY = outVtx.fUVW.fY + parm * (inVtx.fUVW.fY - outVtx.fUVW.fY); |
|
dst.fUVW.fZ = 0.5f; |
|
} |
|
|
|
// IPolyClip |
|
hsBool plCutter::IPolyClip(hsTArray<plCutoutVtx>& poly, const hsPoint3 vPos[]) const |
|
{ |
|
static hsTArray<plCutoutVtx> accum; |
|
accum.SetCount(0); |
|
|
|
poly[0].fUVW.fX = vPos[0].InnerProduct(fDirU) - fDistU; |
|
poly[0].fUVW.fY = vPos[0].InnerProduct(fDirV) - fDistV; |
|
poly[0].fUVW.fZ = vPos[0].InnerProduct(fDirW) - fDistW; |
|
|
|
poly[1].fUVW.fX = vPos[1].InnerProduct(fDirU) - fDistU; |
|
poly[1].fUVW.fY = vPos[1].InnerProduct(fDirV) - fDistV; |
|
poly[1].fUVW.fZ = vPos[1].InnerProduct(fDirW) - fDistW; |
|
|
|
poly[2].fUVW.fX = vPos[2].InnerProduct(fDirU) - fDistU; |
|
poly[2].fUVW.fY = vPos[2].InnerProduct(fDirV) - fDistV; |
|
poly[2].fUVW.fZ = vPos[2].InnerProduct(fDirW) - fDistW; |
|
|
|
// Try an early out test. |
|
int i; |
|
for( i = 0; i < 3; i++ ) |
|
{ |
|
int lo = 1; |
|
int hi = 1; |
|
int j; |
|
for( j = 0; j < 3; j++ ) |
|
{ |
|
lo &= poly[j].fUVW[i] <= 0; |
|
hi &= poly[j].fUVW[i] >= 1.f; |
|
} |
|
if( lo || hi ) |
|
{ |
|
poly.SetCount(0); |
|
return false; |
|
} |
|
} |
|
|
|
|
|
// First trim to lower bounds. |
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fX < 0) << 1) | (poly[j].fUVW.fX < 0); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxLoU(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxLoU(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fY < 0) << 1) | (poly[j].fUVW.fY < 0); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxLoV(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxLoV(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fZ < 0) << 1) | (poly[j].fUVW.fZ < 0); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxLoW(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxLoW(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
// Now upper bounds |
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fX > 1.f) << 1) | (poly[j].fUVW.fX > 1.f); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxHiU(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxHiU(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fY > 1.f) << 1) | (poly[j].fUVW.fY > 1.f); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxHiV(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxHiV(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fZ > 1.f) << 1) | (poly[j].fUVW.fZ > 1.f); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxHiW(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxHiW(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
return poly.GetCount() > 2; |
|
} |
|
|
|
// IPolyClip |
|
hsBool plCutter::IFindHitPoint(const hsTArray<plCutoutVtx>& inPoly, plCutoutHit& hit) const |
|
{ |
|
static hsTArray<plCutoutVtx> accum; |
|
static hsTArray<plCutoutVtx> poly; |
|
accum.SetCount(0); |
|
|
|
poly = inPoly; |
|
|
|
// First trim to lower bounds. |
|
int i; |
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fX < 0.5f) << 1) | (poly[j].fUVW.fX < 0.5f); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxMidU(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxMidU(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fY < 0.5f) << 1) | (poly[j].fUVW.fY < 0.5f); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxMidV(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxMidV(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
// Now upper bounds |
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fX > 0.5f) << 1) | (poly[j].fUVW.fX > 0.5f); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxMidU(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxMidU(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
poly.Swap(accum); |
|
accum.SetCount(0); |
|
|
|
for( i = 0; i < poly.GetCount(); i++ ) |
|
{ |
|
int j = i ? i-1 : poly.GetCount()-1; |
|
|
|
int test = ((poly[i].fUVW.fY > 0.5f) << 1) | (poly[j].fUVW.fY > 0.5f); |
|
switch(test) |
|
{ |
|
case 0: |
|
// Both in |
|
// Add this vert to outList |
|
accum.Append(poly[i]); |
|
break; |
|
case 1: |
|
// This in, last out |
|
// Add ClipVert(j, j-1) to outList |
|
// Add this vert to outList |
|
accum.Push(); |
|
ICutoutVtxMidV(poly[i], poly[j], accum[accum.GetCount()-1]); |
|
accum.Append(poly[i]); |
|
break; |
|
case 2: |
|
// This out, last in |
|
// Add ClipVert(j-1, j) to outList |
|
accum.Push(); |
|
ICutoutVtxMidV(poly[j], poly[i], accum[accum.GetCount()-1]); |
|
break; |
|
case 3: |
|
// Both out |
|
break; |
|
} |
|
} |
|
|
|
// At this point, if we hit, all verts should be identical, interpolated |
|
// into the center of the cutter. |
|
// No verts means no hit. |
|
if( !accum.GetCount() ) |
|
return false; |
|
|
|
if( accum[0].fNorm.InnerProduct(fDirW) < 0 ) |
|
return false; |
|
|
|
hit.fPos = accum[0].fPos; |
|
hit.fNorm = accum[0].fNorm; |
|
|
|
return true; |
|
} |
|
|
|
|
|
hsBool plCutter::FindHitPoints(const hsTArray<plCutoutPoly>& src, hsTArray<plCutoutHit>& hits) const |
|
{ |
|
hits.SetCount(0); |
|
|
|
int iPoly; |
|
for( iPoly = 0; iPoly < src.GetCount(); iPoly++ ) |
|
{ |
|
hsBool loU = false; |
|
hsBool hiU = false; |
|
hsBool loV = false; |
|
hsBool hiV = false; |
|
|
|
const plCutoutPoly& poly = src[iPoly]; |
|
int iv; |
|
for( iv = 0; iv < poly.fVerts.GetCount(); iv++ ) |
|
{ |
|
const hsPoint3& uvw = poly.fVerts[iv].fUVW; |
|
if( uvw.fX < 0.5f ) |
|
loU = true; |
|
else |
|
hiU = true; |
|
if( uvw.fY < 0.5f ) |
|
loV = true; |
|
else |
|
hiV = true; |
|
|
|
if( loU && hiU && loV && hiV ) |
|
{ |
|
plCutoutHit hit; |
|
if( IFindHitPoint(poly.fVerts, hit) ) |
|
hits.Append(hit); |
|
break; |
|
} |
|
} |
|
} |
|
|
|
return hits.GetCount() > 0; |
|
} |
|
|
|
hsBool plCutter::FindHitPointsConstHeight(const hsTArray<plCutoutPoly>& src, hsTArray<plCutoutHit>& hits, hsScalar height) const |
|
{ |
|
if( FindHitPoints(src, hits) ) |
|
{ |
|
int i; |
|
for( i = 0; i < hits.GetCount(); i++ ) |
|
hits[i].fPos.fZ = height; |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void plCutter::ICutoutTransformedConstHeight(plAccessSpan& src, hsTArray<plCutoutPoly>& dst) const |
|
{ |
|
const hsMatrix44& l2w = src.GetLocalToWorld(); |
|
hsMatrix44 l2wNorm; |
|
src.GetWorldToLocal().GetTranspose(&l2wNorm); |
|
|
|
hsBool baseHasAlpha = 0 != (src.GetMaterial()->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendAlpha); |
|
|
|
plAccTriIterator tri(&src.AccessTri()); |
|
// For each tri |
|
for( tri.Begin(); tri.More(); tri.Advance() ) |
|
{ |
|
// Do a polygon clip of tri to box |
|
static hsTArray<plCutoutVtx> poly; |
|
poly.SetCount(3); |
|
|
|
// Not sure about this, whether the constant water height should be world space or local. |
|
// We'll leave it in local for now. |
|
const hsVector3 up(0, 0, 1.f); |
|
hsPoint3 vPos[3]; |
|
vPos[0] = l2w * hsPoint3(tri.Position(0).fX, tri.Position(0).fY, src.GetWaterHeight()); |
|
vPos[1] = l2w * hsPoint3(tri.Position(1).fX, tri.Position(1).fY, src.GetWaterHeight()); |
|
vPos[2] = l2w * hsPoint3(tri.Position(2).fX, tri.Position(2).fY, src.GetWaterHeight()); |
|
|
|
poly[0].Init(l2w * hsPoint3(tri.Position(0).fX, tri.Position(0).fY, tri.Position(0).fZ), l2wNorm * up, tri.DiffuseRGBA(0)); |
|
poly[1].Init(l2w * hsPoint3(tri.Position(1).fX, tri.Position(1).fY, tri.Position(1).fZ), l2wNorm * up, tri.DiffuseRGBA(1)); |
|
poly[2].Init(l2w * hsPoint3(tri.Position(2).fX, tri.Position(2).fY, tri.Position(2).fZ), l2wNorm * up, tri.DiffuseRGBA(2)); |
|
|
|
// If we got a polygon |
|
if( IPolyClip(poly, vPos) ) |
|
{ |
|
// tessalate the polygon into dst |
|
IConstruct(dst, poly, baseHasAlpha); |
|
} |
|
} |
|
} |
|
|
|
// We usually don't need to do any transform, because the kind of surface you |
|
// would leave prints on tends to be static, with the transform folded into the |
|
// verts. So it's worth having 2 separate versions of the function. |
|
void plCutter::ICutoutTransformed(plAccessSpan& src, hsTArray<plCutoutPoly>& dst) const |
|
{ |
|
const hsMatrix44& l2w = src.GetLocalToWorld(); |
|
hsMatrix44 l2wNorm; |
|
src.GetWorldToLocal().GetTranspose(&l2wNorm); |
|
|
|
hsBool baseHasAlpha = 0 != (src.GetMaterial()->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendAlpha); |
|
|
|
plAccTriIterator tri(&src.AccessTri()); |
|
// For each tri |
|
for( tri.Begin(); tri.More(); tri.Advance() ) |
|
{ |
|
// Do a polygon clip of tri to box |
|
static hsTArray<plCutoutVtx> poly; |
|
poly.SetCount(3); |
|
|
|
hsPoint3 vPos[3]; |
|
vPos[0] = l2w * tri.Position(0); |
|
vPos[1] = l2w * tri.Position(1); |
|
vPos[2] = l2w * tri.Position(2); |
|
|
|
poly[0].Init(vPos[0], l2wNorm * tri.Normal(0), tri.DiffuseRGBA(0)); |
|
poly[1].Init(vPos[1], l2wNorm * tri.Normal(1), tri.DiffuseRGBA(1)); |
|
poly[2].Init(vPos[2], l2wNorm * tri.Normal(2), tri.DiffuseRGBA(2)); |
|
|
|
// If we got a polygon |
|
if( IPolyClip(poly, vPos) ) |
|
{ |
|
// tessalate the polygon into dst |
|
IConstruct(dst, poly, baseHasAlpha); |
|
} |
|
} |
|
} |
|
|
|
void plCutter::ICutoutConstHeight(plAccessSpan& src, hsTArray<plCutoutPoly>& dst) const |
|
{ |
|
if( !(src.GetLocalToWorld().fFlags & hsMatrix44::kIsIdent) ) |
|
{ |
|
ICutoutTransformedConstHeight(src, dst); |
|
return; |
|
} |
|
|
|
hsBool baseHasAlpha = 0 != (src.GetMaterial()->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendAlpha); |
|
|
|
plAccTriIterator tri(&src.AccessTri()); |
|
// For each tri |
|
for( tri.Begin(); tri.More(); tri.Advance() ) |
|
{ |
|
// Do a polygon clip of tri to box |
|
static hsTArray<plCutoutVtx> poly; |
|
poly.SetCount(3); |
|
|
|
const hsVector3 up(0, 0, 1.f); |
|
|
|
hsPoint3 vPos[3]; |
|
vPos[0].Set(tri.Position(0).fX, tri.Position(0).fY, src.GetWaterHeight()); |
|
vPos[1].Set(tri.Position(1).fX, tri.Position(1).fY, src.GetWaterHeight()); |
|
vPos[2].Set(tri.Position(2).fX, tri.Position(2).fY, src.GetWaterHeight()); |
|
|
|
poly[0].Init(hsPoint3(tri.Position(0).fX, tri.Position(0).fY, tri.Position(0).fZ), up, tri.DiffuseRGBA(0)); |
|
poly[1].Init(hsPoint3(tri.Position(1).fX, tri.Position(1).fY, tri.Position(1).fZ), up, tri.DiffuseRGBA(1)); |
|
poly[2].Init(hsPoint3(tri.Position(2).fX, tri.Position(2).fY, tri.Position(2).fZ), up, tri.DiffuseRGBA(2)); |
|
|
|
// If we got a polygon |
|
if( IPolyClip(poly, vPos) ) |
|
{ |
|
// tessalate the polygon into dst |
|
IConstruct(dst, poly, baseHasAlpha); |
|
} |
|
} |
|
} |
|
|
|
// Cutout |
|
void plCutter::Cutout(plAccessSpan& src, hsTArray<plCutoutPoly>& dst) const |
|
{ |
|
if( !src.HasAccessTri() ) |
|
return; |
|
|
|
if( src.HasWaterHeight() ) |
|
{ |
|
ICutoutConstHeight(src, dst); |
|
return; |
|
} |
|
|
|
if( !(src.GetLocalToWorld().fFlags & hsMatrix44::kIsIdent) ) |
|
{ |
|
ICutoutTransformed(src, dst); |
|
return; |
|
} |
|
|
|
hsBool baseHasAlpha = 0 != (src.GetMaterial()->GetLayer(0)->GetBlendFlags() & hsGMatState::kBlendAlpha); |
|
|
|
plAccTriIterator tri(&src.AccessTri()); |
|
// For each tri |
|
for( tri.Begin(); tri.More(); tri.Advance() ) |
|
{ |
|
// Do a polygon clip of tri to box |
|
static hsTArray<plCutoutVtx> poly; |
|
poly.SetCount(3); |
|
|
|
hsPoint3 vPos[3]; |
|
vPos[0] = tri.Position(0); |
|
vPos[1] = tri.Position(1); |
|
vPos[2] = tri.Position(2); |
|
|
|
poly[0].Init(vPos[0], tri.Normal(0), tri.DiffuseRGBA(0)); |
|
poly[1].Init(vPos[1], tri.Normal(1), tri.DiffuseRGBA(1)); |
|
poly[2].Init(vPos[2], tri.Normal(2), tri.DiffuseRGBA(2)); |
|
|
|
// If we got a polygon |
|
if( IPolyClip(poly, vPos) ) |
|
{ |
|
// tessalate the polygon into dst |
|
IConstruct(dst, poly, baseHasAlpha); |
|
} |
|
} |
|
} |
|
|
|
void plCutter::IConstruct(hsTArray<plCutoutPoly>& dst, hsTArray<plCutoutVtx>& poly, hsBool baseHasAlpha) const |
|
{ |
|
int iDst = dst.GetCount(); |
|
dst.Push(); |
|
dst[iDst].fVerts.Swap(poly); |
|
dst[iDst].fBaseHasAlpha = baseHasAlpha; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
hsBool plCutter::CutoutGrid(int nWid, int nLen, plFlatGridMesh& grid) const |
|
{ |
|
hsVector3 halfU = fDirU * (fLengthU * fLengthU * 0.5f); |
|
hsVector3 halfV = fDirV * (fLengthV * fLengthV * 0.5f); |
|
return MakeGrid(nWid, nLen, fWorldBounds.GetCenter(), halfU, halfV, grid); |
|
} |
|
|
|
hsBool plCutter::MakeGrid(int nWid, int nLen, const hsPoint3& center, const hsVector3& halfU, const hsVector3& halfV, plFlatGridMesh& grid) |
|
{ |
|
if( nWid < 3 ) |
|
nWid = 3; |
|
if( !(nWid & 0x1) ) |
|
nWid++; |
|
if( nLen < 3 ) |
|
nLen = 3; |
|
if( !(nLen & 0x1) ) |
|
nLen++; |
|
|
|
grid.fVerts.SetCount(nWid * nLen); |
|
|
|
hsVector3 dux = halfU; |
|
hsVector3 dvx = halfV; |
|
dux.fZ = 0; |
|
dvx.fZ = 0; |
|
|
|
hsPoint3 corner = center; |
|
corner.fZ = 0; |
|
corner += -dux; |
|
corner += -dvx; |
|
|
|
hsScalar sWid = 1.f / hsScalar(nWid-1); |
|
hsScalar sLen = 1.f / hsScalar(nLen-1); |
|
|
|
dux *= 2.f * sWid; |
|
dvx *= 2.f * sLen; |
|
|
|
hsScalar du = sWid; |
|
hsScalar dv = sLen; |
|
int j; |
|
for( j = 0; j < nLen; j++ ) |
|
{ |
|
int i; |
|
for( i = 0; i < nWid; i++ ) |
|
{ |
|
plCutoutMiniVtx& vtx = grid.fVerts[j * nWid + i]; |
|
|
|
vtx.fPos = corner; |
|
vtx.fPos += dux * (hsScalar)i; |
|
vtx.fPos += dvx * (hsScalar)j; |
|
|
|
vtx.fUVW.fX = du * i; |
|
vtx.fUVW.fY = dv * j; |
|
vtx.fUVW.fZ = 0.5f; |
|
} |
|
} |
|
|
|
int idx = 0; |
|
grid.fIdx.SetCount(2 * (nWid-1) * (nLen-1) * 3); |
|
for( j = 1; j < nLen; ) |
|
{ |
|
int i; |
|
for( i = 1; i < nWid; ) |
|
{ |
|
grid.fIdx[idx++] = j * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + i; |
|
grid.fIdx[idx++] = (j-1) * nWid + (i-1); |
|
|
|
grid.fIdx[idx++] = (j-1) * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + i; |
|
grid.fIdx[idx++] = (j-1) * nWid + i; |
|
|
|
i++; |
|
|
|
grid.fIdx[idx++] = (j-1) * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + (i-1); |
|
grid.fIdx[idx++] = (j-1) * nWid + i; |
|
|
|
grid.fIdx[idx++] = (j-1) * nWid + i; |
|
grid.fIdx[idx++] = j * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + i; |
|
|
|
i++; |
|
} |
|
|
|
j++; |
|
|
|
for( i = 1; i < nWid; ) |
|
{ |
|
grid.fIdx[idx++] = (j-1) * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + (i-1); |
|
grid.fIdx[idx++] = (j-1) * nWid + i; |
|
|
|
grid.fIdx[idx++] = (j-1) * nWid + i; |
|
grid.fIdx[idx++] = j * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + i; |
|
|
|
i++; |
|
|
|
grid.fIdx[idx++] = j * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + i; |
|
grid.fIdx[idx++] = (j-1) * nWid + (i-1); |
|
|
|
grid.fIdx[idx++] = (j-1) * nWid + (i-1); |
|
grid.fIdx[idx++] = j * nWid + i; |
|
grid.fIdx[idx++] = (j-1) * nWid + i; |
|
|
|
i++; |
|
} |
|
|
|
j++; |
|
} |
|
|
|
return grid.fIdx.GetCount() > 0; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////////// |
|
// Test hackage ensues |
|
///////////////////////////////////////////////////////////////////////////////////////////////////// |
|
void TestCutter(const plKey& key, const hsVector3& size, const hsPoint3& pos) |
|
{ |
|
plCutter cutter; |
|
|
|
cutter.SetLength(size); |
|
|
|
static hsVector3 dir(0, 1.f, 0); |
|
static hsVector3 up(0, 0, 1.f); |
|
|
|
cutter.Set(pos, dir, up); |
|
|
|
plSceneObject* so = plSceneObject::ConvertNoRef(key->ObjectIsLoaded()); |
|
if( !so ) |
|
return; |
|
const plDrawInterface* di = so->GetDrawInterface(); |
|
if( !di ) |
|
return; |
|
|
|
static plDrawableSpans* drawable = nil; |
|
hsBool newDrawable = !drawable; |
|
hsBool haveNormal = true; |
|
|
|
hsTArray<UInt32> retIndex; |
|
|
|
hsTArray<plAccessSpan> src; |
|
plAccessGeometry::Instance()->OpenRO(di, src); |
|
|
|
if( !src.GetCount() ) |
|
return; |
|
|
|
int i; |
|
for( i = 0; i < src.GetCount(); i++ ) |
|
{ |
|
|
|
static hsTArray<plCutoutPoly> dst; |
|
dst.SetCount(0); |
|
#if 1 |
|
cutter.Cutout(src[i], dst); |
|
#else |
|
hsPoint3 corner; |
|
hsVector3 ax[3]; |
|
cutter.GetWorldBounds().GetCorner(&corner); |
|
cutter.GetWorldBounds().GetAxes(ax+0, ax+1, ax+2); |
|
int iAx = 0; |
|
int jAx = 1; |
|
dst.SetCount(6); |
|
int xx; |
|
for( xx = 0; xx < 3; xx++ ) |
|
{ |
|
dst[xx].fVerts.SetCount(4); |
|
|
|
dst[xx].fVerts[0].fPos = corner; |
|
dst[xx].fVerts[0].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[0].fUVW.Set(0,0,0); |
|
|
|
dst[xx].fVerts[1].fPos = corner; |
|
dst[xx].fVerts[1].fPos += ax[iAx]; |
|
dst[xx].fVerts[1].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[1].fUVW.Set(1,0,0); |
|
|
|
dst[xx].fVerts[2].fPos = corner; |
|
dst[xx].fVerts[2].fPos += ax[iAx]; |
|
dst[xx].fVerts[2].fPos += ax[jAx]; |
|
dst[xx].fVerts[2].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[2].fUVW.Set(1.f,1.f,0); |
|
|
|
dst[xx].fVerts[3].fPos = corner; |
|
dst[xx].fVerts[3].fPos += ax[jAx]; |
|
dst[xx].fVerts[3].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[3].fUVW.Set(0,1.f,0); |
|
|
|
iAx++; |
|
jAx = iAx > 1 ? 0 : iAx+1; |
|
} |
|
corner += ax[0]; |
|
corner += ax[1]; |
|
corner += ax[2]; |
|
ax[0] = -ax[0]; |
|
ax[1] = -ax[1]; |
|
ax[2] = -ax[2]; |
|
iAx = 0; |
|
jAx = 1; |
|
for( xx = 3; xx < 6; xx++ ) |
|
{ |
|
dst[xx].fVerts.SetCount(4); |
|
|
|
dst[xx].fVerts[0].fPos = corner; |
|
dst[xx].fVerts[0].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[0].fUVW.Set(0,0,0); |
|
|
|
dst[xx].fVerts[3].fPos = corner; |
|
dst[xx].fVerts[3].fPos += ax[iAx]; |
|
dst[xx].fVerts[3].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[3].fUVW.Set(1.f,0,0); |
|
|
|
dst[xx].fVerts[2].fPos = corner; |
|
dst[xx].fVerts[2].fPos += ax[iAx]; |
|
dst[xx].fVerts[2].fPos += ax[jAx]; |
|
dst[xx].fVerts[2].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[2].fUVW.Set(1.f,1.f,0); |
|
|
|
dst[xx].fVerts[1].fPos = corner; |
|
dst[xx].fVerts[1].fPos += ax[jAx]; |
|
dst[xx].fVerts[1].fNorm.Set(0,0,1.f); |
|
dst[xx].fVerts[1].fUVW.Set(0,1.f,0); |
|
|
|
iAx++; |
|
jAx = iAx > 1 ? 0 : iAx+1; |
|
} |
|
haveNormal = false; |
|
#endif |
|
|
|
// What's our total number of verts? |
|
// Total number of tris? |
|
int numVerts = 0; |
|
int numTris = 0; |
|
int j; |
|
for( j = 0; j < dst.GetCount(); j++ ) |
|
{ |
|
if( dst[j].fVerts.GetCount() ) |
|
{ |
|
numVerts += dst[j].fVerts.GetCount(); |
|
numTris += dst[j].fVerts.GetCount()-2; |
|
} |
|
} |
|
if( !numTris ) |
|
continue; |
|
|
|
hsTArray<hsPoint3> pos; |
|
pos.SetCount(numVerts); |
|
hsTArray<hsVector3> norm; |
|
norm.SetCount(numVerts); |
|
hsTArray<hsPoint3> uvw; |
|
uvw.SetCount(numVerts); |
|
hsTArray<hsColorRGBA> col; |
|
col.SetCount(numVerts); |
|
|
|
int iPoly = 0; |
|
int iVert = 0; |
|
int iv; |
|
for( iv = 0; iv < numVerts; iv++ ) |
|
{ |
|
pos[iv] = dst[iPoly].fVerts[iVert].fPos; |
|
norm[iv] = dst[iPoly].fVerts[iVert].fNorm; |
|
uvw[iv] = dst[iPoly].fVerts[iVert].fUVW; |
|
col[iv] = dst[iPoly].fVerts[iVert].fColor; |
|
|
|
hsScalar opac = uvw[iv].fZ < 0.25f |
|
? uvw[iv].fZ * 4.f |
|
: uvw[iv].fZ > 0.75f |
|
? (1.f - uvw[iv].fZ) * 4.f |
|
: 1.f; |
|
|
|
opac *= norm[iv].fZ; |
|
if( opac < 0 ) |
|
opac = 0; |
|
|
|
if( dst[iPoly].fBaseHasAlpha ) |
|
col[iv].a *= opac; |
|
else |
|
col[iv].a = opac; |
|
|
|
if( ++iVert >= dst[iPoly].fVerts.GetCount() ) |
|
{ |
|
iVert = 0; |
|
iPoly++; |
|
} |
|
} |
|
|
|
hsTArray<UInt16> idx; |
|
|
|
UInt16 base = 0; |
|
for( j = 0; j < dst.GetCount(); j++ ) |
|
{ |
|
UInt16 next = base+1; |
|
int k; |
|
for( k = 2; k < dst[j].fVerts.GetCount(); k++ ) |
|
{ |
|
idx.Append(base); |
|
idx.Append(next++); |
|
idx.Append(next); |
|
} |
|
base = ++next; |
|
} |
|
|
|
drawable = plDrawableGenerator::GenerateDrawable( numVerts, pos.AcquireArray(), |
|
haveNormal ? norm.AcquireArray() : nil, |
|
uvw.AcquireArray(), 1, |
|
col.AcquireArray(), |
|
true, |
|
nil, |
|
idx.GetCount(), idx.AcquireArray(), |
|
src[i].GetMaterial(), |
|
hsMatrix44::IdentityMatrix(), |
|
true, |
|
&retIndex, |
|
drawable); |
|
|
|
} |
|
|
|
if( drawable && newDrawable ) |
|
drawable->SetSceneNode(so->GetSceneNode()); |
|
|
|
} |
|
|
|
void TestCutter2(const plKey& key, const hsVector3& size, const hsPoint3& pos, hsBool flip) |
|
{ |
|
plCutter cutter; |
|
|
|
cutter.SetLength(size); |
|
|
|
static hsVector3 dir(0, 1.f, 0); |
|
static hsVector3 up(0, 0, 1.f); |
|
|
|
cutter.Set(pos, dir, up, flip); |
|
|
|
plSceneObject* so = plSceneObject::ConvertNoRef(key->ObjectIsLoaded()); |
|
if( !so ) |
|
return; |
|
|
|
plSceneNode* node = plSceneNode::ConvertNoRef(so->GetSceneNode()->ObjectIsLoaded()); |
|
if( !node ) |
|
return; |
|
|
|
static plDrawableSpans* drawable = nil; |
|
hsBool newDrawable = !drawable; |
|
hsBool haveNormal = true; |
|
|
|
hsTArray<UInt32> retIndex; |
|
|
|
hsTArray<plDrawVisList> drawVis; |
|
node->Harvest(&cutter.GetIsect(), drawVis); |
|
if( !drawVis.GetCount() ) |
|
return; |
|
|
|
hsTArray<plAccessSpan> src; |
|
|
|
int numSpan = 0; |
|
int iDraw; |
|
for( iDraw = 0; iDraw < drawVis.GetCount(); iDraw++ ) |
|
numSpan += drawVis[iDraw].fVisList.GetCount(); |
|
|
|
src.SetCount(numSpan); |
|
|
|
int i; |
|
|
|
iDraw = 0; |
|
int iSpan = 0; |
|
for( i = 0; i < numSpan; i++ ) |
|
{ |
|
plAccessGeometry::Instance()->OpenRO(drawVis[iDraw].fDrawable, drawVis[iDraw].fVisList[iSpan], src[i]); |
|
|
|
if( ++iSpan >= drawVis[iDraw].fVisList.GetCount() ) |
|
{ |
|
iDraw++; |
|
iSpan = 0; |
|
} |
|
} |
|
|
|
|
|
for( i = 0; i < src.GetCount(); i++ ) |
|
{ |
|
static hsTArray<plCutoutPoly> dst; |
|
dst.SetCount(0); |
|
cutter.Cutout(src[i], dst); |
|
|
|
// What's our total number of verts? |
|
// Total number of tris? |
|
int numVerts = 0; |
|
int numTris = 0; |
|
int j; |
|
for( j = 0; j < dst.GetCount(); j++ ) |
|
{ |
|
if( dst[j].fVerts.GetCount() ) |
|
{ |
|
numVerts += dst[j].fVerts.GetCount(); |
|
numTris += dst[j].fVerts.GetCount()-2; |
|
} |
|
} |
|
if( !numTris ) |
|
continue; |
|
|
|
hsTArray<hsPoint3> pos; |
|
pos.SetCount(numVerts); |
|
hsTArray<hsVector3> norm; |
|
norm.SetCount(numVerts); |
|
hsTArray<hsPoint3> uvw; |
|
uvw.SetCount(numVerts); |
|
hsTArray<hsColorRGBA> col; |
|
col.SetCount(numVerts); |
|
|
|
int iPoly = 0; |
|
int iVert = 0; |
|
int iv; |
|
for( iv = 0; iv < numVerts; iv++ ) |
|
{ |
|
pos[iv] = dst[iPoly].fVerts[iVert].fPos; |
|
norm[iv] = dst[iPoly].fVerts[iVert].fNorm; |
|
uvw[iv] = dst[iPoly].fVerts[iVert].fUVW; |
|
col[iv] = dst[iPoly].fVerts[iVert].fColor; |
|
|
|
hsScalar opac = uvw[iv].fZ < 0.25f |
|
? uvw[iv].fZ * 4.f |
|
: uvw[iv].fZ > 0.75f |
|
? (1.f - uvw[iv].fZ) * 4.f |
|
: 1.f; |
|
|
|
opac *= norm[iv].fZ; |
|
if( opac < 0 ) |
|
opac = 0; |
|
|
|
if( dst[iPoly].fBaseHasAlpha ) |
|
col[iv].a *= opac; |
|
else |
|
col[iv].a = opac; |
|
|
|
|
|
if( ++iVert >= dst[iPoly].fVerts.GetCount() ) |
|
{ |
|
iVert = 0; |
|
iPoly++; |
|
} |
|
} |
|
|
|
hsTArray<UInt16> idx; |
|
|
|
UInt16 base = 0; |
|
for( j = 0; j < dst.GetCount(); j++ ) |
|
{ |
|
UInt16 next = base+1; |
|
int k; |
|
for( k = 2; k < dst[j].fVerts.GetCount(); k++ ) |
|
{ |
|
idx.Append(base); |
|
idx.Append(next++); |
|
idx.Append(next); |
|
} |
|
base = ++next; |
|
} |
|
|
|
drawable = plDrawableGenerator::GenerateDrawable( numVerts, pos.AcquireArray(), |
|
haveNormal ? norm.AcquireArray() : nil, |
|
uvw.AcquireArray(), 1, |
|
col.AcquireArray(), |
|
false, |
|
nil, |
|
idx.GetCount(), idx.AcquireArray(), |
|
src[i].GetMaterial(), |
|
hsMatrix44::IdentityMatrix(), |
|
true, |
|
&retIndex, |
|
drawable); |
|
|
|
} |
|
|
|
for( i = 0; i < numSpan; i++ ) |
|
{ |
|
plAccessGeometry::Instance()->Close(src[i]); |
|
} |
|
|
|
if( drawable && newDrawable ) |
|
drawable->SetSceneNode(so->GetSceneNode()); |
|
|
|
} |