Code Search for Developers
 
 
  

bsp.cpp from NeoEngineNG at Krugle


Show bsp.cpp syntax highlighted

/***************************************************************************
                     bsp.cpp  -  Room specification, BSP tree
                             -------------------
    begin                : Fri Dec 7 2001
    copyright            : (C) 2001 by Mattias Jansson
    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, NeoBSP, bsp.cpp

 The Initial Developer of the Original Code is Mattias Jansson.
 Portions created by Mattias Jansson are Copyright (C) 2001
 Reality Rift Studios. All Rights Reserved.

 ***************************************************************************/

#include "bsp.h"

#include <neoengine/plane.h>
#include <neoengine/aabb.h>
#include <neoengine/frustum.h>
#include <neoengine/collision.h>
#include <neoengine/contact.h>
#include <neoengine/renderprimitive.h>
#include <neoengine/render.h>
#include <neoengine/line.h>
#include <neoengine/logstream.h>

using namespace std;
using namespace NeoEngine;


namespace NeoBSP
{


BSPNode::BSPNode() :
	m_iType( BSPNode::NODE ),
	m_pkPartition( 0 ),
	m_pkFront( 0 ),
	m_pkBack( 0 ),
	m_pkAABB( 0 ),
	m_iVisCluster( -1 ),
	m_iID( -1 )
{
}


BSPNode::~BSPNode()
{
	delete m_pkAABB;
	delete m_pkBack;
	delete m_pkFront;
	delete m_pkPartition;
}


int BSPNode::AttachNode( SceneNode *pkNode )
{
	m_vpkSceneNodes.push_back( pkNode );

	return 0;
}


int BSPNode::DetachNode( SceneNode *pkNode )
{
	unsigned int uiEnd = m_vpkSceneNodes.size();

	vector<SceneNode*>::iterator ppkNode = m_vpkSceneNodes.begin();

	for( unsigned int i = 0; i < uiEnd; ++i, ++ppkNode )
		if( (*ppkNode) == pkNode )
		{
			m_vpkSceneNodes.erase( ppkNode );

			return 1;
		}
		
	return 0;
}


int BSPNode::UpdateNode( SceneNode *pkNode )
{
	//FIXME: Implement, and implement adding scene nodes
	//       to subnodes in BSP tree, and add subnode as
	//       scene partition node in scene node

	return 0;
}


void BSPNode::Render( RenderPrimitive *pkPrimitive, Frustum *pkFrustum )
{
	if( m_iType == NODE )
	{
		float fFactor = m_pkPartition->m_kNormal * pkFrustum->m_akPlanes[ Frustum::BACK ].m_kNormal;

		if( fFactor >= 0.0f )
		{	
			if( !m_pkBack->m_pkAABB || NeoEngine::Intersection( m_pkBack->m_pkAABB, pkFrustum ) )
				m_pkBack->Render( pkPrimitive, pkFrustum );
			
			if( !m_pkFront->m_pkAABB || NeoEngine::Intersection( m_pkFront->m_pkAABB, pkFrustum ) )
				m_pkFront->Render( pkPrimitive, pkFrustum );
		}
		else
		{	
			if( !m_pkFront->m_pkAABB || NeoEngine::Intersection( m_pkFront->m_pkAABB, pkFrustum ) )
				m_pkFront->Render( pkPrimitive, pkFrustum );
			
			if( !m_pkBack->m_pkAABB || NeoEngine::Intersection( m_pkBack->m_pkAABB, pkFrustum ) )
				m_pkBack->Render( pkPrimitive, pkFrustum );
		}
	}
	else
	{
		//if we reach this point, parent node or room have already tested our bounding volume collision with frustum
    	//if( m_pkBoundingVolume && !m_pkBoundingVolume->Collision( *((Frustum*)&rkFrustum) ) )
    		//return;

		//pkPrimitive->m_ModelMatrix            = m_TransMatrix;

		vector< PolygonBufferPtr >::iterator ppkBuffer    = m_vpkPolygons.begin();
		vector< PolygonBufferPtr >::iterator ppkBufferEnd = m_vpkPolygons.end();

		for( ; ppkBuffer != ppkBufferEnd; ++ppkBuffer )
		{
			//if( !(*ppkBuffer)->GetNumPolygons() )
				//continue;

			pkPrimitive->m_pkMaterial             = (*ppkBuffer)->m_pkMaterial;
			pkPrimitive->m_pkVertexBuffer         = (*ppkBuffer)->m_pkVertexBuffer;

			if( !(*ppkBuffer)->IsStripped() )
			{
				pkPrimitive->m_ePrimitive             = RenderPrimitive::TRIANGLES;
				pkPrimitive->m_pkPolygonBuffer        = (*ppkBuffer);
				pkPrimitive->m_uiNumPrimitives        = (*ppkBuffer)->GetNumElements();
			}
			else
			{
				pkPrimitive->m_ePrimitive             = RenderPrimitive::TRIANGLESTRIP;
				pkPrimitive->m_pkPolygonStripBuffer   = (*ppkBuffer)->GetStrip();
				pkPrimitive->m_uiNumPrimitives        = pkPrimitive->m_pkPolygonStripBuffer->GetNumElements();
			}

			Core::Get()->GetRenderDevice()->Render( *pkPrimitive, 0 );
		}

		//Render all scene nodes
		vector<SceneNode*>::iterator ppkNode     = m_vpkSceneNodes.begin();
		vector<SceneNode*>::iterator ppkNodeEnd  = m_vpkSceneNodes.end();

		SceneNode *pkNode;
		BoundingVolume *pkVolume;

		for( ; ppkNode != ppkNodeEnd; ++ppkNode )
		{
			pkNode = *ppkNode;

			if( pkNode->IsActive() && ( !( pkVolume = pkNode->GetBoundingVolume() ) || pkVolume->Intersection( pkFrustum ) ) )
				pkNode->Render( pkFrustum, false );
		}
	}
}


BSPNode *BSPNode::GetNextNode( const Vector3d &rkPoint )
{
	if( m_iType == LEAF )
		return this;

	BSPNode *pkNode      = ( m_pkPartition->Distance( rkPoint ) > 0 ) ? m_pkFront : m_pkBack;
	BSPNode *pkOtherNode = ( pkNode == m_pkFront ) ? m_pkBack : m_pkFront;

	BSPNode *pkRetNode   = 0;

	if( pkNode->m_pkAABB->Intersection( rkPoint ) )
		if( ( pkRetNode = pkNode->GetNextNode( rkPoint ) ) )
			return pkRetNode;

	if( pkOtherNode->m_pkAABB->Intersection( rkPoint ) )
		if( ( pkRetNode = pkOtherNode->GetNextNode( rkPoint ) ) )
			return pkRetNode;

	return pkRetNode;
}


bool BSPNode::Intersection( const Ray &rkRay, ContactSet *pkContactSet )
{
	bool bIntersection = false;

	if( m_iType == NODE )
	{
		if( !m_pkFront->m_pkAABB || m_pkFront->m_pkAABB->Intersection( rkRay ) )
			bIntersection = m_pkFront->Intersection( rkRay, pkContactSet );
			
		if( ( pkContactSet || !bIntersection ) && ( !m_pkBack->m_pkAABB || m_pkBack->m_pkAABB->Intersection( rkRay ) ) )
			bIntersection |= m_pkBack->Intersection( rkRay, pkContactSet );
	}
	else
	{
		//if we reach this point, parent node or room have already tested our bounding volume intersection with object
		vector< PolygonBufferPtr >::iterator ppkBuffer = m_vpkPolygons.begin();
		vector< PolygonBufferPtr >::iterator ppkEnd    = m_vpkPolygons.end();

		ContactSet  kSet;
		ContactSet *pkSet = 0;

		if( pkContactSet )
			pkSet = &kSet;

		for( ; ppkBuffer != ppkEnd; ++ppkBuffer )
		{
			(*ppkBuffer)->Lock( Buffer::READ );

			//Intersection test with all polygons
			VertexBufferPtr    &pkVB         = (*ppkBuffer)->m_pkVertexBuffer;
			NeoEngine::Polygon *pkPolygon    = (*ppkBuffer)->GetPolygon();
			int                 iNumPolygons = (*ppkBuffer)->GetNumElements();

			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 )
					{
						(*ppkBuffer)->Unlock();
						return true;
					}

					bIntersection = true;
				}
			}

			if( pkSet && pkSet->m_vpkContacts.size() )
			{
				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] = (*ppkBuffer)->m_pkMaterial;
						*ppkContactDst = *ppkContact;
					}
				}
				else
				{
					vector< Contact* >::iterator ppkContact    = pkSet->m_vpkContacts.end() - 1;
					vector< Contact* >::iterator ppkContactEnd = pkSet->m_vpkContacts.begin();

					for( ; ppkContact >= ppkContactEnd; --ppkContact )
					{
						(*ppkContact)->m_apkMaterials[0] = (*ppkBuffer)->m_pkMaterial;

						pkContactSet->Add( *ppkContact );
					}
				}
					
				pkSet->m_vpkContacts.clear();
			}

			(*ppkBuffer)->Unlock();
		}
	}

	return bIntersection;
}


bool BSPNode::Intersection( BoundingVolume *pkVolume, ContactSet *pkContactSet )
{
	bool bIntersection = false;

	if( m_iType == NODE )
	{
		if( !m_pkFront->m_pkAABB || pkVolume->Intersection( m_pkFront->m_pkAABB ) )
			bIntersection = m_pkFront->Intersection( pkVolume, pkContactSet );
			
		if( ( pkContactSet || !bIntersection ) && ( !m_pkBack->m_pkAABB || pkVolume->Intersection( m_pkBack->m_pkAABB ) ) )
			bIntersection |= m_pkBack->Intersection( pkVolume, pkContactSet );
	}
	else
	{
		//if we reach this point, parent node or room have already tested our bounding volume intersection with object
		vector< PolygonBufferPtr >::iterator ppkBuffer = m_vpkPolygons.begin();
		vector< PolygonBufferPtr >::iterator ppkEnd    = m_vpkPolygons.end();

		ContactSet  kSet;
		ContactSet *pkSet = 0;

		if( pkContactSet )
			pkSet = &kSet;

		for( ; ppkBuffer != ppkEnd; ++ppkBuffer )
		{
			(*ppkBuffer)->Lock( Buffer::READ );

			//Intersection test with all polygons
			VertexBufferPtr    &pkVB         = (*ppkBuffer)->m_pkVertexBuffer;
			NeoEngine::Polygon *pkPolygon    = (*ppkBuffer)->GetPolygon();
			int                 iNumPolygons = (*ppkBuffer)->GetNumElements();

			for( int i = 0; i < iNumPolygons; ++i, ++pkPolygon )
			{			
				if( pkVolume->Intersection( *(Vector3d*)pkVB->GetVertex( pkPolygon->v[0] ), *(Vector3d*)pkVB->GetVertex( pkPolygon->v[1] ), *(Vector3d*)pkVB->GetVertex( pkPolygon->v[2] ), pkSet ) )
				{
					if( !pkContactSet )
					{
						(*ppkBuffer)->Unlock();
						return true;
					}

					bIntersection = true;
				}
			}

			if( pkSet && pkSet->m_vpkContacts.size() )
			{
				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] = (*ppkBuffer)->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] = (*ppkBuffer)->m_pkMaterial;

						pkContactSet->Add( *ppkContact );
						
						if ( ppkContact != ppkContactEnd )
							++ppkContact;
					}
				}
					
				pkSet->m_vpkContacts.clear();
			}

			(*ppkBuffer)->Unlock();
		}
	}

	return bIntersection;
}











