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