bspnode.cpp

来自「BSP地形系统和光照贴图的技术详解」· C++ 代码 · 共 575 行

CPP
575
字号
// BspNode.cpp: implementation of the CBspNode class.
//
//////////////////////////////////////////////////////////////////////

//#include "d3dfont.h"
#include "BspNode.h"

CFrustum::~CFrustum()
{

}


CFrustum::CFrustum()
{
	ZeroMemory( m_vtx, sizeof( m_vtx[0] ) * 8 );
	ZeroMemory( m_plane, sizeof( m_plane[0] ) * 6 );
}

BOOL CFrustum::Make( D3DXMATRIX* pmatViewProj )
{
	int			i;
	D3DXMATRIX	matInv;
	// projected的整个画面
	m_vtx[0].x = -1.0f;	m_vtx[0].y = -1.0f;	m_vtx[0].z = -1.0f;
	m_vtx[1].x =  1.0f;	m_vtx[1].y = -1.0f;	m_vtx[1].z = -1.0f;
	m_vtx[2].x =  1.0f;	m_vtx[2].y = -1.0f;	m_vtx[2].z = 1.0f;
	m_vtx[3].x = -1.0f;	m_vtx[3].y = -1.0f;	m_vtx[3].z = 1.0f;
	m_vtx[4].x = -1.0f;	m_vtx[4].y =  1.0f;	m_vtx[4].z = -1.0f;
	m_vtx[5].x =  1.0f;	m_vtx[5].y =  1.0f;	m_vtx[5].z = -1.0f;
	m_vtx[6].x =  1.0f;	m_vtx[6].y =  1.0f;	m_vtx[6].z = 1.0f;
	m_vtx[7].x = -1.0f;	m_vtx[7].y =  1.0f;	m_vtx[7].z = 1.0f;

	D3DXMatrixInverse(&matInv, NULL, pmatViewProj );

	// 将view * proj的逆矩阵与 vtx相乘,出现 world坐标
	for( i = 0; i < 8; i++ )
		D3DXVec3TransformCoord( &m_vtx[i], &m_vtx[i], &matInv );

	// 通过得到的 world坐标制作 frustum plane
	D3DXPlaneFromPoints(&m_plane[0], m_vtx+4, m_vtx+7, m_vtx+6);	// up plane
	D3DXPlaneFromPoints(&m_plane[1], m_vtx  , m_vtx+1, m_vtx+2);	// bottom plane
	D3DXPlaneFromPoints(&m_plane[2], m_vtx  , m_vtx+4, m_vtx+5);	// near plane
	D3DXPlaneFromPoints(&m_plane[3], m_vtx+2, m_vtx+6, m_vtx+7);	// far plane
	D3DXPlaneFromPoints(&m_plane[4], m_vtx  , m_vtx+3, m_vtx+7);	// left plane
	D3DXPlaneFromPoints(&m_plane[5], m_vtx+1, m_vtx+5, m_vtx+6);	// right plane

//	for OpenGL
//	MakePlane(&m_plane[0], m_vtx+4, m_vtx+7, m_vtx+6);	// up plane
//	MakePlane(&m_plane[1], m_vtx  , m_vtx+1, m_vtx+2);	// bottom plane
//	MakePlane(&m_plane[2], m_vtx  , m_vtx+4, m_vtx+5);	// near plane
//	MakePlane(&m_plane[3], m_vtx+2, m_vtx+6, m_vtx+7);	// far plane
//	MakePlane(&m_plane[4], m_vtx  , m_vtx+3, m_vtx+7);	// left plane
//	MakePlane(&m_plane[5], m_vtx+1, m_vtx+5, m_vtx+6);	// right plane

	return TRUE;
}