BSPVisCluster::~BSPVisCluster()
{
	if( m_pucData )
		delete [] m_pucData, m_pucData = 0;
}









BSPRoom::BSPRoom( const string &rstrName ) :
  Room( rstrName )
{
	m_pkRootNode        = 0;
	m_pkVisCluster      = 0;
	m_pkRenderPrimitive = new RenderPrimitive;
}


BSPRoom::~BSPRoom()
{
	delete m_pkRootNode;
	delete m_pkVisCluster;
	delete m_pkRenderPrimitive;
}


bool BSPRoom::Render( Frustum *pkFrustum, bool bForce )
{
	if( m_pkVisCluster )
	{
		BSPNode *pkCamNode = m_pkRootNode;

		Vector3d kCamPos = pkFrustum->GetTranslation();

		while( pkCamNode && pkCamNode->m_iType == BSPNode::NODE )
			pkCamNode = pkCamNode->GetNextNode( kCamPos );
/*
		if( pkCamNode->m_iVisCluster < 0 )
			Core::Get()->Log( LogDevice::LOGLEVEL_ERROR, "[BSPRoom::Render] inconsistency, negative camera leaf vis cluster offset\n" );

		if( pkCamNode && !pkCamNode->m_pkAABB->Intersection( kCamPos ) )
		{
			AABB *pkAABB = (AABB*)pkCamNode->m_pkAABB;

			Core::Get()->Log( LogDevice::LOGLEVEL_ERROR, "[BSPRoom::Render] invalid data, camera node does not contain camera pos\n" );
			Core::Get()->Log( LogDevice::LOGLEVEL_ERROR, "[BSPRoom::Render] camera pos [ %.2f %.2f %.2f ]\n", kCamPos.x, kCamPos.y, kCamPos.z );
			Core::Get()->Log( LogDevice::LOGLEVEL_ERROR, "[BSPRoom::Render] node bbox  [ %.2f %.2f %.2f ] dim [ %.2f %.2f %.2f ]\n", pkAABB->GetTranslation().x, pkAABB->GetTranslation().y, pkAABB->GetTranslation().z, pkAABB->GetDim().x, pkAABB->GetDim().y, pkAABB->GetDim().z );
		}
*/
		for( unsigned int i = 0; i < m_vpkLeaves.size(); ++i )
		{
			BSPNode *pkLeaf = m_vpkLeaves[i];

			int iCamVis  = pkCamNode ? pkCamNode->m_iVisCluster : -1;
			int iNodeVis = pkLeaf->m_iVisCluster;

			if( ( iCamVis >= 0 ) && ( iNodeVis >= 0 ) )
			{			
				unsigned char *pucVis = m_pkVisCluster->m_pucData;

				pucVis += ( iCamVis * m_pkVisCluster->m_iRowLength );

				if( !( pucVis[ ( iNodeVis >> 3 ) & 0x1FFFFFF ] & ( 1 << ( iNodeVis & 7 ) ) ) )
					continue;
			}

			//Render leaf if bbox intersect with frustum
			if( !m_vpkLeaves[i]->m_pkAABB || NeoEngine::Intersection( m_vpkLeaves[i]->m_pkAABB, pkFrustum ) )
			{
				m_vpkLeaves[i]->Render( m_pkRenderPrimitive, pkFrustum );
				//m_vpkLeaves[i]->m_pkAABB->RenderOutlines();
			}
		}
	}
	else if( m_pkRootNode )
		m_pkRootNode->Render( m_pkRenderPrimitive, pkFrustum );


	Room::Render( pkFrustum, false );

	//Reset pointers
	m_pkRenderPrimitive->m_pkVertexBuffer       = 0;
	m_pkRenderPrimitive->m_pkPolygonBuffer      = 0;
	m_pkRenderPrimitive->m_pkPolygonStripBuffer = 0;
	m_pkRenderPrimitive->m_pkMaterial           = 0;

	return true;
}


