⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 brush.cpp

📁 BSP地形系统和光照贴图的技术详解
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// Brush.cpp: implementation of the CBrush class.
//
//////////////////////////////////////////////////////////////////////

#include "d3dfont.h"
#include "Brush.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBrush::CBrush()
{
	m_pFaceList			= NULL;
	m_nTotalPlane		= 0;
	m_nFaceCount		= 0;
	m_nTotalPlane		= 0;
	m_nVertexCount		= 0;
	m_pTriangleIndex	= NULL;
	m_pVertex			= NULL;
	m_szName[0]			= '\0';
	m_pNext				= NULL;
	m_pPrev				= NULL;
	m_bUnited			= FALSE;

	m_nTCount			= 0;
	m_pTVtx				= NULL;

	m_nTFCount			= 0;
	m_pTIndex			= NULL;
	m_nTexture			= 0;
}

CBrush::~CBrush()
{
	if( m_pFaceList )
	{
		CFace * curr = NULL, * next = NULL;
		for(curr = m_pFaceList; curr ; curr = next)
		{
			next = curr->m_pNext;
			delete curr;
		}
	}
/*
	if( m_pNext )
	{
		m_pNext->Destroy();
	}
*/
}

//打开max 文件使用的时候,创建 brush时,使用的函数.
BOOL CBrush::InitBrush()
{
	for( int i = 0; i < m_nFaceCount ; i++ )
	{
		CFace *f = CFace::CreateFace();
		BSPVERTEX* ver = new BSPVERTEX[3];
		ver[0] = m_pVertex[m_pTriangleIndex[i]._0];
		ver[1] = m_pVertex[m_pTriangleIndex[i]._1];
		ver[2] = m_pVertex[m_pTriangleIndex[i]._2];
		
		ver[0].u = m_pTVtx[m_pTIndex[i]._0].x;
		ver[0].v = m_pTVtx[m_pTIndex[i]._0].z;
		ver[1].u = m_pTVtx[m_pTIndex[i]._1].x;
		ver[1].v = m_pTVtx[m_pTIndex[i]._1].z;
		ver[2].u = m_pTVtx[m_pTIndex[i]._2].x;
		ver[2].v = m_pTVtx[m_pTIndex[i]._2].z;

		f->m_vList = ver;
		f->m_nNum = 3;
		f->m_nTexture = m_nTexture;

		D3DXPLANE plane;
		D3DXPlaneFromPoints( &plane, &ver[0].pos, &ver[1].pos, &ver[2].pos );
		int res = FindSamePlane( plane );
		if( res == -1 )
		{
			m_Planes[m_nTotalPlane] = plane;
			f->m_nPlane = m_nTotalPlane++;
		}
		else
			f->m_nPlane = res;

		f->AddNext( m_pFaceList );
		m_pFaceList = f;
	}
	delete[] m_pVertex;
	delete[] m_pTriangleIndex;

	delete[] m_pTVtx;
	delete[] m_pTIndex;
	return TRUE;
}

BOOL CBrush::Create( D3DXVECTOR3 *pList, int n )
{
	/*
	for( int i = 0 ; i < n/3 ; i++ )
	{
		CFace* f = CFace::CreateFace();
		f->m_vList = &pList[i*3];
		f->m_nNum = 3;
		D3DXPLANE plane;
		D3DXPlaneFromPoints( &plane, &pList[i*3], &pList[i*3+1], &pList[i*3+2]);
		int res = FindSamePlane( plane );
		if( res == -1 )
		{
			m_Planes[m_nTotalPlane] = plane;
			f->m_nPlane = m_nTotalPlane++;
		}
		else
			f->m_nPlane = res;

		f->AddNext( m_pFaceList );
		m_pFaceList = f;
	}
	*/
	return TRUE;
}

BOOL CBrush::Create( CFace * pList )
{
	CFace * f = NULL;
	int nCount = 0;
	for( f = pList ; f ; f = f->m_pNext, nCount++ )
	{
		D3DXPLANE plane;
		D3DXPlaneFromPoints( &plane, &f->m_vList[0].pos, &f->m_vList[1].pos, &f->m_vList[2].pos );
		int res = FindSamePlane( plane );
		if( res == -1 )
		{
			m_Planes[m_nTotalPlane] = plane;
			f->m_nPlane = m_nTotalPlane++;
		}
		else
			f->m_nPlane = res;
	}
	m_pFaceList = pList;
	m_nFaceCount = nCount;
	return TRUE;
}

int CBrush::FindSamePlane(D3DXPLANE &plane)
{
	for( int i = 0 ; i < m_nTotalPlane ; i++ )
	{
		if( ComparePlane( m_Planes[i], plane ) )
			return i;
	}
	return -1;
}

BOOL CBrush::ComparePlane(D3DXPLANE &a, D3DXPLANE &b)
{
	if( a.a == b.a && a.b == b.b && a.c == b.c && a.d == b.d )
		return TRUE;
	return FALSE;
}

BOOL CBrush::Render( LPDIRECT3DDEVICE8 pd3dDevice, CD3DFont* pFont )
{
	CFace * f = NULL;
	for( f = m_pFaceList ; f ; f = f->m_pNext )
	{
		if( pFont )
		{
			for( int i = 0; i < f->m_nNum ; i++ )
			{
				D3DXMATRIX	mW, mV, mP, mO;
				pd3dDevice->GetTransform( D3DTS_WORLD, &mW );
				pd3dDevice->GetTransform( D3DTS_VIEW, &mV );
				pd3dDevice->GetTransform( D3DTS_PROJECTION, &mP );
				mO = mW * mV * mP;
				D3DXVECTOR3 vI = f->m_vList[i].pos;
				D3DXVECTOR3 vO;
				D3DXVec3TransformCoord( &vO, &vI, &mO );
				char	str[16];
				wsprintf( str, "( %d, %d, %d )", (int)f->m_vList[i].pos.x, (int)f->m_vList[i].pos.y,(int)f->m_vList[i].pos.z );
				pFont->DrawText(400.0f * (vO.x+1.0f), 600 - 300.0f * (vO.y+1.0f), 0xff000000, str );
			}
		}
		pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLELIST, 1, f->m_vList, sizeof( BSPVERTEX )  );
	}

	if( pFont )
	{
		char s[16];
		wsprintf( s, "NUMBER OF FACE : %d", SizeOfFace( m_pFaceList ) );
		pFont->DrawText( 400, 10, 0xff000000, s );
	}

	if( m_pNext )
		m_pNext->Render( pd3dDevice, pFont );

	return TRUE;
}


CBrush* CBrush::Subtraction(CBrush *pB)
{
	CFace * bk_root = NULL;
	CFace * f = NULL, *front = NULL, *back = NULL, *pNext = NULL, *pCurr;
	int plane_split[10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, num_split = 0;
	
	f = pB->m_pFaceList;
	for( pCurr = f ; pCurr ; pCurr = f )
	{
		f = f->m_pNext;
		for( int i = 0 ; i < m_nTotalPlane ; i++ )
		{
			front = NULL;
			back = NULL;
			BOOL bSplit = FALSE;
			DivideFrontBack( m_Planes[i], pCurr, &front, &back, bSplit, FALSE, NULL );
			if( back )
			{
				if( bSplit )
				{
					BOOL bSearch = FALSE;
					for( int j = 0 ; j < num_split ; j++ )
					{
						if( plane_split[j] == i )
						{
							bSearch = TRUE;
							break;
						}
					}
					if( !bSearch )
					{
						plane_split[num_split++] = i;
					}
				}
				if( back->m_pNext )
					back->m_pNext->AddNext( bk_root );
				else
					back->AddNext( bk_root );
				bk_root = back;
			}
		}
	}

	int i_fr = SizeOfFace( bk_root );
	if( bk_root )
	{
		SplitContactFace( plane_split, num_split, &bk_root, pB );
		
		CBrush * pNew = new CBrush();
		pNew->Create( bk_root );
		return pNew;
	}

	return NULL;
}

//现有的 Union
CBrush* CBrush::operator + ( CBrush &pB )
{
	CFace * fr_root = NULL;
	CFace * f = NULL, *front = NULL, *back = NULL, *pNext = NULL, *pCurr;
	int plane_split[10] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }, num_split = 0;
	
	f = pB.m_pFaceList;
	for( pCurr = f ; pCurr ; pCurr = f )
	{
		f = f->m_pNext;
		for( int i = 0 ; i < m_nTotalPlane ; i++ )
		{
			front = NULL;
			back = NULL;
			BOOL bSplit = FALSE;
			DivideFrontBack( m_Planes[i], pCurr, &front, &back, bSplit, TRUE, NULL );

			if( bSplit )
			{
				BOOL bSearch = FALSE;
				for( int j = 0 ; j < num_split ; j++ )
				{
					if( plane_split[j] == i )
					{
						bSearch = TRUE;
						break;
					}
				}
				if( !bSearch )
				{
					plane_split[num_split++] = i;
				}
			}
			
			if( front )
			{
				//删除solid面的face.. 由于在倒∟形的BRUSH,solid的场所存在face 
				//必须制作为solid的BRUSH..
				
				if( front->m_pNext )
					front->m_pNext->AddNext( fr_root );
				else
					front->AddNext( fr_root );
				fr_root = front;
			}
		}
	}

	int i_fr = SizeOfFace( fr_root );
	if( fr_root )
	{
		SplitContactFace( plane_split, num_split, &fr_root, &pB );
		
		CBrush * pNew = new CBrush();
		pNew->Create( fr_root );
		return pNew;
	}
	return NULL;
}

//在brush2中删除进入内部的 brush1的 face. 
BOOL CBrush::DeleteInsideFace(CBrush &brush1, CBrush &brush2)
{
	CFace * new_root = NULL;
	CFace * face = NULL, *face1 = brush2.m_pFaceList;
	int nSplit[32], nCnt = 0;


	for( face = brush1.m_pFaceList; face ; face = face->m_pNext )
	{
		for( int i = 0 ; i < brush2.m_nTotalPlane ; i++ )
		{
			CFace * fr = NULL, * bk = NULL;
			if( TrySplit( &brush2, i, face, fr, bk ) )
			{
				face->m_bDelete = TRUE;
				for( CFace * f = fr ; f->m_pNext ; f = f->m_pNext )
					;
				f->m_pNext = new_root;
				new_root = fr;

				for( f = bk ; f->m_pNext ; f = f->m_pNext )
					;
				f->m_pNext = new_root;
				new_root = bk;

				nSplit[nCnt++] = i;
			}
		}
	}

	if( new_root )
	{
		CFace * curr = NULL;
		for( curr = brush1.m_pFaceList ; curr->m_pNext ; curr = curr->m_pNext )
			;
		curr->m_pNext = new_root;
		brush1.Create( brush1.m_pFaceList );
	}
	
	DeleteBackFace( brush2.m_Planes, brush2.m_nTotalPlane, brush1.m_pFaceList );
	
	return TRUE;
}

BOOL CBrush::DeleteBackFace(D3DXPLANE * planes, int num, CFace * &pList)
{
	CFace * curr = NULL;
	int res = 0, back = 0;
	for( curr = pList ; curr ; curr = curr->m_pNext )
	{
		back = 0;
		for( int i = 0 ; i < num ; i++ )
		{
			res = Classify( &planes[i], curr->m_vList, curr->m_nNum );
			switch( res )
			{
				case SIDE_ON:
				case SIDE_BACK:
					back++;
					break;
			}
		}
		if( back == num )
			curr->m_bDelete = TRUE;
	}
	return TRUE;
}


BOOL CBrush::TrySplit( CBrush* brush, int num, CFace * &f, CFace* &fr, CFace* &bk )
{
	BOOL bCheck = FALSE;
	CFace * curr = NULL;
	int res = Classify( &brush->m_Planes[num], f->m_vList, f->m_nNum );

	switch( res )
	{
		case SIDE_ON:
		case SIDE_FRONT:
		case SIDE_BACK:
			break;
		case SIDE_SPLIT:
			for( curr = brush->m_pFaceList ; curr ; curr = curr->m_pNext )
			{
				if( curr->m_nPlane == num )
				{
					if( IsColliedTriangles( f, curr ) )
					{
						bCheck = TRUE;
						break;
					}
				}
			}
			if( !bCheck )
				return FALSE;

			CFace * front = NULL, * back = NULL, * tmp = NULL;
			Split( &brush->m_Planes[num], f, &front, &back );
			
			if( !front && !back )
				break;
			f->m_bDelete = TRUE;

			fr = front;
			bk = back;
			return TRUE;
	}	

	return FALSE;
}

BOOL CBrush::SplitContactFace( int *pPlane, int nPlane, CFace** pList, CBrush * pBrush )
{
	CFace * cface = NULL;
	if( nPlane <= 0 )
		return FALSE;

	CFace * fr_root = NULL, * fr = NULL, * bk = NULL;

	for( int i = 0; i < nPlane ; i++ )
	{
		cface = NULL;
		for( cface = m_pFaceList ; cface ; cface = cface->m_pNext )
		{
			if( cface->m_nPlane == pPlane[i] )
			{
				for( int n = 0 ; n < pBrush->m_nTotalPlane ; n++ )
				{
					fr = NULL;
					bk = NULL;
					//Union函数丽的 DivideFrontBack函数第五参数是为了确认是否分割
					//而添加的参数.
					//如果是TRUE,在dividefrontback函数内,cface检查 
					//冲突状态.检查m_collision..
					BOOL bTmp = TRUE;
					DivideFrontBack( pBrush->m_Planes[n], cface, &fr, &bk, bTmp, TRUE, pBrush );
					if( fr )
					{
						if( fr->m_pNext )
							fr->m_pNext->AddNext( fr_root );
						else
							fr->AddNext( fr_root );
						fr_root = fr;
					}
				}
			}
			else
			{
				BOOL bCheck = FALSE;
				for( int cnt = 0 ; cnt < nPlane ; cnt++ )
				{
					if( cface->m_nPlane == pPlane[cnt] )
						bCheck = TRUE;
				}

				if( cface && !bCheck )
				{
					CFace * new_face = CFace::CreateFace();
					FaceCopy( cface, new_face );
					new_face->AddNext( fr_root );
					fr_root = new_face;
				}
			}
		}
	}
	
	CFace * tail = NULL;
	for( tail = fr_root ; tail->m_pNext ; tail = tail->m_pNext )
		;
	tail->AddNext( *pList );
	*pList = fr_root;
	return TRUE;
}

//如果值写入pBrush,在SplitContactFace中调用.
//如果NULL写入pBrush,在Union中调用第一个函数