int CFrustum::IsIn( D3DXVECTOR3* pVec )
{
	float		fDist;
	int			i = 0, nLeft = 0, nRight = 0, nUp = 0;
	{
		for( i = 0; i < 4; i++ )
		{
			fDist = D3DXPlaneDotCoord( &m_plane[4], &pVec[i] );
			if( fDist > 0 ) 
				nLeft++;
			fDist = D3DXPlaneDotCoord( &m_plane[5], &pVec[i] );
			if( fDist > 0 ) 
				nRight++;
//			fDist = D3DXPlaneDotCoord( &m_plane[0], &pVec[i] );
//			if( fDist > 0 ) 
//				nUp++;
		}
		if( (nLeft + nRight ) == 0 )
			return 2;					//完全绘制好的时候
		else if( nLeft == 4 || nRight == 4 )
			return 0;					//完全没有绘制好的时候
		else	
			return 1;					//部分绘制的时候
//		for OpenGL
//		fDist = m_plane[4].a * pv->x + m_plane[4].b * pv->y + m_plane[4].c * pv->z + m_plane[4].d;
//		if( fDist < 0 ) return FALSE;
//		fDist = m_plane[5].a * pv->x + m_plane[5].b * pv->y + m_plane[5].c * pv->z + m_plane[5].d;
//		if( fDist < 0 ) return FALSE;
	}

	return TRUE;
}

BOOL CFrustum::Draw( LPDIRECT3DDEVICE8 pDev )
{
	WORD		index[] = { 0, 2, 1,
							0, 3, 2,
							4, 7, 6,
							4, 6, 5,
							1, 5, 6,
							1, 6, 2,
							0, 3, 7,
							0, 7, 4,
							0, 4, 5,
							0, 5, 1,
							3, 7, 6,
							3, 6, 2 };

	typedef struct tagVTX
	{
		D3DXVECTOR3	p;
		DWORD		diffuse;
	} VTX;

	VTX		vtx[8];

	for( int i = 0 ; i < 8 ; i++ )
	{
		vtx[i].p = m_vtx[i];
		vtx[i].diffuse = 0x80ff0000;
	}

	pDev->SetVertexShader( D3DFVF_XYZ|D3DFVF_DIFFUSE );
	pDev->SetStreamSource( 0, NULL, 0 );
	pDev->SetIndices( NULL, 0 );
	pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE);
	pDev->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
	pDev->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_ONE );
	pDev->SetTexture( 0, NULL );
	pDev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
	pDev->DrawIndexedPrimitiveUP( D3DPT_TRIANGLELIST, 0, 8, 12, index, D3DFMT_INDEX16, vtx, sizeof( vtx[0] ) );

    pDev->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
    pDev->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
    pDev->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
	pDev->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
	return TRUE;
}

void MakePlane( D3DXPLANE* pPlane, D3DXVECTOR3* pv0, D3DXVECTOR3* pv1, D3DXVECTOR3* pv2 )
{
	D3DXPlaneFromPoints( pPlane, pv0, pv1, pv2 );

//	for OpenGL
//	CVector	v0, v1, v2;
//	v1 = *pv1 - *pv0;
//	v2 = *pv2 - *pv0;
//	D3DXVec3Cross( &v0, &v1, &v2 );
//	D3DXVec3Normalize( &v0, &v0 );

//	pPlane->a = v0.x;
//	pPlane->b = v0.y;
//	pPlane->c = v0.z;
//	pPlane->d = -( v0.x * pv0->x + v0.y * pv0->y + v0.z * pv0->z );
}

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

CWinding::CWinding()
{
	n				= 0;
}

CWinding::~CWinding()
{

}

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



CBspNode::CPortal::CPortal()
{
	m_pNext[0]		= NULL;
	m_pNext[1]		= NULL;
	m_pWinding		= NULL;
	m_pNode[0]		= NULL;
	m_pNode[1]		= NULL;
	m_nVisCnt		= 0;
	m_nFaceCnt		= 0;

	m_bRender		= TRUE;
	m_ppFaceList	= NULL;
}

CBspNode::CPortal::~CPortal()
{
	if( m_pWinding )
	{
		delete m_pWinding;
		m_pWinding = NULL;
	}
	if( m_ppFaceList )
	{
		delete[] m_ppFaceList;
	}
	m_pNode[0] = NULL;
	m_pNode[1] = NULL;
	m_pNext[0] = NULL;
	m_pNext[1] = NULL;
}

