📄 object.cpp
字号:
ptri->pPt3->mypt.pTempPt,
&CurTriRoot );
pNewTri->mytri = ptri->mytri;
iNumTris++;
}
ASSERT ( iNumTris == iFullNumTris );
iNumCollapses = 0;
iCurSlidingWindowLevel = 0;
SetNewLevel ( iCurSlidingWindowLevel );
}
// Renders the given material of the current state of the object.
// Set iSlidingWindowLevel to -1 if you don't care about level numbers.
void Object::RenderCurrentObject ( LPDIRECT3DDEVICE8 pd3ddev, int iMaterialNumber, int iSlidingWindowLevel )
{
STDVERTEX vert[3];
HRESULT hres;
hres = pd3ddev->SetVertexShader ( STDVERTEX_FVF );
MeshTri *tri = CurTriRoot.ListNext();
while ( tri != NULL )
{
if ( tri->mytri.iMaterialNumber == iMaterialNumber )
{
if ( ( iSlidingWindowLevel == -1 ) ||
( iSlidingWindowLevel == tri->mytri.iSlidingWindowLevel ) )
{
// Draw this one.
vert[0].v = tri->pPt1->mypt.vPos;
vert[0].norm = tri->pPt1->mypt.vNorm;
vert[0].tu = tri->pPt1->mypt.fU;
vert[0].tv = tri->pPt1->mypt.fV;
vert[1].v = tri->pPt2->mypt.vPos;
vert[1].norm = tri->pPt2->mypt.vNorm;
vert[1].tu = tri->pPt2->mypt.fU;
vert[1].tv = tri->pPt2->mypt.fV;
vert[2].v = tri->pPt3->mypt.vPos;
vert[2].norm = tri->pPt3->mypt.vNorm;
vert[2].tu = tri->pPt3->mypt.fU;
vert[2].tv = tri->pPt3->mypt.fV;
hres = pd3ddev->DrawPrimitiveUP ( D3DPT_TRIANGLELIST, 1, vert, sizeof(vert[0]) );
}
}
tri = tri->ListNext();
}
}
void Object::RenderCurrentEdges ( LPDIRECT3DDEVICE8 pd3ddev, int iMaterialNumber, BOOL bIgnoreBackFaced )
{
STDVERTEX vert[2];
HRESULT hres;
hres = pd3ddev->SetVertexShader ( STDVERTEX_FVF );
MeshEdge *edge = CurEdgeRoot.ListNext();
while ( edge != NULL )
{
if ( edge->myedge.iMaterialNumber == iMaterialNumber )
{
if ( edge->myedge.bFrontFaced || !bIgnoreBackFaced )
{
// Draw this one.
vert[0].v = edge->pPt1->mypt.vPos;
vert[0].norm = edge->pPt1->mypt.vNorm;
vert[0].tu = edge->pPt1->mypt.fU;
vert[0].tv = edge->pPt1->mypt.fV;
vert[1].v = edge->pPt2->mypt.vPos;
vert[1].norm = edge->pPt2->mypt.vNorm;
vert[1].tu = edge->pPt2->mypt.fU;
vert[1].tv = edge->pPt2->mypt.fV;
hres = pd3ddev->DrawPrimitiveUP ( D3DPT_LINELIST, 1, vert, sizeof(vert[0]) );
}
else
{
bIgnoreBackFaced = bIgnoreBackFaced;
}
}
edge = edge->ListNext();
}
}
// Creates and performs a collapse of pptBinned to pptKept.
// Make sure they actually share an edge!
// Make sure the object is fully collapsed already.
void Object::CreateEdgeCollapse ( MeshPt *pptBinned, MeshPt *pptKept )
{
MarkAsDirty();
CheckObject();
// The thing had better be fully collapsed.
ASSERT ( pNextCollapse == &CollapseRoot );
MeshEdge *pedge = pptBinned->FindEdge ( pptKept );
ASSERT ( pedge != NULL );
GeneralCollapseInfo *pGCI = new GeneralCollapseInfo ( &CollapseRoot );
pGCI->fError = FindCollapseError ( pptBinned, pptKept->FindEdge ( pptBinned ) );
// Because deleting a tri breaks the FirstTri, NextTri sequence,
// we need to find the tris & just store their pointers.
// Then we delete them.
pGCI->pptBin = pptBinned;
pGCI->pptKeep = pptKept;
const int c_iMaxNumTris = 100; // Grow as needed.
MeshTri *pBinnedTris[c_iMaxNumTris];
MeshTri *ptri;
int iNumTrisCollapsed = 0;
BOOL bNeedNewLevel = FALSE;
for ( ptri = pptBinned->FirstTri(); ptri != NULL; ptri = pptBinned->NextTri() )
{
ASSERT ( iNumTrisCollapsed < c_iMaxNumTris ); // Grow c_iMaxNumTris as needed.
pBinnedTris[iNumTrisCollapsed++] = ptri;
if ( ptri->mytri.iSlidingWindowLevel != iCurSlidingWindowLevel )
{
ASSERT ( ptri->mytri.iSlidingWindowLevel == iCurSlidingWindowLevel + 1 );
// Need to set a new level before doing this collapse.
bNeedNewLevel = TRUE;
}
}
if ( bNeedNewLevel )
{
// Store which tris were already on this level.
for ( MeshTri *pTri = CurTriRoot.ListNext(); pTri != NULL; pTri = pTri->ListNext() )
{
if ( pTri->mytri.iSlidingWindowLevel != iCurSlidingWindowLevel )
{
ASSERT ( pTri->mytri.iSlidingWindowLevel == iCurSlidingWindowLevel + 1 );
GeneralTriInfo *pTriInfoNew = pGCI->TriNextLevel.AddItem();
pTriInfoNew->ppt[0] = pTri->pPt1;
pTriInfoNew->ppt[1] = pTri->pPt2;
pTriInfoNew->ppt[2] = pTri->pPt3;
}
}
// And set the new level.
iCurSlidingWindowLevel++;
SetNewLevel ( iCurSlidingWindowLevel );
}
pGCI->iSlidingWindowLevel = iCurSlidingWindowLevel;
// Now bin them.
// Store the tris so that pptBinned is always ppt[0].
// This makes some of the optimised mesh versions simpler to code.
// Also, make two passes and store the changed tris first, then the
// binned ones. Again, this makes life easier later on.
// So all the tris in TriCollapsed should correspond with the
// same-numbered item in TriOriginal.
int i;
for ( i = iNumTrisCollapsed - 1; i >= 0; i-- )
{
MeshPt *ppt[3];
ppt[0] = pBinnedTris[i]->pPt1;
ppt[1] = pBinnedTris[i]->pPt2;
ppt[2] = pBinnedTris[i]->pPt3;
while ( ppt[0] != pptBinned )
{
MeshPt *pptTemp = ppt[0];
ppt[0] = ppt[1];
ppt[1] = ppt[2];
ppt[2] = pptTemp;
}
ASSERT ( iCurSlidingWindowLevel == pBinnedTris[i]->mytri.iSlidingWindowLevel );
if ( ( ppt[0] == pptKept ) ||
( ppt[1] == pptKept ) ||
( ppt[2] == pptKept ) )
{
// This tri will be binned. Store it next time round.
}
else
{
GeneralTriInfo *pTriInfo = pGCI->TriOriginal.AddItem();
pTriInfo->ppt[0] = ppt[0];
pTriInfo->ppt[1] = ppt[1];
pTriInfo->ppt[2] = ppt[2];
pBinnedTris[i]->Delete ( TRUE );
pBinnedTris[i] = NULL;
}
}
// Do it again, adding the binned tris this time.
int iNumBinned = 0;
for ( i = iNumTrisCollapsed - 1; i >= 0; i-- )
{
if ( pBinnedTris[i] != NULL )
{
iNumBinned++;
MeshPt *ppt[3];
ppt[0] = pBinnedTris[i]->pPt1;
ppt[1] = pBinnedTris[i]->pPt2;
ppt[2] = pBinnedTris[i]->pPt3;
while ( ppt[0] != pptBinned )
{
MeshPt *pptTemp = ppt[0];
ppt[0] = ppt[1];
ppt[1] = ppt[2];
ppt[2] = pptTemp;
}
ASSERT ( iCurSlidingWindowLevel == pBinnedTris[i]->mytri.iSlidingWindowLevel );
ASSERT ( ( ppt[0] == pptKept ) || ( ppt[1] == pptKept ) || ( ppt[2] == pptKept ) );
GeneralTriInfo *pTriInfo = pGCI->TriOriginal.AddItem();
pTriInfo->ppt[0] = ppt[0];
pTriInfo->ppt[1] = ppt[1];
pTriInfo->ppt[2] = ppt[2];
pBinnedTris[i]->Delete ( TRUE );
pBinnedTris[i] = NULL;
}
}
// And add in the new tris.
for ( i = 0; i < iNumTrisCollapsed; i++ )
{
GeneralTriInfo *pTriInfo = pGCI->TriOriginal.Item ( i );
// ppt[0] should always be the binned pt.
ASSERT ( pTriInfo->ppt[0] == pptBinned );
// Now, are either of the other two the kept point?
// If so, these are tris that get binned, rather than remapped.
if ( ( pTriInfo->ppt[1] == pptKept ) ||
( pTriInfo->ppt[2] == pptKept ) )
{
// Binned tri - these should be the last few.
ASSERT ( i >= iNumTrisCollapsed - iNumBinned );
}
else
{
// A remapped tri.
ASSERT ( pGCI->TriCollapsed.Size() == i );
GeneralTriInfo *pTriInfoNew = pGCI->TriCollapsed.AddItem();
pTriInfoNew->ppt[0] = pptKept;
pTriInfoNew->ppt[1] = pTriInfo->ppt[1];
pTriInfoNew->ppt[2] = pTriInfo->ppt[2];
// And actually create this tri.
MeshTri *pTri = new MeshTri ( pTriInfoNew->ppt[0], pTriInfoNew->ppt[1], pTriInfoNew->ppt[2], &CurTriRoot, &CurEdgeRoot );
ASSERT ( pTri != NULL );
pTri->mytri.iMaterialNumber = pTriInfoNew->ppt[0]->mypt.iMaterialNumber;
pTri->pEdge12->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->pEdge23->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->pEdge31->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->mytri.iSlidingWindowLevel = iCurSlidingWindowLevel + 1;
}
}
pGCI->iNumTris = 0;
for ( MeshTri *pTri = CurTriRoot.ListNext(); pTri != NULL; pTri = pTri->ListNext() )
{
pGCI->iNumTris++;
}
iNumCollapses++;
}
// Bin the last collapse.
// Returns TRUE if these was a last collapse to do.
BOOL Object::BinEdgeCollapse ( void )
{
MarkAsDirty();
GeneralCollapseInfo *pGCI = CollapseRoot.ListNext();
if ( pGCI == NULL )
{
// No collapses to bin.
ASSERT ( iNumCollapses == 0 );
return FALSE;
}
else
{
iNumCollapses--;
if ( pNextCollapse == &CollapseRoot )
{
// Fully collapsed - uncollapse once.
UndoCollapse();
}
if ( pNextCollapse == pGCI )
{
// This is the next collapse to be done.
pNextCollapse = &CollapseRoot;
}
pGCI->ListDel();
delete pGCI;
return TRUE;
}
}
// Returns TRUE if a collapse was undone.
BOOL Object::UndoCollapse ( void )
{
bSomethingHappened = TRUE;
if ( pNextCollapse->ListNext() == NULL )
{
// No more to undo.
return FALSE;
}
else
{
pNextCollapse = pNextCollapse->ListNext();
ASSERT ( pNextCollapse->iSlidingWindowLevel == iCurSlidingWindowLevel );
int i;
for ( i = 0; i < pNextCollapse->TriCollapsed.Size(); i++ )
{
GeneralTriInfo *pTriInfo = pNextCollapse->TriCollapsed.Item(i);
MeshTri *pTri = pTriInfo->ppt[0]->FindTri ( pTriInfo->ppt[1], pTriInfo->ppt[2] );
ASSERT ( pTri != NULL );
pTri->Delete ( TRUE );
}
for ( i = 0; i < pNextCollapse->TriOriginal.Size(); i++ )
{
GeneralTriInfo *pTriInfo = pNextCollapse->TriOriginal.Item(i);
MeshTri *pTri = new MeshTri ( pTriInfo->ppt[0], pTriInfo->ppt[1], pTriInfo->ppt[2], &CurTriRoot, &CurEdgeRoot );
ASSERT ( pTri != NULL );
pTri->mytri.iMaterialNumber = pTriInfo->ppt[0]->mypt.iMaterialNumber;
pTri->pEdge12->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->pEdge23->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->pEdge31->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->mytri.iSlidingWindowLevel = iCurSlidingWindowLevel;
}
// Now see if the _previous_ collapse is on a different level.
if ( pNextCollapse->ListNext() != NULL )
{
if ( pNextCollapse->ListNext()->iSlidingWindowLevel != iCurSlidingWindowLevel )
{
// Need to go back a level.
ASSERT ( pNextCollapse->ListNext()->iSlidingWindowLevel == iCurSlidingWindowLevel - 1 );
iCurSlidingWindowLevel--;
SetNewLevel ( iCurSlidingWindowLevel );
// Except that some tris will already be at the lower level.
for ( int i = 0; i < pNextCollapse->TriNextLevel.Size(); i++ )
{
GeneralTriInfo *pTriInfo = pNextCollapse->TriNextLevel.Item(i);
MeshTri *pTri = pTriInfo->ppt[0]->FindTri ( pTriInfo->ppt[1], pTriInfo->ppt[2] );
ASSERT ( pTri != NULL );
pTri->mytri.iSlidingWindowLevel = iCurSlidingWindowLevel + 1;
}
}
}
return TRUE;
}
}
// Returns TRUE if a collapse was done.
BOOL Object::DoCollapse ( void )
{
bSomethingHappened = TRUE;
if ( pNextCollapse == &CollapseRoot )
{
// No more to do.
return FALSE;
}
else
{
if ( pNextCollapse->iSlidingWindowLevel != iCurSlidingWindowLevel )
{
// Need to start a new level.
ASSERT ( pNextCollapse->TriNextLevel.Size() > 0 );
ASSERT ( pNextCollapse->iSlidingWindowLevel == iCurSlidingWindowLevel + 1 );
iCurSlidingWindowLevel++;
SetNewLevel ( iCurSlidingWindowLevel );
}
else
{
// No new level to start.
ASSERT ( pNextCollapse->TriNextLevel.Size() == 0 );
}
int i;
for ( i = 0; i < pNextCollapse->TriOriginal.Size(); i++ )
{
GeneralTriInfo *pTriInfo = pNextCollapse->TriOriginal.Item(i);
MeshTri *pTri = pTriInfo->ppt[0]->FindTri ( pTriInfo->ppt[1], pTriInfo->ppt[2] );
ASSERT ( pTri != NULL );
ASSERT ( pTri->mytri.iSlidingWindowLevel == iCurSlidingWindowLevel );
pTri->Delete ( TRUE );
}
for ( i = 0; i < pNextCollapse->TriCollapsed.Size(); i++ )
{
GeneralTriInfo *pTriInfo = pNextCollapse->TriCollapsed.Item(i);
MeshTri *pTri = new MeshTri ( pTriInfo->ppt[0], pTriInfo->ppt[1], pTriInfo->ppt[2], &CurTriRoot, &CurEdgeRoot );
ASSERT ( pTri != NULL );
pTri->mytri.iMaterialNumber = pTriInfo->ppt[0]->mypt.iMaterialNumber;
pTri->pEdge12->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->pEdge23->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->pEdge31->myedge.iMaterialNumber = pTri->mytri.iMaterialNumber;
pTri->mytri.iSlidingWindowLevel = iCurSlidingWindowLevel + 1;
}
pNextCollapse = pNextCollapse->ListPrev();
return TRUE;
}
}
void Object::SetNewLevel ( int iLevel )
{
for ( MeshTri *pTri = CurTriRoot.ListNext(); pTri != NULL; pTri = pTri->ListNext() )
{
pTri->mytri.iSlidingWindowLevel = iLevel;
}
}
BOOL Object::CollapseAllowedForLevel ( MeshPt *pptBinned, int iLevel )
{
// All the tris that use the binned point must be at the current level.
BOOL bRes = TRUE;
for ( MeshTri *pTri = pptBinned->FirstTri(); pTri != NULL; pTri = pptBinned->NextTri() )
{
if ( iLevel != pTri->mytri.iSlidingWindowLevel )
{
bRes = FALSE;
}
}
return bRes;
}
// Return the error from this edge collapse.
// Set bTryToCacheResult=TRUE if you can pass pptBinned in multiple times.
// Make sure you call this with bTryToCacheResult=FALSE if any data changes,
// or you'll confuse the poor thing.
float Object::FindCollapseError ( MeshPt *pptBinned, MeshEdge *pedgeCollapse, BOOL bTryToCacheResult /*= FALSE*/ )
{
static MeshPt *pptLast;
static Quad qLast;
if ( pptBinned == NULL )
{
// You can call it like this to flush the cache.
pptLast = NULL;
return 0.0f;
}
MeshPt *pptKept = pedgeCollapse->OtherPt ( pptBinned );
ASSERT ( pptKept != NULL );
Quad qSum;
if ( bTryToCacheResult && ( pptLast == pptBinned ) )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -