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

📄 object.cpp

📁 游戏编程精粹2第四章源码
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/* Copyright (C) Tom Forsyth, 2001. 
 * All rights reserved worldwide.
 *
 * This software is provided "as is" without express or implied
 * warranties. You may freely copy and compile this source into
 * applications you distribute provided that the copyright text
 * below is included in the resulting source code, for example:
 * "Portions Copyright (C) Tom Forsyth, 2001"
 */


#include "object.h"




int g_iNumOfObjectTrisDrawn = 0;
int g_iNumOfObjectVertsDrawn = 0;
int g_iMaxNumTrisDrawn = -1;
BOOL g_bOptimiseVertexOrder = FALSE;
BOOL g_bShowVIPMInfo = FALSE;
BOOL g_bUseFastButBadOptimise = TRUE;


// Controls for skiplists.
int g_iSkiplistMinCollapsesPerLevel = 10;
float g_fSkiplistMinCollapseFraction = 0.25f;


#if ALLOW_PROGRESS_BARS
HWND g_hProgress1 = NULL;		// Progress bar 1
HWND g_hProgress2 = NULL;		// Progress bar 2.
HWND g_hProgressWindow = NULL;	// Window that holds both bars.
HWND g_hWndApp = NULL;			// The main app window.


void CreateProgressBars ( void )
{
	if ( g_hProgressWindow == NULL )
	{
		ASSERT ( g_hProgress1 == NULL );
		ASSERT ( g_hProgress2 == NULL );
		ASSERT ( g_hWndApp != NULL );

		g_hProgressWindow =
			CreateDialog ( (HINSTANCE)GetWindowLong( g_hWndApp, GWL_HINSTANCE ),
							MAKEINTRESOURCE ( IDD_PROGRESS ),
							g_hWndApp,
							NULL );

		ASSERT ( g_hProgressWindow != NULL );
		DWORD dwError = GetLastError();

		g_hProgress1 = GetDlgItem ( g_hProgressWindow, IDC_PROGRESS1 );
		ASSERT ( g_hProgress1 != NULL );
		g_hProgress2 = GetDlgItem ( g_hProgressWindow, IDC_PROGRESS2 );
		ASSERT ( g_hProgress2 != NULL );

		ShowWindow ( g_hProgressWindow, SW_SHOWNORMAL );
	}
}

void BinProgressBars ( void )
{
	if ( g_hProgressWindow != NULL )
	{
		ASSERT ( g_hProgress1 != NULL );
		ASSERT ( g_hProgress2 != NULL );

		DestroyWindow ( g_hProgressWindow );

		g_hProgressWindow = NULL;
		g_hProgress1 = NULL;
		g_hProgress2 = NULL;
	}
}


#else //#if ALLOW_PROGRESS_BARS

void CreateProgressBars ( void ){}
void BinProgressBars ( void ) {}

#endif //#else //#if ALLOW_PROGRESS_BARS






char *VIPMTypeName ( VIPMTypeEnum type )
{
	switch ( type )
	{
	case VIPMType_Vanilla:
		return "vanilla";
		break;
	case VIPMType_SlidingWindow:
		return "sliding window";
		break;
	case VIPMType_MultilevelSkiplist:
		return "multilevel skiplist";
		break;
	default:
		ASSERT ( FALSE );
		return "unknown";
		break;
	}
}



// Call this to reorder the tris in this trilist to get good vertex-cache coherency.
// *pwList is modified (but obviously not changed in size or memory location).
void OptimiseVertexCoherencyTriList ( WORD *pwList, int iHowManyTris );

// Finds the weighted average number of verts read when rendering this list.
float GetNumVerticesLoadedTriList ( WORD *pwList, int iHowManyTris );

// Tuning gubbins.
void TuneValenceScores ( WORD *pwList, int iHowManyTris );



Object::Object()
{
	pNextCollapse = &CollapseRoot;
	iCurSlidingWindowLevel = 0;

	for ( int i = 0; i < VIPMType_Last; i++ )
	{
		pOptMesh[i] = OptimisedMesh::Create ( (VIPMTypeEnum)i, this );
	}
}


Object::~Object()
{
	BinCurrentObject();


	for ( int i = 0; i < VIPMType_Last; i++ )
	{
		if ( pOptMesh[i] != NULL )
		{
			delete pOptMesh[i];
			pOptMesh[i] = NULL;
		}
	}


	while ( CollapseRoot.ListNext() != NULL )
	{
		delete ( CollapseRoot.ListNext() );
	}

	// Bin any mesh data.
	while ( PermTriRoot.ListNext() != NULL )
	{
		delete ( PermTriRoot.ListNext() );
	}
	while ( PermEdgeRoot.ListNext() != NULL )
	{
		delete ( PermEdgeRoot.ListNext() );
	}
	while ( PermPtRoot.ListNext() != NULL )
	{
		delete ( PermPtRoot.ListNext() );
	}

}

