📄 object.cpp
字号:
wCurIndex++;
}
}
// Should meet in the middle!
ASSERT ( wCurIndex == iCurVerts );
WORD wCurTri = 0;
for ( tri = pObj->CurTriRoot.ListNext(); tri != NULL; tri = tri->ListNext() )
{
tri->mytri.dwIndex = wCurTri;
// Add the three indices.
ASSERT ( tri->pPt1->mypt.dwIndex != (DWORD)-1 );
ASSERT ( tri->pPt2->mypt.dwIndex != (DWORD)-1 );
ASSERT ( tri->pPt3->mypt.dwIndex != (DWORD)-1 );
*(wIndices.AddItem()) = (WORD)tri->pPt1->mypt.dwIndex;
*(wIndices.AddItem()) = (WORD)tri->pPt2->mypt.dwIndex;
*(wIndices.AddItem()) = (WORD)tri->pPt3->mypt.dwIndex;
wCurTri++;
}
// And undo all the collapses in turn, adding vertices,
// tris, and VanillaCollapseRecords as we go.
int iPrevNumChanges = -1;
int iVCRecordSize = 0;
iNumCollapses = 0;
while ( pObj->pNextCollapse->ListNext() != NULL )
{
iNumCollapses++;
GeneralCollapseInfo *pCollapse = pObj->pNextCollapse->ListNext();
// Create a collapse item.
int iNumChanges = pCollapse->TriCollapsed.Size();
int iSizeCollapseRecords = pbCollapseRecords.Size();
pbCollapseRecords.SizeTo ( iSizeCollapseRecords + sizeof ( VanillaCollapseRecord ) + sizeof(WORD) * iNumChanges );
// No no no, records were made from plain poly-vinyl, not poly-vinyl chloride.
// You're thinking of kinky boots. Actually, that was a record, wasn't it? Hmmm.. maybe you're right then.
// Honor Blackman - oh yes. Patrick MacNee - no thanks.
VanillaCollapseRecord *pvcRecord = (VanillaCollapseRecord *)pbCollapseRecords.Item ( iSizeCollapseRecords );
pvcRecord->bNumChanges = iNumChanges;
pvcRecord->bNumOfTris = pCollapse->TriOriginal.Size() - pCollapse->TriCollapsed.Size();
ASSERT ( pCollapse->pptKeep->mypt.dwIndex != (DWORD)-1 );
pvcRecord->wKeptVert = pCollapse->pptKeep->mypt.dwIndex;
pvcRecord->bPrevNumChanges = iPrevNumChanges;
iPrevNumChanges = iNumChanges;
DWORD *pdwTriIndices = new DWORD [pCollapse->TriCollapsed.Size()];
// These tris will be remapped.
for ( int i = 0; i < pCollapse->TriCollapsed.Size(); i++ )
{
GeneralTriInfo *pTriInfo = pCollapse->TriCollapsed.Item(i);
MeshTri *pTri = pTriInfo->ppt[0]->FindTri ( pTriInfo->ppt[1], pTriInfo->ppt[2] );
ASSERT ( pTri != NULL );
// Find which one will change.
// Unfortunately, the order of pPt1, pPt2, pPt3 has nothing to
// do with the order it is in the index list. So we need to check with
// the index list to see which index needs changing.
WORD *pwTriIndices = wIndices.Item ( pTri->mytri.dwIndex * 3 );
int iOffset;
if ( pwTriIndices[0] == pCollapse->pptKeep->mypt.dwIndex )
{
iOffset = 0;
}
else if ( pwTriIndices[1] == pCollapse->pptKeep->mypt.dwIndex )
{
iOffset = 1;
}
else
{
ASSERT ( pwTriIndices[2] == pCollapse->pptKeep->mypt.dwIndex );
iOffset = 2;
}
pvcRecord->wIndexOffset[i] = ( 3 * pTri->mytri.dwIndex ) + iOffset;
// And actually undo the collapse.
ASSERT ( *(wIndices.Item(pvcRecord->wIndexOffset[i])) == (WORD)pCollapse->pptKeep->mypt.dwIndex );
*(wIndices.Item(pvcRecord->wIndexOffset[i])) = wCurIndex;
pdwTriIndices[i] = pTri->mytri.dwIndex;
}
// Do the uncollapse.
pObj->UndoCollapse();
// Add the vertex.
MeshPt *pPt = pCollapse->pptBin;
ASSERT ( pPt->mypt.dwIndex == wCurIndex );
pCurVertex->v = pPt->mypt.vPos;
pCurVertex->norm = pPt->mypt.vNorm;
pCurVertex->tu = pPt->mypt.fU;
pCurVertex->tv = pPt->mypt.fV;
pCurVertex++;
wCurIndex++;
// Now find which tris were remapped and which are new.
int iNewTriNum = 0;
for ( i = 0; i < pCollapse->TriOriginal.Size(); i++ )
{
GeneralTriInfo *pTriInfo = pCollapse->TriOriginal.Item(i);
MeshTri *pTri = pTriInfo->ppt[0]->FindTri ( pTriInfo->ppt[1], pTriInfo->ppt[2] );
// Because we store these in a specific way, this is a lot easier.
ASSERT ( pTriInfo->ppt[0] == pCollapse->pptBin );
if ( i < pCollapse->TriCollapsed.Size() )
{
// This should be a remapped tri, and correspond to the one in the Collapsed list.
ASSERT ( ( pTriInfo->ppt[1] != pCollapse->pptKeep ) && ( pTriInfo->ppt[2] != pCollapse->pptKeep ) );
ASSERT ( pCollapse->pptKeep == pCollapse->TriCollapsed.Item(i)->ppt[0] );
ASSERT ( pTriInfo->ppt[1] == pCollapse->TriCollapsed.Item(i)->ppt[1] );
ASSERT ( pTriInfo->ppt[2] == pCollapse->TriCollapsed.Item(i)->ppt[2] );
// We don't do anything exiting with these,
// except remember what index the tri was when it was originally created.
pTri->mytri.dwIndex = pdwTriIndices[i];
}
else
{
// This will be binned.
ASSERT ( ( pTriInfo->ppt[1] == pCollapse->pptKeep ) || ( pTriInfo->ppt[2] == pCollapse->pptKeep ) );
// And add this tri to the end of the index list.
pTri->mytri.dwIndex = wCurTri;
// Add the three indices.
ASSERT ( pTri->pPt1->mypt.dwIndex != (DWORD)-1 );
ASSERT ( pTri->pPt2->mypt.dwIndex != (DWORD)-1 );
ASSERT ( pTri->pPt3->mypt.dwIndex != (DWORD)-1 );
*(wIndices.AddItem()) = (WORD)pTri->pPt1->mypt.dwIndex;
*(wIndices.AddItem()) = (WORD)pTri->pPt2->mypt.dwIndex;
*(wIndices.AddItem()) = (WORD)pTri->pPt3->mypt.dwIndex;
wCurTri++;
iNewTriNum++;
}
}
ASSERT ( iNewTriNum == pvcRecord->bNumOfTris );
delete []pdwTriIndices;
}
// Dummy last (well, OK - first) collapse.
int iSizeCollapseRecords = pbCollapseRecords.Size();
pbCollapseRecords.SizeTo ( iSizeCollapseRecords + sizeof ( VanillaCollapseRecord ) );
VanillaCollapseRecord *pvcRecord = (VanillaCollapseRecord *)pbCollapseRecords.Item ( iSizeCollapseRecords );
pvcRecord->bNumChanges = -1;
pvcRecord->bNumOfTris = 0;
pvcRecord->wKeptVert = -1;
pvcRecord->bPrevNumChanges = iPrevNumChanges;
pVCRLast = pvcRecord;
hres = pVB->Unlock();
ASSERT ( SUCCEEDED ( hres ) );
}
OMIVanilla::OMIVanilla ( ObjectInstance *pObjectInstance, OMVanilla *pOptimisedMesh )
{
pObjInst = pObjectInstance;
pOptMesh = pOptimisedMesh;
pIndexBuffer = NULL;
pVCRCur = NULL;
iCurNumTris = 0;
iCurNumVerts = 0;
iCurNumCollapses = 0;
}
OMIVanilla::~OMIVanilla ( void )
{
pObjInst = NULL;
pOptMesh = NULL;
ASSERT ( pIndexBuffer == NULL );
}
void OMIVanilla::AboutToChangeDevice ( void )
{
ASSERT ( pOptMesh != NULL );
pOptMesh->AboutToChangeDevice();
HRESULT hres = g_pd3dDevice->SetIndices ( NULL, 0 );
ASSERT ( SUCCEEDED ( hres ) );
SAFE_RELEASE ( pIndexBuffer );
}
const void OMIVanilla::InfoGetGlobal ( DWORD *pdwMemoryUsed, DWORD *pdwOfWhichAGP )
{
ASSERT ( pOptMesh != NULL );
ASSERT ( pOptMesh->bWillGetInfo );
DWORD dwMemoryUsed = 0;
DWORD dwOfWhichAGP = 0;
// The thing itself.
dwMemoryUsed += sizeof ( OMVanilla );
// Master index list.
dwMemoryUsed += pOptMesh->wIndices.Size() * sizeof ( WORD );
// Collapse list.
dwMemoryUsed += pOptMesh->pbCollapseRecords.Size() * sizeof ( BYTE );
// And the size of the VB.
dwOfWhichAGP += pOptMesh->iNumVerts * sizeof ( STDVERTEX );
// Add the AGP memory in.
dwMemoryUsed += dwOfWhichAGP;
if ( pdwMemoryUsed != NULL )
{
*pdwMemoryUsed = dwMemoryUsed;
}
if ( pdwOfWhichAGP != NULL )
{
*pdwOfWhichAGP = dwOfWhichAGP;
}
}
const void OMIVanilla::InfoGetInstance ( DWORD *pdwMemoryUsed, DWORD *pdwOfWhichAGP, DWORD *pdwVerticesLoaded, DWORD *pdwRealTrisDrawn, DWORD *pdwTotalVertices )
{
ASSERT ( pOptMesh != NULL );
ASSERT ( pOptMesh->bWillGetInfo );
DWORD dwMemoryUsed = 0;
DWORD dwOfWhichAGP = 0;
// The thing itself.
dwMemoryUsed += sizeof ( OMIVanilla );
// The copied index list.
// Note! This could be better - we could only grow the index buffer
// to the size we actually need for this instance.
// Most of the objects will be far smaller than this.
// For speed, you'd need to use pools of IBs of the right power-of-two size,
// to avoid constantly creating and destroying IBs. Which sounds like a lot of boring coding
// for the sake of a few slightly more accurate numbers (but still larger than
// anything else per-instance).
// So I haven't.
dwOfWhichAGP += pOptMesh->wIndices.Size() * sizeof ( WORD );
// Add the AGP memory in.
dwMemoryUsed += dwOfWhichAGP;
if ( pdwMemoryUsed != NULL )
{
*pdwMemoryUsed = dwMemoryUsed;
}
if ( pdwOfWhichAGP != NULL )
{
*pdwOfWhichAGP = dwOfWhichAGP;
}
if ( pdwVerticesLoaded != NULL )
{
// Find the vertex-cache info for the current render.
WORD *pwIndices;
HRESULT hres = pIndexBuffer->Lock ( 0,
pOptMesh->wIndices.Size() * sizeof ( WORD ),
(BYTE**)&pwIndices,
D3DLOCK_READONLY );
ASSERT ( SUCCEEDED ( hres ) );
float fVertexScore = GetNumVerticesLoadedTriList ( pwIndices, iCurNumTris );
*pdwVerticesLoaded = (DWORD)(fVertexScore + 0.4999f);
hres = pIndexBuffer->Unlock();
ASSERT ( SUCCEEDED ( hres ) );
}
if ( pdwRealTrisDrawn != NULL )
{
// We don't get degenerate tris in Vanilla.
*pdwRealTrisDrawn = iCurNumTris;
}
if ( pdwTotalVertices != NULL )
{
*pdwTotalVertices = iCurNumVerts;
}
}
VIPMTypeEnum OMIVanilla::GetType ( void )
{
return VIPMType_Vanilla;
}
char *OMIVanilla::GetTypeName ( void )
{
return "Vanilla";
}
// Renders the given material of the object with the given level of detail.
void OMIVanilla::RenderCurrentObject ( LPDIRECT3DDEVICE8 pd3ddev, int iMaterialNumber, int iLoD )
{
// Do an update if necessary.
if ( bNeedsUpdate() )
{
Update();
}
if ( iLoD > iCurNumCollapses )
{
DoCollapse ( iLoD - iCurNumCollapses );
}
else if ( iLoD < iCurNumCollapses )
{
UndoCollapse ( iCurNumCollapses - iLoD );
}
// And draw the object.
HRESULT hres;
hres = pd3ddev->SetVertexShader ( STDVERTEX_FVF );
ASSERT ( SUCCEEDED ( hres ) );
ASSERT ( pIndexBuffer != NULL );
hres = pd3ddev->SetIndices ( pIndexBuffer, 0 );
ASSERT ( SUCCEEDED ( hres ) );
ASSERT ( pOptMesh->pVB != NULL );
hres = pd3ddev->SetStreamSource ( 0, pOptMesh->pVB, sizeof ( STDVERTEX ) );
ASSERT ( SUCCEEDED ( hres ) );
if ( g_iMaxNumTrisDrawn > 0 )
{
// Limit the number of tris.
int iNumTris = g_iMaxNumTrisDrawn;
if ( iCurNumTris < iNumTris )
{
iNumTris = iCurNumTris;
}
hres = pd3ddev->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, 0, iCurNumVerts, 0, iNumTris );
ASSERT ( SUCCEEDED ( hres ) );
}
else
{
hres = pd3ddev->DrawIndexedPrimitive ( D3DPT_TRIANGLELIST, 0, iCurNumVerts, 0, iCurNumTris );
ASSERT ( SUCCEEDED ( hres ) );
}
g_iNumOfObjectTrisDrawn += iCurNumTris;
g_iNumOfObjectVertsDrawn += iCurNumVerts;
}
BOOL OMIVanilla::bNeedsUpdate ( void )
{
ASSERT ( pOptMesh != NULL );
return ( iVersion != pOptMesh->iVersion );
}
void OMIVanilla::Update ( void )
{
ASSERT ( pOptMesh != NULL );
pOptMesh->Update();
if ( bNeedsUpdate() )
{
DWORD dwFlags = D3DUSAGE_DYNAMIC;
#if !EXTRA_DEBUGGING
// If doing extra debugging, we're always going to do reads from the IB.
if ( !pOptMesh->bWillGetInfo )
{
// We don't need to do reads from the IB to get vertex-cache info.
dwFlags |= D3DUSAGE_WRITEONLY;
}
#endif
// Copy the base index list.
SAFE_RELEASE ( pIndexBuffer );
HRESULT hres = g_pd3dDevice->CreateIndexBuffer (
pOptMesh->wIndices.Size() * sizeof ( WORD ),
dwFlags,
D3DFMT_INDEX16,
D3DPOOL_DEFAULT,
&pIndexBuffer );
ASSERT ( SUCCEEDED ( hres ) );
// And fill.
WORD *pwIndices;
hres = pIndexBuffer->Lock ( 0,
pOptMesh->wIndices.Size() * sizeof ( WORD ),
(BYTE**)&pwIndices,
D3DLOCK_DISCARD );
ASSERT ( SUCCEEDED ( hres ) );
memcpy ( pwIndices, pOptMesh->wIndices.Ptr(), pOptMesh->wIndices.Size() * sizeof ( WORD ) );
hres = pIndexBuffer->Unlock();
ASSERT ( SUCCEEDED ( hres ) );
// Point to the last collapse record.
pVCRCur = pOptMesh->pVCRLast;
iCurNumVerts = pOptMesh->iNumVerts;
ASSERT ( ( pOptMesh->wIndices.Size() % 3 ) == 0 );
iCurNumTris = pOptMesh->wIndices.Size() / 3;
iCurNumCollapses = 0;
iVersion = pOptMesh->iVersion;
}
Check();
}
BOOL OMIVanilla::DoCollapse ( int iNum )
{
if ( pVCRCur->bPrevNumChanges == (BYTE)-1 )
{
// No more to do.
return FALSE;
}
else
{
ASSERT ( pIndexBuffer != NULL );
WORD *pwIndices;
HRESULT hres = pIndexBuffer->Lock ( 0,
iCurNumTris * 3 * sizeof ( WORD ),
(BYTE**)&pwIndices,
0 );
ASSERT ( SUCCEEDED ( hres ) );
while ( --iNum >= 0 )
{
if ( pVCRCur->bPrevNumChanges == (BYTE)-1 )
{
// No more to do.
break;
}
iCurNumCollapses++;
pVCRCur = pVCRCur->Prev();
iCurNumVerts--;
ASSERT ( iCurNumVerts >= 0 );
iCurNumTris -= pVCRCur->bNumOfTris;
ASSERT ( iCurNumTris >= 0 );
for ( int i = 0; i < pVCRCur->bNumChanges; i++ )
{
// Change all the instances of the vertex that's just been binned to the one that has been kept.
ASSERT ( pVCRCur->wIndexOffset[i] < ( iCurNumTris * 3 ) );
#if EXTRA_DEBUGGING
ASSERT ( pwIndices[pVCRCur->wIndexOffset[i]] == (WORD)iCurNumVerts );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -