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
14 years ago
|
/*==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;
|
||
|
}
|