void CBspNode::CPortal::AddPortalToNodes( CBspNode *front, CBspNode *back )
{
	if( m_pNode[0] || m_pNode[1] )
		;		// error
	m_pNode[0]= front;
	if( front )
	{
		m_pNext[0] = front->m_pPortals;
		front->m_pPortals = this;
	}
	
	m_pNode[1] = back;
	if( back )
	{
		m_pNext[1] = back->m_pPortals;
		back->m_pPortals = this;
	}
}

void CBspNode::CPortal::RemovePortalFromNode ( CBspNode *l )
{
	CPortal	**pp, *t;
	
// remove reference to the current portal

	pp = &l->m_pPortals;
	while (1)
	{
		t = *pp;
		if (!t)
			return;	//error

		if ( t == this )
			break;

		if (t->m_pNode[0] == l)
			pp = &t->m_pNext[0];
		else if (t->m_pNode[1] == l)
			pp = &t->m_pNext[1];
		else
			return; //error
	}
	
	if ( m_pNode[0] == l)
	{
		*pp = m_pNext[0];
		m_pNode[0] = NULL;
	}
	else if (m_pNode[1] == l)
	{
		*pp = m_pNext[1];	
		m_pNode[1] = NULL;
	}
}

void CBspNode::CPortal::Render( LPDIRECT3DDEVICE8 pd3dDevice )
{
	if( m_pWinding )
		pd3dDevice->DrawPrimitiveUP( D3DPT_TRIANGLEFAN, 2, m_pWinding->vPoint ,sizeof( D3DXVECTOR3 ));
//	if( m_pNode[0] )
//		m_pNode[0]->Render( pd3dDevice, NULL );
//	if( m_pNode[1] )
//		m_pNode[1]->Render( pd3dDevice, NULL );
}

CFace::CFace()
{
	m_bDelete	= FALSE;
	m_bCollision = FALSE;
	m_bUsed		= FALSE;
	m_bInside	= FALSE;
	m_nNum		= 0;
	m_pNext		= NULL;
	m_pPrev		= NULL;
	m_vList		= NULL;

	m_nTexture	= -1;
	m_nLightMap = 0;
}

CFace::~CFace()
{
	if( m_vList )
	{
		delete[] m_vList;
	}
}

CFace*	CFace::CreateFace()
{
	CFace* p = new CFace();
	return p;
}

BOOL	CFace::MakePlane( BSPVERTEX* v, int n )
{
	/*
	if( n < 3 )
		return FALSE;

//	D3DXPlaneFromPoints( &m_facePlane, &v[0], &v[2], &v[1] );
	
	m_vList = v;
	m_nNum = n;
	*/
	return TRUE;
	
}

BOOL CFace::AddNext(CFace *pNext)
{
	m_pNext = pNext;
	return TRUE;
}

BOOL CFace::AddTail(CFace *pTail)
{
	if( m_pNext )
		m_pNext->AddTail( pTail );
	else
	{
		m_pNext = pTail;
		return TRUE;
	}
	return FALSE;
}