int BSPRoom::AttachNode( SceneNode *pkNode, bool bKeepWorldSRT )
{
	return Room::AttachNode( pkNode, bKeepWorldSRT );
	//return m_pkRootNode->AttachNode( pkNode );
}


int BSPRoom::DetachNode( SceneNode *pkNode )
{
	return Room::DetachNode( pkNode );
	//return m_pkRootNode->DetachNode( pkNode );
}


bool BSPRoom::Intersection( const Ray &rkRay, ContactSet *pkContactSet )
{
	//Lock all vertex buffers for reading
	vector<VertexBufferPtr>::iterator ppkBuffer = m_vpkVertexBuffers.begin();
	vector<VertexBufferPtr>::iterator ppkEnd    = m_vpkVertexBuffers.end();

	for( ; ppkBuffer != ppkEnd; ++ppkBuffer )
		(*ppkBuffer)->Lock( Buffer::READ );

	bool bIntersection = m_pkRootNode ? m_pkRootNode->Intersection( rkRay, pkContactSet ) : false;

	ppkBuffer = m_vpkVertexBuffers.begin();

	for( ; ppkBuffer != ppkEnd; ++ppkBuffer )
		(*ppkBuffer)->Unlock();

	bIntersection |= Room::Intersection( rkRay, pkContactSet );

	return bIntersection;
}


bool BSPRoom::Intersection( BoundingVolume *pkVolume, ContactSet *pkContactSet )
{
	//Lock all vertex buffers for reading
	vector<VertexBufferPtr>::iterator ppkBuffer = m_vpkVertexBuffers.begin();
	vector<VertexBufferPtr>::iterator ppkEnd    = m_vpkVertexBuffers.end();

	for( ; ppkBuffer != ppkEnd; ++ppkBuffer )
		(*ppkBuffer)->Lock( Buffer::READ );

	bool bIntersection = m_pkRootNode ? m_pkRootNode->Intersection( pkVolume, pkContactSet ) : false;

	ppkBuffer = m_vpkVertexBuffers.begin();

	for( ; ppkBuffer != ppkEnd; ++ppkBuffer )
		(*ppkBuffer)->Unlock();

	bIntersection |= Room::Intersection( pkVolume, pkContactSet );

	return bIntersection;
}


}; // namespace NeoBSP




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
  bsp.cpp
  bsp.h
  chunk.cpp
  chunk.h
  dll.cpp
  link.h
  neobsp-static.dev
  neobsp.cbp
  neobsp.dev
  neobsp.dsp
  neobsp.layout
  neobsp.vcproj