Show geometry.cpp syntax highlighted
/***************************************************************************
geometry.cpp - Static geometry data for ABT
-------------------
begin : Tue Sep 23 2003
copyright : (C) 2003 by Reality Rift Studios
email : mattias@realityrift.com
***************************************************************************
The contents of this file are subject to the Mozilla Public License Version
1.1 (the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
The Original Code is the NeoEngine, NeoABT, geometry.cpp
The Initial Developer of the Original Code is Mattias Jansson.
Portions created by Mattias Jansson are Copyright (C) 2003
Reality Rift Studios. All Rights Reserved.
***************************************************************************/
#include "geometry.h"
#include "room.h"
#include <neoengine/aabb.h>
#include <neoengine/radix.h>
#include <neoengine/vertexdecl.h>
#include <neoengine/render.h>
#include <neoengine/renderprimitive.h>
#include <neoengine/collision.h>
#include <neoengine/contact.h>
#include <limits>
using namespace std;
using namespace NeoEngine;
#define SPLITGROW_THRESHOLD 1.10f
#define POLYGONLIMIT 100
#define DISTRIBUTIONFACTOR_WEIGHT 1.0f
#define VOLUMEFACTOR_WEIGHT 0.3f
#define SPLITFACTOR_WEIGHT 1.0f
#define AXISFACTOR_WEIGHT 0.5f
namespace NeoABT
{
inline void CheckMinMax( Vector3d *pkPoint, Vector3d *pkMin, Vector3d *pkMax )
{
if( pkPoint->x < pkMin->x )
pkMin->x = pkPoint->x;
if( pkPoint->y < pkMin->y )
pkMin->y = pkPoint->y;
if( pkPoint->z < pkMin->z )
pkMin->z = pkPoint->z;
if( pkPoint->x > pkMax->x )
pkMax->x = pkPoint->x;
if( pkPoint->y > pkMax->y )
pkMax->y = pkPoint->y;
if( pkPoint->z > pkMax->z )
pkMax->z = pkPoint->z;
}
void Geometry::Partition( std::vector< Geometry* > *pvpkGeometries, unsigned int uiDepth )
{
if( m_pkPolygons->GetNumElements() < POLYGONLIMIT )
{
//Add as final geometry
m_pkPolygons->Lock( Buffer::READ );
PolygonBufferPtr pkFinalPolygonBuffer = Core::Get()->GetRenderDevice()->CreatePolygonBuffer( Buffer::STATIC | Buffer::READPRIORITIZED, m_pkPolygons->GetNumElements(), m_pkPolygons->GetPolygon(), false );
m_pkPolygons->Unlock();
int *piMap = new int[ m_pkPolygons->m_pkVertexBuffer->GetNumElements() ];
memset( piMap, 0, m_pkPolygons->m_pkVertexBuffer->GetNumElements() * sizeof( int ) );
unsigned short usNumUsed = 0;
// ### FIXME: Can we achieve better locality of vertices?
/* DON'T STIP ABOVE: MUST MODIFY SOURCE POLYGON BUFFER TOO!!!
if( pkFinalPolygonBuffer->IsStripped() )
{
//If final polygon buffer is stripped, compress vertex buffer in strip order
PolygonStripBufferPtr pkStripBuf = pkFinalPolygonBuffer->GetStrip();
pkStripBuf->Lock( Buffer::WRITE );
unsigned short *pusIndex = pkStripBuf->GetIndices();
unsigned short *pusEnd = pusIndex + ( pkStripBuf->GetNumPolygons() + 2 );
for( ; pusIndex < pusEnd; ++pusIndex )
{
if( !piMap[ *pusIndex ] )
*pusIndex = ( piMap[ *pusIndex ] = ++usNumUsed ) - 1;
else
*pusIndex = piMap[ *pusIndex ] - 1;
}
pkStripBuf->Unlock();
}
else*/
{
//Compress vertex buffer in polygon order
pkFinalPolygonBuffer->Lock( Buffer::WRITE );
Polygon *pkPolygon = pkFinalPolygonBuffer->GetPolygon();
Polygon *pkPolygonEnd = pkPolygon + pkFinalPolygonBuffer->GetNumElements();
for( ; pkPolygon < pkPolygonEnd; ++pkPolygon )
{
if( !piMap[ pkPolygon->v[0] ] )
pkPolygon->v[0] = ( piMap[ pkPolygon->v[0] ] = ++usNumUsed ) - 1;
else
pkPolygon->v[0] = piMap[ pkPolygon->v[0] ] - 1;
if( !piMap[ pkPolygon->v[1] ] )
pkPolygon->v[1] = ( piMap[ pkPolygon->v[1] ] = ++usNumUsed ) - 1;
else
pkPolygon->v[1] = piMap[ pkPolygon->v[1] ] - 1;
if( !piMap[ pkPolygon->v[2] ] )
pkPolygon->v[2] = ( piMap[ pkPolygon->v[2] ] = ++usNumUsed ) - 1;
else
pkPolygon->v[2] = piMap[ pkPolygon->v[2] ] - 1;
}
pkFinalPolygonBuffer->Unlock();
// ### FIXME: TEMPORARY!!!
pkFinalPolygonBuffer->Stripify();
}
VertexBufferPtr pkFinalVertexBuffer = Core::Get()->GetRenderDevice()->CreateVertexBuffer( Buffer::STATIC | Buffer::READPRIORITIZED, usNumUsed, m_pkPolygons->m_pkVertexBuffer->GetVertexFormat() );
pkFinalVertexBuffer->Lock( Buffer::WRITE );
m_pkPolygons->m_pkVertexBuffer->Lock( Buffer::READ );
unsigned int uiSize = m_pkPolygons->m_pkVertexBuffer->GetVertexSize();
unsigned int uiNum = m_pkPolygons->m_pkVertexBuffer->GetNumElements();
unsigned char *pucSrc = (unsigned char*)m_pkPolygons->m_pkVertexBuffer->GetVertex();
unsigned char *pucDst = (unsigned char*)pkFinalVertexBuffer->GetVertex();
for( unsigned int uiCur = 0; uiCur < uiNum; ++uiCur, pucSrc += uiSize )
{
if( piMap[ uiCur ] )
fmemcpy( pucDst + ( uiSize * ( piMap[ uiCur ] - 1 ) ), pucSrc, uiSize );
}
m_pkPolygons->m_pkVertexBuffer->Unlock();
pkFinalVertexBuffer->Unlock();
pkFinalPolygonBuffer->m_pkVertexBuffer = pkFinalVertexBuffer;
pkFinalPolygonBuffer->m_pkMaterial = m_pkPolygons->m_pkMaterial;
m_pkPolygons = pkFinalPolygonBuffer;
delete [] piMap;
pvpkGeometries->push_back( this );
return;
}
AABB *pkAABB = (AABB*)GetBoundingVolume();
const Vector3d &kDim = pkAABB->GetDim();
VertexBufferPtr pkVertexBuffer = m_pkPolygons->m_pkVertexBuffer;
//All polygons is contained inside this node by parent
m_pkPolygons->Lock( Buffer::READ );
pkVertexBuffer->Lock( Buffer::READ );
float afSplitPlanes[3]; //Position of split plane along axis
int aiNumSplits[3]; //Number of split polygons, optimal is 0
int aiNum[3][2]; //Number of polygons in each subcube
float afSplitFactor[3]; //Factor between number of preserved and split faces, optimal is 1.0, worst is 0.0
float afVolumeFactor[3]; //Factor between resulting volumes, optimal is 1.0, worst is 0.0
float afDistributionFactor[3]; //Polygon distribution factor, optimal is 1.0, worst is 0.0
float afAxisFactor[3]; //Factor between split axis length and major axis length, optimal is 1.0, worst is 0.0
float afFinalFactor[3]; //Final split grade factor, optimal is 1.0, worst is 0.0
float fAverage;
int iMajorAxis = 0; //Bounding box major axis
if( kDim[1] > kDim[ iMajorAxis ] )
iMajorAxis = 1;
if( kDim[2] > kDim[ iMajorAxis ] )
iMajorAxis = 2;
unsigned int uiNumPolygons = m_pkPolygons->GetNumElements();
NeoEngine::Polygon *pkPolygon;
NeoEngine::Polygon *pkPolygonEnd = m_pkPolygons->GetPolygon( uiNumPolygons - 1 ) + 1;
unsigned int uiNumExtraVertices[3] = { 0, 0, 0 };
char *pcSide[3];
char *pcCurSide;
pcSide[0] = new char[ uiNumPolygons ];
pcSide[1] = new char[ uiNumPolygons ];
pcSide[2] = new char[ uiNumPolygons ];
//Get best split plane along each axis
for( int iAxis = 0; iAxis < 3; ++iAxis )
{
fAverage = 0.0f;
// FIXME: Median value might result in better split plane
// FIXME: This method can be replaced by simply averaging all vertices which can be summed in order for better cache performace
//Loop polygons and get average point along axis
for( pkPolygon = m_pkPolygons->GetPolygon(); pkPolygon < pkPolygonEnd; ++pkPolygon )
fAverage += ( (*(Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[0] ))[ iAxis ] + (*(Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[1] ))[ iAxis ] + (*(Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[2] ))[ iAxis ] ) / 3.0f;
fAverage /= float( uiNumPolygons );
// FIXME: Maybe base growth size on sub-AABB predicted size
float afLimit[2] = {
fAverage + kDim[ iAxis ] * SPLITGROW_THRESHOLD,
fAverage - kDim[ iAxis ] * SPLITGROW_THRESHOLD
};
pcCurSide = pcSide[ iAxis ];
aiNumSplits[ iAxis ] = 0;
aiNum[ iAxis ][0] = 0;
aiNum[ iAxis ][1] = 0;
//Calculate number of split polygons (polygons outside grow threshold
for( pkPolygon = m_pkPolygons->GetPolygon(); pkPolygon < pkPolygonEnd; ++pkPolygon, ++pcCurSide )
{
float afAxis[3] = { (*(Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[0] ))[ iAxis ], (*(Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[1] ))[ iAxis ], (*(Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[2] ))[ iAxis ] };
// ### FIXME: We should calculate splitting grade factors for the three planes at
// fAverage, afLimit[0] and afLimit[1] and pick the best plane+grade for this axis
if( ( afAxis[0] <= fAverage ) && ( afAxis[1] <= fAverage ) && ( afAxis[2] <= fAverage ) )
{
*pcCurSide = 1;
++aiNum[ iAxis ][0];
}
else if( ( afAxis[0] >= fAverage ) && ( afAxis[1] >= fAverage ) && ( afAxis[2] >= fAverage ) )
{
*pcCurSide = 2;
++aiNum[ iAxis ][1];
}
else
{
//See if polygon will fit inside grow threshold
if( ( afAxis[0] <= afLimit[0] ) && ( afAxis[1] <= afLimit[0] ) && ( afAxis[2] <= afLimit[0] ) )
{
*pcCurSide = 1;
++aiNum[ iAxis ][0];
}
else if( ( afAxis[0] >= afLimit[1] ) && ( afAxis[1] >= afLimit[1] ) && ( afAxis[2] >= afLimit[1] ) )
{
*pcCurSide = 2;
++aiNum[ iAxis ][1];
}
else
{
*pcCurSide = 0;
++aiNumSplits[ iAxis ];
//If one vertex is inside overgrowth area, split can go through that vertex (two vertices are outside!)
if( ( ( afAxis[0] < afLimit[0] ) && ( afAxis[0] > afLimit[1] ) ) ||
( ( afAxis[1] < afLimit[0] ) && ( afAxis[1] > afLimit[1] ) ) ||
( ( afAxis[2] < afLimit[0] ) && ( afAxis[2] > afLimit[1] ) ) )
{
//Split will go through one vertex
++aiNum[ iAxis ][0];
++aiNum[ iAxis ][1];
++uiNumExtraVertices[ iAxis ];
}
else
{
if( afAxis[0] < fAverage )
{
++(*pcCurSide);
++aiNum[ iAxis ][0];
}
else
{
--(*pcCurSide);
++aiNum[ iAxis ][1];
}
if( afAxis[1] < fAverage )
{
++(*pcCurSide);
++aiNum[ iAxis ][0];
}
else
{
--(*pcCurSide);
++aiNum[ iAxis ][1];
}
if( afAxis[2] < fAverage )
{
++(*pcCurSide);
++aiNum[ iAxis ][0];
}
else
{
--(*pcCurSide);
++aiNum[ iAxis ][1];
}
assert( ( *pcCurSide == 1 ) || ( *pcCurSide == -1 ) );
*pcCurSide = ( *pcCurSide > 0 ) ? -1 : -2;
uiNumExtraVertices[ iAxis ] += 2;
}
}
}
}
if( !aiNum[ iAxis ][0] || !aiNum[ iAxis ][1] )
afDistributionFactor[ iAxis ] = 0.0f; //Degenerate case
else
afDistributionFactor[ iAxis ] = ( aiNum[ iAxis ][0] > aiNum[ iAxis ][1] ) ? ( (float)aiNum[ iAxis ][1] / (float)aiNum[ iAxis ][0] ) : ( (float)aiNum[ iAxis ][0] / (float)aiNum[ iAxis ][1] );
//Calculate factors
afSplitFactor[ iAxis ] = 1.0f - ( float( aiNumSplits[ iAxis ] ) / float( uiNumPolygons ) );
afVolumeFactor[ iAxis ] = 1.0f - ( fabsf( fAverage - GetWorldTranslation()[ iAxis ] ) / kDim[ iAxis ] );
afAxisFactor[ iAxis ] = kDim[ iAxis ] / kDim[ iMajorAxis ];
afSplitPlanes[ iAxis ] = fAverage;
//Weight factors
afFinalFactor[ iAxis ] =
( ( afDistributionFactor[ iAxis ] * DISTRIBUTIONFACTOR_WEIGHT ) +
( afVolumeFactor[ iAxis ] * VOLUMEFACTOR_WEIGHT ) +
( afSplitFactor[ iAxis ] * SPLITFACTOR_WEIGHT ) +
( afAxisFactor[ iAxis ] * AXISFACTOR_WEIGHT ) ) / ( DISTRIBUTIONFACTOR_WEIGHT + VOLUMEFACTOR_WEIGHT + SPLITFACTOR_WEIGHT + AXISFACTOR_WEIGHT );
}
//Pick best split axis
int iSplitAxis = 0;
if( afFinalFactor[1] > afFinalFactor[ iSplitAxis ] )
iSplitAxis = 1;
if( afFinalFactor[2] > afFinalFactor[ iSplitAxis ] )
iSplitAxis = 2;
//Split geometry along selected plane
//Create two new polygon buffers
PolygonBufferPtr pkSubPolygonBuffer[2] = {
new PolygonBuffer( Buffer::NORENDER, aiNum[ iSplitAxis ][0] ),
new PolygonBuffer( Buffer::NORENDER, aiNum[ iSplitAxis ][1] )
};
pkSubPolygonBuffer[0]->Lock( Buffer::WRITE );
pkSubPolygonBuffer[1]->Lock( Buffer::WRITE );
pcCurSide = pcSide[ iSplitAxis ];
NeoEngine::Polygon *pkDestPolygon[2] = { pkSubPolygonBuffer[0]->GetPolygon(), pkSubPolygonBuffer[1]->GetPolygon() };
unsigned int uiNewVertex = pkVertexBuffer->GetNumElements();
//Create new vertex buffer if need split polygons
// ### FIXME: insert vertices close to split polygon vertices to maintain good locality
if( uiNumExtraVertices[ iSplitAxis ] )
{
VertexBufferPtr pkNewVertexBuffer = new VertexBuffer( Buffer::NORENDER, pkVertexBuffer->GetNumElements() + uiNumExtraVertices[ iSplitAxis ], pkVertexBuffer->GetVertexFormat(), pkVertexBuffer->GetVertex( 0 ) );
pkNewVertexBuffer->Lock( Buffer::WRITE );
pkVertexBuffer->Unlock();
pkVertexBuffer = pkNewVertexBuffer;
}
Vector3d kMin[2];
Vector3d kMax[2];
kMin[0].Set( numeric_limits< float >::max(), numeric_limits< float >::max(), numeric_limits< float >::max() );
kMin[1] = kMin[0];
kMax[0] = -kMin[0];
kMax[1] = -kMin[0];
for( pkPolygon = m_pkPolygons->GetPolygon(); pkPolygon < pkPolygonEnd; ++pkPolygon, ++pcCurSide )
{
if( *pcCurSide > 0 )
{
//Add polygon to one box
int iBox = *pcCurSide - 1;
*pkDestPolygon[ iBox ]++ = *pkPolygon;
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[0] ), &kMin[ iBox ], &kMax[ iBox ] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[1] ), &kMin[ iBox ], &kMax[ iBox ] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[2] ), &kMin[ iBox ], &kMax[ iBox ] );
}
else
{
unsigned char *apucVertex[3] = {
(unsigned char*)pkVertexBuffer->GetVertex( pkPolygon->v[0] ),
(unsigned char*)pkVertexBuffer->GetVertex( pkPolygon->v[1] ),
(unsigned char*)pkVertexBuffer->GetVertex( pkPolygon->v[2] )
};
float afPoint[3] = {
(*(Vector3d*)apucVertex[0])[ iSplitAxis ],
(*(Vector3d*)apucVertex[1])[ iSplitAxis ],
(*(Vector3d*)apucVertex[2])[ iSplitAxis ]
};
int aiPoint[3] = { 0, 1, 2 };
if( afPoint[ 0 ] > afPoint[ 1 ] )
{
aiPoint[0] = 1;
aiPoint[1] = 0;
}
if( afPoint[ aiPoint[ 1 ] ] > afPoint[ 2 ] )
{
aiPoint[2] = aiPoint[1];
aiPoint[1] = 2;
}
if( afPoint[ aiPoint[0] ] > afPoint[ aiPoint[1] ] )
{
int iTemp = aiPoint[0];
aiPoint[0] = aiPoint[1];
aiPoint[1] = iTemp;
}
// aiPoint[0] is start, aiPoint[1] is mid and aiPoint[2] is end
if( !*pcCurSide )
{
//Split polygon in two
float fFactor = ( afPoint[ aiPoint[1] ] - afPoint[ aiPoint[0] ] ) / ( afPoint[ aiPoint[2] ] - afPoint[ aiPoint[0] ] );
unsigned char *pucDestVertex = (unsigned char*)pkVertexBuffer->GetVertex( uiNewVertex++ );
//Interpolate vertex data
pkVertexBuffer->GetVertexFormat()->Interpolate( apucVertex[ aiPoint[0] ], apucVertex[ aiPoint[2] ], pucDestVertex, fFactor );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[0] ] ), &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[1] ] ), &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[1] ] ), &kMin[1], &kMax[1] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[2] ] ), &kMin[1], &kMax[1] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[1], &kMax[1] );
//Check polygon winding
if( ( ( aiPoint[0] + 1 ) % 3 ) == aiPoint[1] )
{
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = pkPolygon->v[ aiPoint[1] ];
pkDestPolygon[ 0 ]->v[2] = uiNewVertex;
++pkDestPolygon[ 0 ];
pkDestPolygon[ 1 ]->v[0] = uiNewVertex;
pkDestPolygon[ 1 ]->v[1] = pkPolygon->v[ aiPoint[1] ];
pkDestPolygon[ 1 ]->v[2] = pkPolygon->v[ aiPoint[2] ];
++pkDestPolygon[ 1 ];
}
else
{
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = uiNewVertex;
pkDestPolygon[ 0 ]->v[2] = pkPolygon->v[ aiPoint[1] ];
++pkDestPolygon[ 0 ];
pkDestPolygon[ 1 ]->v[0] = pkPolygon->v[ aiPoint[1] ];
pkDestPolygon[ 1 ]->v[1] = uiNewVertex;
pkDestPolygon[ 1 ]->v[2] = pkPolygon->v[ aiPoint[2] ];
++pkDestPolygon[ 1 ];
}
}
else if( *pcCurSide == -1 )
{
//Split polygon in three, two polygons in first box
//Split is along sorted vertices 0-2 and 1-2
assert( afPoint[0] < afSplitPlanes[ iSplitAxis ] );
assert( afPoint[1] < afSplitPlanes[ iSplitAxis ] );
assert( afPoint[2] > afSplitPlanes[ iSplitAxis ] );
float fFactor = ( afSplitPlanes[ iSplitAxis ] - afPoint[ aiPoint[0] ] ) / ( afPoint[ aiPoint[2] ] - afPoint[ aiPoint[0] ] );
unsigned char *pucDestVertex = (unsigned char*)pkVertexBuffer->GetVertex( uiNewVertex++ );
//Interpolate vertex data
pkVertexBuffer->GetVertexFormat()->Interpolate( apucVertex[ aiPoint[0] ], apucVertex[ aiPoint[2] ], pucDestVertex, fFactor );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[0] ] ), &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[1] ] ), &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[2] ] ), &kMin[1], &kMax[1] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[1], &kMax[1] );
fFactor = ( afSplitPlanes[ iSplitAxis ] - afPoint[ aiPoint[1] ] ) / ( afPoint[ aiPoint[2] ] - afPoint[ aiPoint[1] ] );
pucDestVertex = (unsigned char*)pkVertexBuffer->GetVertex( uiNewVertex++ );
//Interpolate vertex data
pkVertexBuffer->GetVertexFormat()->Interpolate( apucVertex[ aiPoint[1] ], apucVertex[ aiPoint[2] ], pucDestVertex, fFactor );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[1], &kMax[1] );
//Check polygon winding
if( ( ( aiPoint[0] + 1 ) % 3 ) == aiPoint[1] )
{
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = pkPolygon->v[ aiPoint[1] ];
pkDestPolygon[ 0 ]->v[2] = uiNewVertex - 1;
++pkDestPolygon[ 0 ];
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = uiNewVertex - 1;
pkDestPolygon[ 0 ]->v[2] = uiNewVertex - 2;
++pkDestPolygon[ 0 ];
pkDestPolygon[ 1 ]->v[0] = uiNewVertex - 2;
pkDestPolygon[ 1 ]->v[1] = uiNewVertex - 1;
pkDestPolygon[ 1 ]->v[2] = pkPolygon->v[ aiPoint[2] ];
++pkDestPolygon[ 1 ];
}
else
{
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = uiNewVertex - 2;
pkDestPolygon[ 0 ]->v[2] = uiNewVertex - 1;
++pkDestPolygon[ 0 ];
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = uiNewVertex - 1;
pkDestPolygon[ 0 ]->v[2] = pkPolygon->v[ aiPoint[1] ];
++pkDestPolygon[ 0 ];
pkDestPolygon[ 1 ]->v[0] = uiNewVertex - 1;
pkDestPolygon[ 1 ]->v[1] = uiNewVertex - 2;
pkDestPolygon[ 1 ]->v[2] = pkPolygon->v[ aiPoint[2] ];
++pkDestPolygon[ 1 ];
}
}
else //if( *pcCurSide == -2 )
{
//Split polygon in three, two polygons in second box
//Split is along sorted vertices 0-1 and 0-2
assert( afPoint[0] < afSplitPlanes[ iSplitAxis ] );
assert( afPoint[1] > afSplitPlanes[ iSplitAxis ] );
assert( afPoint[2] > afSplitPlanes[ iSplitAxis ] );
float fFactor = ( afSplitPlanes[ iSplitAxis ] - afPoint[ aiPoint[0] ] ) / ( afPoint[ aiPoint[1] ] - afPoint[ aiPoint[0] ] );
unsigned char *pucDestVertex = (unsigned char*)pkVertexBuffer->GetVertex( uiNewVertex++ );
//Interpolate vertex data
pkVertexBuffer->GetVertexFormat()->Interpolate( apucVertex[ aiPoint[0] ], apucVertex[ aiPoint[1] ], pucDestVertex, fFactor );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[0] ] ), &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[1] ] ), &kMin[1], &kMax[1] );
CheckMinMax( (Vector3d*)pkVertexBuffer->GetVertex( pkPolygon->v[ aiPoint[2] ] ), &kMin[1], &kMax[1] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[1], &kMax[1] );
fFactor = ( afSplitPlanes[ iSplitAxis ] - afPoint[ aiPoint[0] ] ) / ( afPoint[ aiPoint[2] ] - afPoint[ aiPoint[0] ] );
pucDestVertex = (unsigned char*)pkVertexBuffer->GetVertex( uiNewVertex++ );
//Interpolate vertex data
pkVertexBuffer->GetVertexFormat()->Interpolate( apucVertex[ aiPoint[0] ], apucVertex[ aiPoint[2] ], pucDestVertex, fFactor );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[0], &kMax[0] );
CheckMinMax( (Vector3d*)pucDestVertex, &kMin[1], &kMax[1] );
//Check polygon winding
if( ( ( aiPoint[0] + 1 ) % 3 ) == aiPoint[1] )
{
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = uiNewVertex - 2;
pkDestPolygon[ 0 ]->v[2] = uiNewVertex - 1;
++pkDestPolygon[ 0 ];
pkDestPolygon[ 1 ]->v[0] = uiNewVertex - 2;
pkDestPolygon[ 1 ]->v[1] = pkPolygon->v[ aiPoint[1] ];
pkDestPolygon[ 1 ]->v[2] = pkPolygon->v[ aiPoint[2] ];
++pkDestPolygon[ 1 ];
pkDestPolygon[ 1 ]->v[0] = uiNewVertex - 2;
pkDestPolygon[ 1 ]->v[1] = pkPolygon->v[ aiPoint[2] ];
pkDestPolygon[ 1 ]->v[2] = uiNewVertex - 1;
++pkDestPolygon[ 1 ];
}
else
{
pkDestPolygon[ 0 ]->v[0] = pkPolygon->v[ aiPoint[0] ];
pkDestPolygon[ 0 ]->v[1] = uiNewVertex - 1;
pkDestPolygon[ 0 ]->v[2] = uiNewVertex - 2;
++pkDestPolygon[ 0 ];
pkDestPolygon[ 1 ]->v[0] = uiNewVertex - 2;
pkDestPolygon[ 1 ]->v[1] = uiNewVertex - 1;
pkDestPolygon[ 1 ]->v[2] = pkPolygon->v[ aiPoint[2] ];
++pkDestPolygon[ 1 ];
pkDestPolygon[ 1 ]->v[0] = uiNewVertex - 2;
pkDestPolygon[ 1 ]->v[1] = pkPolygon->v[ aiPoint[2] ];
pkDestPolygon[ 1 ]->v[2] = pkPolygon->v[ aiPoint[1] ];
++pkDestPolygon[ 1 ];
}
}
}
}
pkSubPolygonBuffer[0]->Unlock();
pkSubPolygonBuffer[1]->Unlock();
pkSubPolygonBuffer[0]->m_pkVertexBuffer = pkVertexBuffer;
pkSubPolygonBuffer[1]->m_pkVertexBuffer = pkVertexBuffer;
pkSubPolygonBuffer[0]->m_pkMaterial = m_pkPolygons->m_pkMaterial;
pkSubPolygonBuffer[1]->m_pkMaterial = m_pkPolygons->m_pkMaterial;
pkVertexBuffer->Unlock();
m_pkPolygons->Unlock();
//Deallocate buffer before recursion since we don't need it anymore
m_pkPolygons = 0;
delete [] pcSide[0];
delete [] pcSide[1];
delete [] pcSide[2];
//Create child nodes and split
{
Geometry *pkSplitGeom[2] = { this, new Geometry() };
AABB *pkAABB = new AABB( ( kMax[0] - kMin[0] ) * 0.5f );
pkAABB->SetTranslation( kMin[0] + pkAABB->GetDim() );
// pkSplitGeom[0]->SetTranslation( pkAABB->GetTranslation() );
pkSplitGeom[0]->SetTranslation( pkAABB->GetTranslation() + pkAABB->m_kDelta );
pkSplitGeom[0]->SetBoundingVolume( pkAABB );
pkSplitGeom[0]->m_pkPolygons = pkSubPolygonBuffer[0];
pkSplitGeom[0]->Partition( pvpkGeometries, uiDepth + 1 );
pkAABB = new AABB( ( kMax[1] - kMin[1] ) * 0.5f );
pkAABB->SetTranslation( kMin[1] + pkAABB->GetDim() );
// pkSplitGeom[1]->SetTranslation( pkAABB->GetTranslation() );
pkSplitGeom[1]->SetTranslation( pkAABB->GetTranslation() + pkAABB->m_kDelta );
pkSplitGeom[1]->SetBoundingVolume( pkAABB );
pkSplitGeom[1]->m_pkPolygons = pkSubPolygonBuffer[1];
pkSplitGeom[1]->Partition( pvpkGeometries, uiDepth + 1 );
}
}
bool Geometry::Render( Frustum *pkFrustum, bool bForce )
{
//Skip scene node render method step, we don't need it
if( !RenderEntity::Render( pkFrustum, bForce ) )
return false;
RenderPrimitive &kPrim = ABTRoom::s_kRenderPrimitive;
if( m_pkPolygons->IsStripped() )
{
kPrim.m_ePrimitive = RenderPrimitive::TRIANGLESTRIP;
kPrim.m_pkPolygonStripBuffer = m_pkPolygons->GetStrip();
kPrim.m_uiNumPrimitives = m_pkPolygons->GetStrip()->GetNumElements();
}
else
{
kPrim.m_ePrimitive = RenderPrimitive::TRIANGLES;
kPrim.m_pkPolygonBuffer = m_pkPolygons;
kPrim.m_uiNumPrimitives = m_pkPolygons->GetNumElements();
}
kPrim.m_pkVertexBuffer = m_pkPolygons->m_pkVertexBuffer;
kPrim.m_pkMaterial = m_pkPolygons->m_pkMaterial;
Core::Get()->GetRenderDevice()->Render( kPrim, 0 );
return true;
}
bool Geometry::Intersection( const Ray &rkRay, ContactSet *pkContactSet )
{
m_pkPolygons->Lock( Buffer::READ );
//Intersection test with all polygons
VertexBufferPtr &pkVB = m_pkPolygons->m_pkVertexBuffer;
NeoEngine::Polygon *pkPolygon = m_pkPolygons->GetPolygon();
int iNumPolygons = m_pkPolygons->GetNumElements();
ContactSet kSet;
ContactSet *pkSet = 0;
bool bIntersection = false;
if( pkContactSet )
pkSet = &kSet;
pkVB->Lock( Buffer::READ );
for( int i = 0; i < iNumPolygons; ++i, ++pkPolygon )
{
if( NeoEngine::Intersection( rkRay, *(Vector3d*)pkVB->GetVertex( pkPolygon->v[0] ), *(Vector3d*)pkVB->GetVertex( pkPolygon->v[1] ), *(Vector3d*)pkVB->GetVertex( pkPolygon->v[2] ), pkSet ) )
{
if( !pkContactSet )
{
pkVB->Unlock();
m_pkPolygons->Unlock();
return true;
}
bIntersection = true;
}
}
pkVB->Unlock();
m_pkPolygons->Unlock();
if( bIntersection && pkContactSet )
{
if( !pkContactSet->m_vpkContacts.size() )
{
pkContactSet->m_vpkContacts.resize( pkSet->m_vpkContacts.size() );
vector< Contact* >::iterator ppkContact = pkSet->m_vpkContacts.begin();
vector< Contact* >::iterator ppkContactEnd = pkSet->m_vpkContacts.end();
vector< Contact* >::iterator ppkContactDst = pkContactSet->m_vpkContacts.begin();
for( ; ppkContact != ppkContactEnd; ++ppkContact, ++ppkContactDst )
{
(*ppkContact)->m_apkMaterials[0] = m_pkPolygons->m_pkMaterial;
*ppkContactDst = *ppkContact;
}
}
else
{
vector< Contact* >::reverse_iterator ppkContact = pkSet->m_vpkContacts.rbegin();
vector< Contact* >::reverse_iterator ppkContactEnd = pkSet->m_vpkContacts.rend();
for( ; ppkContact != ppkContactEnd; )
{
(*ppkContact)->m_apkMaterials[0] = m_pkPolygons->m_pkMaterial;
pkContactSet->Add( *ppkContact );
if ( ppkContact != ppkContactEnd )
++ppkContact;
}
}
pkSet->m_vpkContacts.clear();
}
return bIntersection;
}
bool Geometry::Intersection( BoundingVolume *pkVolume, ContactSet *pkContactSet )
{
m_pkPolygons->Lock( Buffer::READ );
//Intersection test with all polygons
VertexBuffer *pkVB = m_pkPolygons->m_pkVertexBuffer;
NeoEngine::Polygon *pkPolygon = m_pkPolygons->GetPolygon();
int iNumPolygons = m_pkPolygons->GetNumElements();
ContactSet kSet;
ContactSet *pkSet = 0;
bool bIntersection = false;
if( pkContactSet )
pkSet = &kSet;
pkVB->Lock( Buffer::READ );
unsigned int uiVSize = pkVB->GetVertexSize();
unsigned char *pucVertex = (unsigned char*)pkVB->GetVertex();
for( int i = 0; i < iNumPolygons; ++i, ++pkPolygon )
{
if( pkVolume->Intersection( *(Vector3d*)( pucVertex + uiVSize * pkPolygon->v[0] ), *(Vector3d*)( pucVertex + uiVSize * pkPolygon->v[1] ), *(Vector3d*)( pucVertex + uiVSize * pkPolygon->v[2] ), pkSet ) )
{
if( !pkContactSet )
{
pkVB->Unlock();
m_pkPolygons->Unlock();
return true;
}
bIntersection = true;
}
}
pkVB->Unlock();
m_pkPolygons->Unlock();
if( bIntersection && pkContactSet )
{
if( !pkContactSet->m_vpkContacts.size() )
{
pkContactSet->m_vpkContacts.resize( pkSet->m_vpkContacts.size() );
vector< Contact* >::iterator ppkContact = pkSet->m_vpkContacts.begin();
vector< Contact* >::iterator ppkContactEnd = pkSet->m_vpkContacts.end();
vector< Contact* >::iterator ppkContactDst = pkContactSet->m_vpkContacts.begin();
for( ; ppkContact != ppkContactEnd; ++ppkContact, ++ppkContactDst )
{
(*ppkContact)->m_apkMaterials[0] = m_pkPolygons->m_pkMaterial;
*ppkContactDst = *ppkContact;
}
}
else
{
vector< Contact* >::reverse_iterator ppkContact = pkSet->m_vpkContacts.rbegin();
vector< Contact* >::reverse_iterator ppkContactEnd = pkSet->m_vpkContacts.rend();
for( ; ppkContact != ppkContactEnd; )
{
(*ppkContact)->m_apkMaterials[0] = m_pkPolygons->m_pkMaterial;
pkContactSet->Add( *ppkContact );
if ( ppkContact != ppkContactEnd )
++ppkContact;
}
}
pkSet->m_vpkContacts.clear();
}
return bIntersection;
}
};
See more files for this project here