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.
318 lines
7.4 KiB
318 lines
7.4 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 <memory.h> |
|
|
|
#include "hsTypes.h" |
|
#include "plGeoSpanDice.h" |
|
#include "plGeometrySpan.h" |
|
|
|
plGeoSpanDice::plGeoSpanDice() |
|
: fMinFaces(0), |
|
fMaxFaces(0) |
|
{ |
|
fMaxSize.Set(0,0,0); |
|
} |
|
|
|
plGeoSpanDice::~plGeoSpanDice() |
|
{ |
|
} |
|
|
|
hsBool plGeoSpanDice::Dice(hsTArray<plGeometrySpan*>& spans) const |
|
{ |
|
int startingCount = spans.GetCount(); |
|
|
|
hsTArray<plGeometrySpan*> out; |
|
hsTArray<plGeometrySpan*> next; |
|
|
|
while(spans.GetCount()) |
|
{ |
|
int i; |
|
for( i = 0; i < spans.GetCount(); i++ ) |
|
{ |
|
if( !IHalf(spans[i], next) ) |
|
{ |
|
out.Append(spans[i]); |
|
} |
|
} |
|
spans.Swap(next); |
|
next.SetCount(0); |
|
} |
|
spans.Swap(out); |
|
|
|
return spans.GetCount() != startingCount; |
|
} |
|
|
|
hsBool plGeoSpanDice::INeedSplitting(plGeometrySpan* src) const |
|
{ |
|
// Do we have enough faces to bother? |
|
if( fMinFaces ) |
|
{ |
|
if( src->fNumIndices < fMinFaces * 3 ) |
|
return false; |
|
} |
|
// Do we have enough faces to bother no matter how small we are? |
|
if( fMaxFaces ) |
|
{ |
|
if( src->fNumIndices > fMaxFaces * 3 ) |
|
return true; |
|
} |
|
// Are we big enough to bother? |
|
if( (fMaxSize.fX > 0) || (fMaxSize.fY > 0) || (fMaxSize.fZ > 0) ) |
|
{ |
|
hsPoint3 size = src->fLocalBounds.GetMaxs() - src->fLocalBounds.GetMins(); |
|
if( size.fX > fMaxSize.fX ) |
|
return true; |
|
if( size.fY > fMaxSize.fY ) |
|
return true; |
|
if( size.fZ > fMaxSize.fZ ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
hsBool plGeoSpanDice::IHalf(plGeometrySpan* src, hsTArray<plGeometrySpan*>& out, int exclAxis) const |
|
{ |
|
if( !INeedSplitting(src) ) |
|
return false; |
|
|
|
int iAxis = ISelectAxis(exclAxis, src); |
|
// Ran out of axes to try. |
|
if( iAxis < 0 ) |
|
return false; |
|
|
|
hsScalar midPoint = src->fLocalBounds.GetCenter()[iAxis]; |
|
|
|
hsTArray<UInt32> loTris; |
|
hsTArray<UInt32> hiTris; |
|
|
|
UInt16* indexData = src->fIndexData; |
|
|
|
int numTris = src->fNumIndices / 3; |
|
|
|
int stride = src->GetVertexSize(src->fFormat); |
|
|
|
int i; |
|
for( i = 0; i < numTris; i++ ) |
|
{ |
|
hsPoint3& pos0 = *(hsPoint3*)(src->fVertexData + *indexData++ * stride); |
|
hsPoint3& pos1 = *(hsPoint3*)(src->fVertexData + *indexData++ * stride); |
|
hsPoint3& pos2 = *(hsPoint3*)(src->fVertexData + *indexData++ * stride); |
|
|
|
if( (pos0[iAxis] >= midPoint) |
|
&&(pos1[iAxis] >= midPoint) |
|
&&(pos2[iAxis] >= midPoint) ) |
|
{ |
|
hiTris.Append(i); |
|
} |
|
else |
|
{ |
|
loTris.Append(i); |
|
} |
|
} |
|
|
|
// This axis isn't working out, try another. |
|
if( !hiTris.GetCount() || !loTris.GetCount() ) |
|
return IHalf(src, out, exclAxis | (1 << iAxis)); |
|
|
|
|
|
plGeometrySpan* loDst = IExtractTris(src, loTris); |
|
plGeometrySpan* hiDst = IExtractTris(src, hiTris); |
|
|
|
delete src; |
|
|
|
out.Append(loDst); |
|
out.Append(hiDst); |
|
|
|
return true; |
|
} |
|
|
|
int plGeoSpanDice::ISelectAxis(int exclAxis, plGeometrySpan* src) const |
|
{ |
|
int iAxis = -1; |
|
hsScalar maxDim = 0; |
|
|
|
int i; |
|
for( i = 0; i < 3; i++ ) |
|
{ |
|
// Check to see if we've already tried this one. |
|
if( exclAxis & (1 << i) ) |
|
continue; |
|
|
|
hsScalar dim = src->fLocalBounds.GetMaxs()[i] - src->fLocalBounds.GetMins()[i]; |
|
if( dim > maxDim ) |
|
{ |
|
maxDim = dim; |
|
iAxis = i; |
|
} |
|
} |
|
return iAxis; |
|
} |
|
|
|
plGeometrySpan* plGeoSpanDice::IExtractTris(plGeometrySpan* src, hsTArray<UInt32>& tris) const |
|
{ |
|
// First off, find out how many and which vers we're talking here. |
|
// Easiest way is while we're building the LUTs we'll want later anyway. |
|
hsTArray<Int16> fwdLUT; |
|
fwdLUT.SetCount(src->fNumVerts); |
|
memset(fwdLUT.AcquireArray(), -1, src->fNumVerts * sizeof(*fwdLUT.AcquireArray())); |
|
|
|
hsTArray<UInt16> bckLUT; |
|
bckLUT.SetCount(0); |
|
|
|
int i; |
|
for( i = 0; i < tris.GetCount(); i++ ) |
|
{ |
|
UInt16* idx = src->fIndexData + tris[i] * 3; |
|
|
|
if( fwdLUT[*idx] < 0 ) |
|
{ |
|
fwdLUT[*idx] = bckLUT.GetCount(); |
|
bckLUT.Append(*idx); |
|
} |
|
|
|
idx++; |
|
|
|
if( fwdLUT[*idx] < 0 ) |
|
{ |
|
fwdLUT[*idx] = bckLUT.GetCount(); |
|
bckLUT.Append(*idx); |
|
} |
|
|
|
idx++; |
|
|
|
if( fwdLUT[*idx] < 0 ) |
|
{ |
|
fwdLUT[*idx] = bckLUT.GetCount(); |
|
bckLUT.Append(*idx); |
|
} |
|
} |
|
|
|
int numVerts = bckLUT.GetCount(); |
|
int numTris = tris.GetCount(); |
|
|
|
plGeometrySpan* dst = IAllocSpace(src, numVerts, numTris); |
|
|
|
// Okay, set the index data. |
|
UInt16* idxTrav = dst->fIndexData; |
|
for( i = 0; i < tris.GetCount(); i++ ) |
|
{ |
|
*idxTrav++ = fwdLUT[src->fIndexData[ tris[i] * 3 + 0] ]; |
|
*idxTrav++ = fwdLUT[src->fIndexData[ tris[i] * 3 + 1] ]; |
|
*idxTrav++ = fwdLUT[src->fIndexData[ tris[i] * 3 + 2] ]; |
|
} |
|
|
|
// Copy over the basic vertex data |
|
// We'll update the bounds as we go. |
|
int stride = src->GetVertexSize(src->fFormat); |
|
|
|
hsBounds3Ext localBnd; |
|
localBnd.MakeEmpty(); |
|
UInt8* vtxTrav = dst->fVertexData; |
|
for( i = 0; i < numVerts; i++ ) |
|
{ |
|
memcpy(vtxTrav, src->fVertexData + bckLUT[i] * stride, stride); |
|
|
|
hsPoint3* pos = (hsPoint3*)vtxTrav; |
|
localBnd.Union(pos); |
|
vtxTrav += stride; |
|
} |
|
if( src->fProps & plGeometrySpan::kWaterHeight ) |
|
{ |
|
src->AdjustBounds(localBnd); |
|
} |
|
dst->fLocalBounds = localBnd; |
|
|
|
// Now the rest of this optional garbage. |
|
if( src->fMultColor ) |
|
{ |
|
for( i = 0; i < numVerts; i++ ) |
|
{ |
|
dst->fMultColor[i] = src->fMultColor[bckLUT[i]]; |
|
} |
|
} |
|
if( src->fAddColor ) |
|
{ |
|
for( i = 0; i < numVerts; i++ ) |
|
{ |
|
dst->fAddColor[i] = src->fAddColor[bckLUT[i]]; |
|
} |
|
} |
|
if( src->fDiffuseRGBA ) |
|
{ |
|
for( i = 0; i < numVerts; i++ ) |
|
{ |
|
dst->fDiffuseRGBA[i] = src->fDiffuseRGBA[bckLUT[i]]; |
|
} |
|
} |
|
if( src->fSpecularRGBA ) |
|
{ |
|
for( i = 0; i < numVerts; i++ ) |
|
{ |
|
dst->fSpecularRGBA[i] = src->fSpecularRGBA[bckLUT[i]]; |
|
} |
|
} |
|
dst->fMaxOwner = src->fMaxOwner; |
|
|
|
return dst; |
|
} |
|
|
|
plGeometrySpan* plGeoSpanDice::IAllocSpace(plGeometrySpan* src, int numVerts, int numTris) const |
|
{ |
|
plGeometrySpan* dst = TRACKED_NEW plGeometrySpan; |
|
// Do a structure copy here. That's okay, because we're going to immediately |
|
// fix up the pointers and counters that shouldn't have been copied. If |
|
// plGeometrySpan ever gets a copy constructor, this'll blow wide open. |
|
*dst = *src; |
|
|
|
int stride = src->GetVertexSize(src->fFormat); |
|
|
|
dst->fNumIndices = numTris * 3; |
|
dst->fIndexData = TRACKED_NEW UInt16[dst->fNumIndices]; |
|
|
|
dst->fNumVerts = numVerts; |
|
dst->fVertexData = TRACKED_NEW UInt8[numVerts * stride]; |
|
|
|
if( src->fMultColor ) |
|
{ |
|
dst->fMultColor = TRACKED_NEW hsColorRGBA[numVerts]; |
|
} |
|
if( src->fAddColor ) |
|
{ |
|
dst->fAddColor = TRACKED_NEW hsColorRGBA[numVerts]; |
|
} |
|
if( src->fDiffuseRGBA ) |
|
{ |
|
dst->fDiffuseRGBA = TRACKED_NEW UInt32[numVerts]; |
|
} |
|
if( src->fSpecularRGBA ) |
|
{ |
|
dst->fSpecularRGBA = TRACKED_NEW UInt32[numVerts]; |
|
} |
|
|
|
return dst; |
|
} |