BOOL CFace::SetVertexList(BSPVERTEX *pList)
{
	m_vList = pList;
	return TRUE;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBspNode::CBspNode()
{
	m_bIsSolid		= FALSE;
	m_bIsLeaf		= FALSE;
	m_bRender		= FALSE;
	m_pBack			= NULL;
	m_pFront		= NULL;
	m_pFaceList		= NULL;
	m_pPortals		= NULL;
	m_pTXData		= NULL;
	m_vMax			= D3DXVECTOR3( -BSP_BOGUS, -BSP_BOGUS, -BSP_BOGUS );
	m_vMin			= D3DXVECTOR3( BSP_BOGUS, BSP_BOGUS, BSP_BOGUS );
}

CBspNode::~CBspNode()
{
	if( m_pFaceList && !m_bIsSolid && m_bIsLeaf )
	{
		CFace * curr = NULL, * next = NULL;
		for( curr = m_pFaceList; curr ; curr = next )
		{
			next = curr->m_pNext;
			curr->m_pNext = NULL;
			delete curr;
		}
	}

	if( m_pBack )
		delete m_pBack;
	if( m_pFront )
		delete m_pFront;
}


BOOL CBspNode::Render(LPDIRECT3DDEVICE8 pd3dDevice,  CD3DFont* pFont )
{
//	pd3dDevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE );
	if( m_bIsLeaf && !m_bIsSolid )
	{
		pd3dDevice->SetRenderState(D3DRS_LIGHTING,FALSE);
		
		
		CFace * f;
		for( f = m_pFaceList; f ; f = f->m_pNext )
		{
			pd3dDevice->SetTexture( 0, m_pTXData[f->m_nTexture].texture );
/*
			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 );
				}
			}
			else */
				pd3dDevice->DrawPrimitiveUP(D3DPT_TRIANGLELIST, 1,f->m_vList, sizeof( BSPVERTEX )  );
		}
		
	}

	if( m_pBack )
		m_pBack->Render( pd3dDevice, pFont );
	if( m_pFront )
		m_pFront->Render( pd3dDevice, pFont );
	return TRUE;
}

BOOL CBspNode::SetFrontNode(CBspNode *pNode)
{
	m_pFront = pNode;
	return TRUE;
}

BOOL CBspNode::SetBackNode(CBspNode *pNode)
{
	m_pBack = pNode;
	return TRUE;
}

BOOL CBspNode::SetFaceList(CFace *pFace)
{
	m_pFaceList = pFace;
	return TRUE;
}

BOOL CBspNode::IsCollision( BOOL &b, D3DXVECTOR3 &v, CBspNode * & render_start)
{
	if( m_bIsLeaf && !m_bIsSolid )
	{
		render_start = this;
	}
	if( m_bIsSolid )
	{
		b = TRUE;
		return TRUE;
	}
	int res = ClassifyPoint( v );
	if( res == FACE_FRONT )
	{
		if( m_pFront && !b )
		{
			m_pFront->IsCollision( b, v, render_start );
		}
	}
	else if( res == FACE_BACK )
	{
		if( m_pBack && !b )
		{
			m_pBack->IsCollision( b, v, render_start );
		}
	}
	return FALSE;
}

int CBspNode::ClassifyPoint(D3DXVECTOR3 &v)
{
	float res = D3DXPlaneDotCoord( &m_plane, &v );
	if( res > EPSILON )
		return FACE_FRONT;
	else if( res < -EPSILON )
		return FACE_BACK;
	else if( res < EPSILON && res > -EPSILON )
		return FACE_ON;
	return FACE_SPLIT;
}

int CBspNode::GetFaceCount()
{
	int count = 0;
	for( CFace* f = m_pFaceList ; f ; f = f->m_pNext )
	{
		count++;
	}
	return count;
}

void CBspNode::InitRender()
{
	m_bRender = FALSE;
	if( m_pFront )
		m_pFront->InitRender();
	if( m_pBack )
		m_pBack->InitRender();
}

///////////////////////////////// THING CLASS ///////////////////

void CThing::InitThing()
{
	m_pFaceList = new BSPVERTEX[m_nFaceCount*3];
	int n = 0;
	for( int i = 0; i < m_nFaceCount ; i++)
	{
		m_pFaceList[n] = m_pVertex[m_pTriangleIndex[i]._0];
		m_pFaceList[n].u = m_pTVtx[m_pTIndex[i]._0].x;
		m_pFaceList[n].v = m_pTVtx[m_pTIndex[i]._0].z;
		n++;

		m_pFaceList[n] = m_pVertex[m_pTriangleIndex[i]._1];
		m_pFaceList[n].u = m_pTVtx[m_pTIndex[i]._1].x;
		m_pFaceList[n].v = m_pTVtx[m_pTIndex[i]._1].z;
		n++;

		m_pFaceList[n] = m_pVertex[m_pTriangleIndex[i]._2];
		m_pFaceList[n].u = m_pTVtx[m_pTIndex[i]._2].x;
		m_pFaceList[n].v = m_pTVtx[m_pTIndex[i]._2].z;
		n++;

/*
		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;
}

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

BOOL CThing::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;
}

⌨️ 快捷键说明

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