// Call before D3D leaves.
void Object::AboutToChangeDevice ( void )
{
	// Not actually much to do.
	for ( int i = 0; i < VIPMType_Last; i++ )
	{
		if ( pOptMesh[i] != NULL )
		{
			pOptMesh[i]->AboutToChangeDevice();
		}
	}

	MarkAsDirty();
}



void Object::CreateTestObject ( LPDIRECT3DDEVICE8 pd3dDevice )
{
	MarkAsDirty();

	ASSERT ( PermPtRoot.ListNext() == NULL );
	ASSERT ( PermTriRoot.ListNext() == NULL );
	ASSERT ( PermEdgeRoot.ListNext() == NULL );

#if 0
	// Make a cube.
	MeshPt *ppt000 = new MeshPt ( &PermPtRoot );
	MeshPt *ppt001 = new MeshPt ( &PermPtRoot );
	MeshPt *ppt010 = new MeshPt ( &PermPtRoot );
	MeshPt *ppt011 = new MeshPt ( &PermPtRoot );
	MeshPt *ppt100 = new MeshPt ( &PermPtRoot );
	MeshPt *ppt101 = new MeshPt ( &PermPtRoot );
	MeshPt *ppt110 = new MeshPt ( &PermPtRoot );
	MeshPt *ppt111 = new MeshPt ( &PermPtRoot );

	ppt000->mypt.vPos = D3DXVECTOR3 ( -1.0f,  1.0f, -1.0f );
	ppt001->mypt.vPos = D3DXVECTOR3 (  1.0f,  1.0f, -1.0f );
	ppt010->mypt.vPos = D3DXVECTOR3 ( -1.0f,  1.0f,  1.0f );
	ppt011->mypt.vPos = D3DXVECTOR3 (  1.0f,  1.0f,  1.0f );
	ppt100->mypt.vPos = D3DXVECTOR3 ( -1.0f, -1.0f, -1.0f );
	ppt101->mypt.vPos = D3DXVECTOR3 (  1.0f, -1.0f, -1.0f );
	ppt110->mypt.vPos = D3DXVECTOR3 ( -1.0f, -1.0f,  1.0f );
	ppt111->mypt.vPos = D3DXVECTOR3 (  1.0f, -1.0f,  1.0f );

	// Dodgy normals.
	MeshPt *pt = PermPtRoot.ListNext();
	DWORD dwIndex = 0;
	while ( pt != NULL )
	{
		//pt->mypt.dwIndex = dwIndex++;
		D3DXVec3Normalize ( &(pt->mypt.vNorm), &(pt->mypt.vPos) );

		pt->mypt.iMaterialNumber = 0;

		pt = pt->ListNext();
	}


	MeshTri *ptri;
	// Top.
	ptri = new MeshTri ( ppt000, ppt010, ppt011, &PermTriRoot, &PermEdgeRoot );
	ptri = new MeshTri ( ppt000, ppt011, ppt001, &PermTriRoot, &PermEdgeRoot );
	// Bottom.
	ptri = new MeshTri ( ppt100, ppt111, ppt110, &PermTriRoot, &PermEdgeRoot );
	ptri = new MeshTri ( ppt100, ppt101, ppt111, &PermTriRoot, &PermEdgeRoot );
	// Left.
	ptri = new MeshTri ( ppt000, ppt110, ppt010, &PermTriRoot, &PermEdgeRoot );
	ptri = new MeshTri ( ppt000, ppt100, ppt110, &PermTriRoot, &PermEdgeRoot );
	// Right.
	ptri = new MeshTri ( ppt001, ppt011, ppt111, &PermTriRoot, &PermEdgeRoot );
	ptri = new MeshTri ( ppt001, ppt111, ppt101, &PermTriRoot, &PermEdgeRoot );
	// Front
	ptri = new MeshTri ( ppt000, ppt001, ppt101, &PermTriRoot, &PermEdgeRoot );
	ptri = new MeshTri ( ppt000, ppt101, ppt100, &PermTriRoot, &PermEdgeRoot );
	// Back
	ptri = new MeshTri ( ppt010, ppt111, ppt011, &PermTriRoot, &PermEdgeRoot );
	ptri = new MeshTri ( ppt010, ppt110, ppt111, &PermTriRoot, &PermEdgeRoot );
#else

	HRESULT hres;

	// Make a teapotahedron.
	LPD3DXMESH pmeshTeapot;
	ASSERT ( pd3dDevice != NULL );		// Slight fudge - shame we need a D3D device.
	hres = D3DXCreateTeapot ( pd3dDevice, &pmeshTeapot, NULL );
	// These are just some simpler test meshes
	//hres = D3DXCreatePolygon ( pd3dDevice, 1.0f, 6, &pmeshTeapot, NULL );
	//hres = D3DXCreateSphere ( pd3dDevice, 1.0f, 12, 6, &pmeshTeapot, NULL );
	//hres = D3DXCreateSphere ( pd3dDevice, 1.0f, 30, 15, &pmeshTeapot, NULL );


	// OK, now extract the data.
	int iNumVerts = pmeshTeapot->GetNumVertices();
	int iNumFaces = pmeshTeapot->GetNumFaces();

	LPDIRECT3DVERTEXBUFFER8 pVertexBuffer;
	hres = pmeshTeapot->GetVertexBuffer ( &pVertexBuffer );
	D3DVERTEXBUFFER_DESC vbdesc;
	hres = pVertexBuffer->GetDesc ( &vbdesc );
	// Create my "smart" pointer.
	MyFVFPointer pFVF ( vbdesc.FVF );
	BYTE *pbData;
	hres = pVertexBuffer->Lock ( 0, pFVF.GetFVFSize() * iNumVerts, &pbData, D3DLOCK_READONLY );
	pFVF.SetCurVertex ( pbData );

	// The de-index list.
	MeshPt **ppPts = new MeshPt*[iNumVerts];

	for ( int i = 0; i < iNumVerts; i++ )
	{
		ppPts[i] = new MeshPt ( &PermPtRoot );
		ppPts[i]->mypt.vPos		= pFVF.Position();
		ppPts[i]->mypt.vNorm	= pFVF.Normal();
		//ppPts[i]->mypt.fU		= pFVF.U0();
		//ppPts[i]->mypt.fV		= pFVF.V0();

		//ppPts[i]->mypt.dwIndex = i;

		++pFVF;
	}

	hres = pVertexBuffer->Unlock();
	pVertexBuffer->Release();


	// And now the index buffer.
	LPDIRECT3DINDEXBUFFER8 pIndexBuffer;
	hres = pmeshTeapot->GetIndexBuffer ( &pIndexBuffer );
	D3DINDEXBUFFER_DESC ibdesc;
	hres = pIndexBuffer->GetDesc ( &ibdesc );
	// Unlikely to get any 32bpp indices, but check, just in case.
	// If you do - well, I leave that as an exercise for the reader :-)

	// Oh - just found this comment in the docs:
	//
	// D3DXMESH_32BIT 
	//   The mesh has 32-bit indices instead of 16-bit indices.
	//   A 32-bit mesh can support up to 2^32-1 faces and vertices.
	//   This flag is not supported and should not be used. 
	//
	// So, that answers that question!
	ASSERT ( ibdesc.Format == D3DFMT_INDEX16 );

	// Also, assume that this defines a trilist. Not sure if the mesh tells us
	// what the primitive type is anywhere.
	WORD *pIndex;
	ASSERT ( sizeof (*pIndex) * iNumFaces * 3 == ibdesc.Size );
	hres = pIndexBuffer->Lock ( 0, ibdesc.Size, (BYTE**)&pIndex, D3DLOCK_READONLY );

	for ( int j = 0; j < iNumFaces; j++ )
	{
		MeshPt *ppt[3];
		for ( int i = 0; i < 3; i++ )
		{
			ASSERT ( *pIndex < iNumVerts );
			ppt[i] = ppPts[*pIndex];
			pIndex++;
		}

		MeshTri *ptri = new MeshTri ( ppt[0], ppt[1], ppt[2], &PermTriRoot, &PermEdgeRoot );

		ptri->mytri.iMaterialNumber = 0;
		ptri->pPt1->mypt.iMaterialNumber = 0;
		ptri->pPt2->mypt.iMaterialNumber = 0;
		ptri->pPt3->mypt.iMaterialNumber = 0;
		ptri->pEdge12->myedge.iMaterialNumber = 0;
		ptri->pEdge23->myedge.iMaterialNumber = 0;
		ptri->pEdge31->myedge.iMaterialNumber = 0;
	}

	hres = pIndexBuffer->Unlock();
	pIndexBuffer->Release();


	delete[] ppPts;


	// And finally bin the thing.
	pmeshTeapot->Release();
#endif

	iFullNumTris = 0;
	MeshTri *tri = PermTriRoot.ListNext();
	while ( tri != NULL )
	{
		// All the pts had better be the same material.
		ASSERT ( tri->pPt1->mypt.iMaterialNumber == tri->pPt2->mypt.iMaterialNumber );
		ASSERT ( tri->pPt1->mypt.iMaterialNumber == tri->pPt3->mypt.iMaterialNumber );
		tri->mytri.iMaterialNumber = tri->pPt1->mypt.iMaterialNumber;

		tri = tri->ListNext();
		iFullNumTris++;
	}

	MeshEdge *edge = PermEdgeRoot.ListNext();
	while ( edge != NULL )
	{
		// All the pts had better be the same material.
		ASSERT ( edge->pPt1->mypt.iMaterialNumber == edge->pPt2->mypt.iMaterialNumber );
		edge->myedge.iMaterialNumber = edge->pPt1->mypt.iMaterialNumber;

		edge = edge->ListNext();
	}

	iCurSlidingWindowLevel = 0;
	SetNewLevel ( iCurSlidingWindowLevel );
}