BOOL CBrush::DivideFrontBack(D3DXPLANE &plane, CFace *f, CFace **fr, CFace **bk, BOOL &bSplit, BOOL bIsUnion, CBrush* pBrush )
{
	CFace * nf = CFace::CreateFace();
	FaceCopy( f, nf );
	int res = Classify( &plane, nf->m_vList, nf->m_nNum );

//	相对面的Normal相反的情况..(相互附贴)使用的参数
	D3DXVECTOR3 plane_normal( plane.a, plane.b, plane.c );
	D3DXVECTOR3 vBA, vCA;
	D3DXVECTOR3 vCross, face_normal;

	float dot = 0;


	switch( res )
	{
		case SIDE_ON:
			if( bIsUnion )
			{
/*
				nf->AddNext( *bk );
				*bk = nf;
		%Union的情况下,由于没有必要,为了防止 memory leak..
*/
				delete nf;
			}
			else
			{
				nf->AddNext( *fr );
				*fr = nf;
			}

//	相对面的Normal相反的情况..(相互附贴)
//	将TRUEb代入Split参数,以后计算时需要
			vBA = f->m_vList[1].pos - f->m_vList[0].pos;
			vCA = f->m_vList[2].pos - f->m_vList[0].pos;
			D3DXVec3Cross( &vCross, &vBA, &vCA );
			D3DXVec3Normalize( &face_normal, &vCross );
			
			dot = D3DXVec3Dot( &plane_normal, &face_normal );
			
			if( dot < 0 )
				bSplit = TRUE;

			break;
		case SIDE_FRONT:
			nf->AddNext( *fr );
			*fr = nf;
			break;
		case SIDE_BACK:
			if( bIsUnion )
			{
/*
		%Union的情况下,由于没有必要,为了防止 memory leak..
				nf->AddNext( *bk );
				*bk = nf;
		%%% memory leak 规瘤甫 困秦 %%%
*/
				delete nf;
			}
			break;
		case SIDE_SPLIT:
			CFace * front = NULL, * back = NULL, * pFace = NULL;
//bSplit代入 TRUE,通过 f或者复制的 nf检查是否有冲突状态..
//如果不是冲突状态,清除nf,返回 FALSE.
			if( bSplit )
			{
				if( !nf->m_bCollision )
				{
					nf->AddNext( *fr );
					*fr = nf;
					return FALSE;
				}
				else
				{
					delete nf;
				}
			}
///////////// 防止memory leak  /////////
//清除的理由: split 时,没有使用复制件nf,直接使用 f分割
//分割面生成了新的 face,复制件就不需要了.
			else
			{
				delete nf;
			}

//具有brush的 face中,检查相同平面上的face和对象face两个三角形是否处于
//冲突状态,如果不是冲突,删除nf,返回 FALSE.
//如果冲突,将face的主参数 m_bCollision设为 TRUE, 
//进行split.
			BOOL bColl = FALSE;
			if( pBrush == NULL )
			{
				for( pFace = m_pFaceList ; pFace ; pFace = pFace->m_pNext )
				{
					if( m_Planes[pFace->m_nPlane] == plane )
					{
	//f具有一个cface,由于被coding,就没有制作for的必要了.
						if( IsColliedTriangles( pFace, f ) )
						{
							pFace->m_bCollision = TRUE;
							f->m_bCollision = TRUE;
							bColl = TRUE;
						}
					}
				}
				if( !bColl )
				{
					return FALSE;
				}
			}// end if( pBrush == NULL ) Union的情况下,只在第一种情况下使用.

			Split( &plane, f, &front, &back );
			if( !front && !back )
				break;
			if( front->m_pNext )
			{
				if( bIsUnion )
				{
					front->m_pNext->AddNext( *fr );
					*fr = front;
				}
				else
				{
					front->m_pNext->AddNext( *bk );
					*bk = front;
				}
			}
			else 
			{
				if( bIsUnion )
				{
					front->AddNext( *fr );
					*fr = front;
				}
				else
				{
					front->AddNext( *bk );
					*bk = front;
				}
			}
			if( back->m_pNext )
			{
				if( bIsUnion )
				{
/*
		%Union的情况下,由于没有必要,为了防止 memory leak..
					back->m_pNext->AddNext( *bk );
					*bk = back;
*/
					delete back->m_pNext;
					delete back;
				}
				else
				{
					back->m_pNext->AddNext( *fr );
					*fr = back;
				}
			}
			else
			{
				if( bIsUnion )
				{
/*
		%Union的情况下,由于没有必要,为了防止 memory leak..
					back->AddNext( *bk );
					*bk = back;
*/
					delete back;
				}
				else
				{
					back->AddNext( *fr );
					*fr = back;
				}
			}
			bSplit = TRUE;
			break;
	}	
	return TRUE;
}

BOOL CBrush::FaceCopy(CFace *pOrig, CFace *pCopy)
{
	pCopy->m_nNum = pOrig->m_nNum;
	pCopy->m_bCollision = pOrig->m_bCollision;
	BSPVERTEX * copy = new BSPVERTEX[pOrig->m_nNum];
	for( int i = 0; i < pOrig->m_nNum ; i++ )
	{
		copy[i] = pOrig->m_vList[i];
	}
	pCopy->m_vList = copy;
	pCopy->m_nTexture = pOrig->m_nTexture;
	pCopy->m_nLightMap = pOrig->m_nLightMap;
	return TRUE;
}

int CBrush::Classify( D3DXPLANE *plane, BSPVERTEX *v, int num )
{
	int front = 0, back = 0, on = 0;
	float res = 0;

	for (int cnt = 0; cnt < num; cnt++)
	{
		res = D3DXPlaneDotCoord( plane, &v[cnt].pos );

		if ( res > EPSILON )
			front++;
		else if ( res < -EPSILON )
			back++;
		else
		{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -