Code Search for Developers
 
 
  

geometry.cpp from NeoEngineNG at Krugle


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

NeoEngineNG

NeoenEngine NG (Next Generation) is the evolution of neoengine one,it\'s a different development from NeoEngine2, it\'s a direct inherits from NeoEngine one.\n

Project homepage: http://sourceforge.net/projects/neoengineng
Programming language(s): C,C++
License: other

  Makefile.am
  SConscript
  base.h
  chunk.cpp
  chunk.h
  dll.cpp
  geometry.cpp
  geometry.h
  link.h
  neoabt-static.dev
  neoabt.cbp
  neoabt.dev
  neoabt.dsp
  neoabt.layout
  neoabt.vcproj
  node.cpp
  node.h
  room.cpp
  room.h