// Check that this is sensible.
void Object::CheckObject ( void )
{
	MeshEdge *edge = PermEdgeRoot.ListNext();
	while ( edge != NULL )
	{
		// All the pts had better be the same material.
		ASSERT ( edge->pPt1->mypt.iMaterialNumber == edge->pPt2->mypt.iMaterialNumber );
		ASSERT ( edge->myedge.iMaterialNumber == edge->pPt1->mypt.iMaterialNumber );
		edge = edge->ListNext();
	}

	MeshTri *tri = PermTriRoot.ListNext();
	while ( tri != NULL )
	{
		// All the pts had better be the same material.
		ASSERT ( tri->pPt1->mypt.iMaterialNumber == tri->pPt2->mypt.iMaterialNumber );
		ASSERT ( tri->pPt1->mypt.iMaterialNumber == tri->pPt3->mypt.iMaterialNumber );
		ASSERT ( tri->mytri.iMaterialNumber == tri->pPt1->mypt.iMaterialNumber );
		tri = tri->ListNext();
	}

	edge = CurEdgeRoot.ListNext();
	while ( edge != NULL )
	{
		// All the pts had better be the same material.
		ASSERT ( edge->pPt1->mypt.iMaterialNumber == edge->pPt2->mypt.iMaterialNumber );
		ASSERT ( edge->myedge.iMaterialNumber == edge->pPt1->mypt.iMaterialNumber );
		edge = edge->ListNext();
	}

	tri = CurTriRoot.ListNext();
	while ( tri != NULL )
	{
		// All the pts had better be the same material.
		ASSERT ( tri->pPt1->mypt.iMaterialNumber == tri->pPt2->mypt.iMaterialNumber );
		ASSERT ( tri->pPt1->mypt.iMaterialNumber == tri->pPt3->mypt.iMaterialNumber );
		ASSERT ( tri->mytri.iMaterialNumber == tri->pPt1->mypt.iMaterialNumber );
		// And all tris should be the current level or the next.
		ASSERT ( ( tri->mytri.iSlidingWindowLevel == iCurSlidingWindowLevel ) || 
				 ( tri->mytri.iSlidingWindowLevel == iCurSlidingWindowLevel + 1 ) );
		tri = tri->ListNext();
	}

	for ( int i = 0; i < VIPMType_Last; i++ )
	{
		if ( pOptMesh[i] != NULL )
		{
			pOptMesh[i]->Check();
		}
	}
}


