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

📄 object.cpp

📁 游戏编程精华02-含有几十个游戏编程例子
💻 CPP
📖 第 1 页 / 共 5 页
字号:
		qSum = qLast;
	}
	else
	{
		// Find the sum of the QEMs of the tris that will be binned.
		for ( MeshTri *ptri = pptBinned->FirstTri(); ptri != NULL; ptri = pptBinned->NextTri() )
		{
			qSum += Quad ( ptri->pPt1->mypt.vPos, ptri->pPt2->mypt.vPos, ptri->pPt3->mypt.vPos );
		}

		if ( bTryToCacheResult )
		{
			qLast = qSum;
			pptLast = pptBinned;
		}
		else
		{
			pptLast = NULL;
		}
	}

	// And find the error once the collapse has happened.
	return qSum.FindError ( pptKept->mypt.vPos );
}



// Call this if you make a change to the mesh.
// It will mark all the OptimisedMeshes hanging off it as dirty.
void Object::MarkAsDirty ( void )
{
	bSomethingHappened = TRUE;

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



ObjectInstance::ObjectInstance ( Object *pObject /*= NULL*/, ObjectInstance *pRoot /*= NULL*/ )
{
	pObj = pObject;
	D3DXMatrixIdentity( &matOrn );

	ListInit();
	if ( pRoot != NULL )
	{
		ListAddAfter ( pRoot );
	}

	for ( int i = 0; i < VIPMType_Last; i++ )
	{
		pOptMeshInst[i] = NULL;
	}

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

	// Start with the naive method.
	iRenderMethod = -1;

	iCurCollapses = 0;

}

ObjectInstance::~ObjectInstance ( void )
{
	pObj = NULL;

	ListDel();

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

}



void ObjectInstance::RenderCurrentObject ( LPDIRECT3DDEVICE8 pd3ddev, int iMaterialNumber, int iSlidingWindowLevel /*= -1*/, BOOL bShowOptiMesh /*= FALSE*/ )
{
	ASSERT ( ( iRenderMethod >= -1 ) && ( iRenderMethod < VIPMType_Last ) );
	if ( bShowOptiMesh &&
		 ( iRenderMethod >= 0 ) &&
		 ( pOptMeshInst[iRenderMethod] != NULL ) )
	{
		pOptMeshInst[iRenderMethod]->RenderCurrentObject ( pd3ddev, iMaterialNumber, iCurCollapses );
	}
	else
	{
		// Want plain bog-slow rendering, or the OptMeshInstance doesn't exist.
		pObj->RenderCurrentObject ( pd3ddev, iMaterialNumber, iSlidingWindowLevel );
	}
}


void ObjectInstance::SetNumCollapses ( int iNum )
{
	iCurCollapses = iNum;
}

int ObjectInstance::GetNumCollapses ( void )
{
	return iCurCollapses;
}


// Call before D3D leaves.
void ObjectInstance::AboutToChangeDevice ( void )
{
	// Not actually much to do.
	ASSERT ( pObj != NULL );
	pObj->AboutToChangeDevice();

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





#ifdef DEBUG

// Set this to 1 if you want to do extra debugging on the OptimisedMesh stuff.
// But it will change where things like index buffers go, and so potentially
// hide other bugs.
// It's also very slow, because it does a lot of checking.
#define EXTRA_DEBUGGING 0

#else
// Not a debug build - no extras.
#define EXTRA_DEBUGGING 0
#endif


OptimisedMesh::OptimisedMesh ( void )
{
	iVersion = 1234;
	bDirty = TRUE;
	bWillGetInfo = FALSE;
}

OptimisedMesh::~OptimisedMesh() {}


// No real need to override this - override Update() instead.
// Tell this method that the underlying mesh has changed.
// bWillGetInfo = TRUE if you are going to call any of the Info* functions.
// This causes a speed hit, so only do it when necessary.
void OptimisedMesh::MarkAsDirty ( BOOL bNewWillGetInfo )
{
	iVersion++;
	bDirty = TRUE;
	bWillGetInfo = bNewWillGetInfo;
}



OptimisedMeshInstance::OptimisedMeshInstance ( void )
{
	iVersion = 1233;		// One less than the initialiser of OptimisedMesh
}

OptimisedMeshInstance::~OptimisedMeshInstance() {}







///////// VANILLA VIPM ////////////




// Trimmed-down, lean'n'mean vanilla collapse record.
// bNumChanges = -1 means the end of the list (dummy last action).
// bPrevNumChanges = -1 means the start of the list (no dummy first).
// Note! This structure changes length! :-)
struct VanillaCollapseRecord
{
	WORD	wKeptVert;			// The offset of the vertex that doesn't vanish/appear
	BYTE	bNumOfTris;			// Number of tris removed/added.
	BYTE	bNumChanges;		// How many entries in wIndexOffset[].
	BYTE	bPrevNumChanges;	// How many entries in wIndexOffset[] in the previous action.
	// Packing to get correct WORD alignment.
	BYTE	bPadding[1];

	// This will be of actual length bNumChanges,
	// then immeditaely after in memory will be another record.
	WORD	wIndexOffset[];		// The offsets of the indices to change.


	// And some helpful list-scanners. These will return NULL if at the start/end of the list.

	VanillaCollapseRecord *Prev ( void )
	{
		VanillaCollapseRecord *pRecord = this;
		if ( pRecord->bPrevNumChanges == (BYTE)-1 )
		{
			// Start of the list.
			return ( NULL );
		}

		int iPrevNumChanges = (int)( pRecord->bPrevNumChanges );
		// Skip over the previous change list.
		pRecord = (VanillaCollapseRecord *)((WORD *)pRecord - iPrevNumChanges );
		// Skip over the previous record body.
		pRecord--;

		// A quick check - these need to agree up and down the list.
		ASSERT ( iPrevNumChanges == (int)( pRecord->bNumChanges ) );

		return ( pRecord );
	}

	VanillaCollapseRecord *Next ( void )
	{
		VanillaCollapseRecord *pRecord = this;
		if ( pRecord->bNumChanges == (BYTE)-1 )
		{
			// End of the list.
			return ( NULL );
		}

		int iNumChanges = (int)( pRecord->bNumChanges );
		// Skip over the record body.
		pRecord++;
		// Skip over the change list.
		pRecord = (VanillaCollapseRecord *)((WORD *)pRecord + iNumChanges );

		// A quick check - these need to agree up and down the list.
		ASSERT ( iNumChanges == (int)( pRecord->bPrevNumChanges ) );

		return ( pRecord );
	}

};




// Now the different classes that inherit off OptimisedMesh
class OMVanilla : public OptimisedMesh
{
	friend class OMIVanilla;

	Object *pObj;

	int							iNumVerts;			// Number of verts at full rez.
	int							iNumCollapses;		// Total number of collapses.
	ArbitraryList<WORD>			wIndices;			// The initial index list. Always using TRILISTs.
	ArbitraryList<BYTE>			pbCollapseRecords;	// The memory that will store the VanillaCollapseRecords.
	// VCRs are stored in a list, last first, with a dummy last entry.
	// The current pointer will point to the collapse that has already happened.
	// So if the mesh is completely uncollapsed, the pointer will point to the dummy last
	// item, and if the mesh is completely collapses, the pointer will point to the first in the list.
	VanillaCollapseRecord		*pVCRLast;			// Last collapse record (which is the first collapse done).

	LPDIRECT3DVERTEXBUFFER8		pVB;				// The VB with the vertices in.

public:
	OMVanilla ( Object *pObject );
	virtual ~OMVanilla ( void );
	virtual VIPMTypeEnum GetType ( void );
	virtual char *GetTypeName ( void );
	virtual OptimisedMeshInstance *CreateInstance ( ObjectInstance *pObjectInstance );
	virtual void Check ( void );
	virtual void Update ( void );
	virtual void AboutToChangeDevice ( void );
};


class OMIVanilla : public OptimisedMeshInstance
{
	friend class OMVanilla;

	ObjectInstance *pObjInst;
	OMVanilla *pOptMesh;


	LPDIRECT3DINDEXBUFFER8		pIndexBuffer;		// The current index list.
	VanillaCollapseRecord		*pVCRCur;			// Current collapse record.
	int							iCurNumVerts;		// Current number of verts.
	int							iCurNumTris;		// Current number of tris.
	int							iCurNumCollapses;	// Current number of collapses done.


public:

	OMIVanilla ( ObjectInstance *pObjectInstance, OMVanilla *pOptimisedMesh );
	virtual ~OMIVanilla ( void );
	virtual VIPMTypeEnum GetType ( void );
	virtual char *GetTypeName ( void );
	virtual void RenderCurrentObject ( LPDIRECT3DDEVICE8 pd3ddev, int iMaterialNumber, int iLoD );
	virtual BOOL bNeedsUpdate ( void );
	virtual void Update ( void );
	virtual void Check ( void );
	virtual void AboutToChangeDevice ( void );
	virtual const void InfoGetGlobal ( DWORD *pdwMemoryUsed, DWORD *pdwOfWhichAGP );
	virtual const void InfoGetInstance ( DWORD *pdwMemoryUsed, DWORD *pdwOfWhichAGP, DWORD *pdwVerticesLoaded, DWORD *pdwRealTrisDrawn, DWORD *pdwTotalVertices );


	// Return TRUE if a collapse was actually done.
	BOOL DoCollapse ( int iNumCollapses = 1 );
	BOOL UndoCollapse ( int iNumCollapses = 1 );
};




OMVanilla::OMVanilla ( Object *pObject )
{
	pObj = pObject;
	pVB = NULL;
}

OMVanilla::~OMVanilla ( void )
{
	pObj = NULL;
	ASSERT ( pVB == NULL );
}

VIPMTypeEnum OMVanilla::GetType ( void )
{
	return VIPMType_Vanilla;
}

char *OMVanilla::GetTypeName ( void )
{
	return "Vanilla";
}

void OMVanilla::AboutToChangeDevice ( void )
{
	HRESULT hres = g_pd3dDevice->SetStreamSource ( 0, NULL, 0 );
	ASSERT ( SUCCEEDED ( hres ) );
	SAFE_RELEASE ( pVB );

	MarkAsDirty ( g_bShowVIPMInfo );
}


// Create an instance of this optimised mesh, and returns the pointer to it.
// Pass in the object instance you wish to associate it with.
OptimisedMeshInstance *OMVanilla::CreateInstance ( ObjectInstance *pObjectInstance )
{
	return new OMIVanilla ( pObjectInstance, this );
}


void OMVanilla::Check ( void )
{
}


void OMVanilla::Update ( void )
{
	if ( !bDirty )
	{
		// Nothing to do!
		return;
	}

	bDirty = FALSE;
	iVersion++;			// Just for luck.



	SAFE_RELEASE ( pVB );
	wIndices.SizeTo ( 0 );
	pbCollapseRecords.SizeTo ( 0 );


	MeshPt *pt;
	MeshTri *tri;


	// Undo all the collapses, so we start from the maximum mesh.
	while ( pObj->UndoCollapse() ) {}


	// How many vertices are we looking at?
	iNumVerts = 0;
	for ( pt = pObj->CurPtRoot.ListNext(); pt != NULL; pt = pt->ListNext() )
	{
		pt->mypt.dwIndex = -1;
		iNumVerts++;
	}
	// Er... word indices, guys... nothing supports 32-bit indices yet.
	ASSERT ( iNumVerts < 65535 );


	// How many tris are we looking at?
	int iNumTris = 0;
	for ( tri = pObj->CurTriRoot.ListNext(); tri != NULL; tri = tri->ListNext() )
	{
		tri->mytri.dwIndex = -1;
		iNumTris++;
	}
	// A lot of cards have this annoying limit - see D3DCAPS8.MaxPrimitiveCount, which is
	// exactly 65535 for DX7 and previous devices. So might as well stick with that number.
	ASSERT ( iNumTris < 65535 );



	HRESULT hres = g_pd3dDevice->CreateVertexBuffer ( iNumVerts * sizeof ( STDVERTEX ),
										D3DUSAGE_WRITEONLY,
										STDVERTEX_FVF,
										D3DPOOL_DEFAULT,
										&pVB );
	ASSERT ( SUCCEEDED ( hres ) );

	STDVERTEX *pVertices, *pCurVertex;
	hres = pVB->Lock ( 0, 0, (BYTE **)(&pVertices), 0 );
	ASSERT ( SUCCEEDED ( hres ) );

	pCurVertex = pVertices;






	// Now do all the collapses, so we start from the minimum mesh.
	// Along the way, mark the vertices in reverse order.
	int iCurVerts = iNumVerts;
	while ( TRUE )
	{
		GeneralCollapseInfo *pCollapse = pObj->pNextCollapse;
		if ( pObj->pNextCollapse == &(pObj->CollapseRoot) )
		{
			break;
		}

		iCurVerts--;
		pCollapse->pptBin->mypt.dwIndex = iCurVerts;

		pObj->DoCollapse();
	}

	// Add the remaining existing pts and tris in any old order - vertex coherency is not this
	// method's strong point anyway.
	WORD wCurIndex = 0;
	for ( pt = pObj->CurPtRoot.ListNext(); pt != NULL; pt = pt->ListNext() )
	{
		if ( pt->mypt.dwIndex == (DWORD)-1 )
		{
			// Not binned in a collapse.
			pt->mypt.dwIndex = wCurIndex;
			pCurVertex->v = pt->mypt.vPos;
			pCurVertex->norm = pt->mypt.vNorm;
			pCurVertex->tu = pt->mypt.fU;
			pCurVertex->tv = pt->mypt.fV;

			pCurVertex++;

⌨️ 快捷键说明

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