📄 object.cpp
字号:
/* 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 + -