// Bins all the current data.
void Object::BinCurrentObject ( void )
{
	MarkAsDirty();
	while ( CurTriRoot.ListNext() != NULL )
	{
		delete ( CurTriRoot.ListNext() );
	}
	while ( CurEdgeRoot.ListNext() != NULL )
	{
		delete ( CurEdgeRoot.ListNext() );
	}
	while ( CurPtRoot.ListNext() != NULL )
	{
		delete ( CurPtRoot.ListNext() );
	}
}

// Creates the current data from the permanent data.
void Object::MakeCurrentObjectFromPerm ( void )
{
	MarkAsDirty();
	BinCurrentObject();

	// Copy the points.
	for ( MeshPt *ppt = PermPtRoot.ListNext(); ppt != NULL; ppt = ppt->ListNext() )
	{
		// Temporarily link the current and permanent points for when I construct the tris.
		ppt->mypt.pTempPt = new MeshPt ( &CurPtRoot );
		ppt->mypt.pTempPt->mypt = ppt->mypt;
		ppt->mypt.pTempPt->mypt.pTempPt = ppt;
	}
	// Copy the edges.
	for ( MeshEdge *pedge = PermEdgeRoot.ListNext(); pedge != NULL; pedge = pedge->ListNext() )
	{
		MeshEdge *pNewEdge = new MeshEdge (	pedge->pPt1->mypt.pTempPt, 
											pedge->pPt2->mypt.pTempPt, 
											&CurEdgeRoot );
		pNewEdge->myedge = pedge->myedge;
	}
	// Copy the tris.
	int iNumTris = 0;
	for ( MeshTri *ptri = PermTriRoot.ListNext(); ptri != NULL; ptri = ptri->ListNext() )
	{
		MeshTri *pNewTri = new MeshTri (	ptri->pPt1->mypt.pTempPt, 
											ptri->pPt2->mypt.pTempPt, 

⌨️ 快捷键说明

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