123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948 |
- /******************************************************************************
- @File PVRTTriStrip.cpp
- @Title PVRTTriStrip
- @Version
- @Copyright Copyright (C) Imagination Technologies Limited.
- @Platform Independent
- @Description Strips a triangle list.
- ******************************************************************************/
- /****************************************************************************
- ** Includes
- ****************************************************************************/
- #include <stdlib.h>
- #include "PVRTGlobal.h"
- #include "PVRTContext.h"
- #include "PVRTTriStrip.h"
- /****************************************************************************
- ** Defines
- ****************************************************************************/
- #if !defined(__BADA__) // qsort is not supported by Bada
- #define RND_TRIS_ORDER
- #endif
- /****************************************************************************
- ** Structures
- ****************************************************************************/
- /****************************************************************************
- ** Class: CTri
- ****************************************************************************/
- class CTri;
- /*!***************************************************************************
- @Class CTriState
- @Description Stores a pointer to the triangles either side of itself,
- as well as it's winding.
- *****************************************************************************/
- class CTriState
- {
- public:
- CTri *pRev, *pFwd;
- bool bWindFwd;
- CTriState()
- {
- bWindFwd = true; // Initial value irrelevent
- pRev = NULL;
- pFwd = NULL;
- }
- };
- /*!***************************************************************************
- @Class CTri
- @Description Object used to store information about the triangle, such as
- the vertex indices it is made from, which triangles are
- adjacent to it, etc.
- *****************************************************************************/
- class CTri
- {
- public:
- CTriState sNew, sOld;
- CTri *pAdj[3];
- bool bInStrip;
- const unsigned int *pIdx; // three indices for the tri
- bool bOutput;
- public:
- CTri();
- int FindEdge(const unsigned int pw0, const unsigned int pw1) const;
- void Cement();
- void Undo();
- int EdgeFromAdjTri(const CTri &tri) const; // Find the index of the adjacent tri
- };
- /*!***************************************************************************
- @Class CStrip
- @Description Object used to store the triangles that a given strip is
- composed from.
- *****************************************************************************/
- class CStrip
- {
- protected:
- unsigned int m_nTriCnt;
- CTri *m_pTri;
- unsigned int m_nStrips;
- CTri **m_psStrip; // Working space for finding strips
- public:
- CStrip(
- const unsigned int * const pui32TriList,
- const unsigned int nTriCnt);
- ~CStrip();
- protected:
- bool StripGrow(
- CTri &triFrom,
- const unsigned int nEdgeFrom,
- const int nMaxChange);
- public:
- void StripFromEdges();
- void StripImprove();
- void Output(
- unsigned int **ppui32Strips,
- unsigned int **ppnStripLen,
- unsigned int *pnStripCnt);
- };
- /****************************************************************************
- ** Constants
- ****************************************************************************/
- /****************************************************************************
- ** Code: Class: CTri
- ****************************************************************************/
- CTri::CTri()
- {
- pAdj[0] = NULL;
- pAdj[1] = NULL;
- pAdj[2] = NULL;
- bInStrip = false;
- bOutput = false;
- }
- /*!***************************************************************************
- @Function FindEdge
- @Input pw0 The first index
- @Input pw1 The second index
- @Return The index of the edge
- @Description Finds the index of the edge that the current object shares
- with the two vertex index values that have been passed in
- (or returns -1 if they dont share an edge).
- *****************************************************************************/
- int CTri::FindEdge(const unsigned int pw0, const unsigned int pw1) const
- {
- if((pIdx[0] == pw0 && pIdx[1] == pw1))
- return 0;
- if((pIdx[1] == pw0 && pIdx[2] == pw1))
- return 1;
- if((pIdx[2] == pw0 && pIdx[0] == pw1))
- return 2;
- return -1;
- }
- /*!***************************************************************************
- @Function Cement
- @Description Assigns the new state as the old state.
- *****************************************************************************/
- void CTri::Cement()
- {
- sOld = sNew;
- }
- /*!***************************************************************************
- @Function Undo
- @Description Reverts the new state to the old state.
- *****************************************************************************/
- void CTri::Undo()
- {
- sNew = sOld;
- }
- /*!***************************************************************************
- @Function EdgeFromAdjTri
- @Input tri The triangle to compare
- @Return int Index of adjacent triangle (-1 if not adjacent)
- @Description If the input triangle is adjacent to the current triangle,
- it's index is returned.
- *****************************************************************************/
- int CTri::EdgeFromAdjTri(const CTri &tri) const
- {
- for(int i = 0; i < 3; ++i)
- {
- if(pAdj[i] == &tri)
- {
- return i;
- }
- }
- _ASSERT(false);
- return -1;
- }
- /****************************************************************************
- ** Local code
- ****************************************************************************/
- /*!***************************************************************************
- @Function OrphanTri
- @Input tri The triangle test
- @Return int Returns 1 if change was made
- @Description If the input triangle is not wound forward and is not the last
- triangle in the strip, the connection with the next triangle
- in the strip is removed.
- *****************************************************************************/
- static int OrphanTri(
- CTri * const pTri)
- {
- _ASSERT(!pTri->bInStrip);
- if(pTri->sNew.bWindFwd || !pTri->sNew.pFwd)
- return 0;
- pTri->sNew.pFwd->sNew.pRev = NULL;
- pTri->sNew.pFwd = NULL;
- return 1;
- }
- /*!***************************************************************************
- @Function TakeTri
- @Input pTri The triangle to take
- @Input pRevNew The triangle that is before pTri in the new strip
- @Return int Returns 1 if a new strip has been created
- @Description Removes the triangle from it's current strip
- and places it in a new one (following pRevNew in the new strip).
- *****************************************************************************/
- static int TakeTri(
- CTri * const pTri,
- CTri * const pRevNew,
- const bool bFwd)
- {
- int nRet;
- _ASSERT(!pTri->bInStrip);
- if(pTri->sNew.pFwd && pTri->sNew.pRev)
- {
- _ASSERT(pTri->sNew.pFwd->sNew.pRev == pTri);
- pTri->sNew.pFwd->sNew.pRev = NULL;
- _ASSERT(pTri->sNew.pRev->sNew.pFwd == pTri);
- pTri->sNew.pRev->sNew.pFwd = NULL;
- // If in the middle of a Strip, this will generate a new Strip
- nRet = 1;
- // The second tri in the strip may need to be orphaned, or it will have wrong winding order
- nRet += OrphanTri(pTri->sNew.pFwd);
- }
- else if(pTri->sNew.pFwd)
- {
- _ASSERT(pTri->sNew.pFwd->sNew.pRev == pTri);
- pTri->sNew.pFwd->sNew.pRev = NULL;
- // If at the beginning of a Strip, no change
- nRet = 0;
- // The second tri in the strip may need to be orphaned, or it will have wrong winding order
- nRet += OrphanTri(pTri->sNew.pFwd);
- }
- else if(pTri->sNew.pRev)
- {
- _ASSERT(pTri->sNew.pRev->sNew.pFwd == pTri);
- pTri->sNew.pRev->sNew.pFwd = NULL;
- // If at the end of a Strip, no change
- nRet = 0;
- }
- else
- {
- // Otherwise it's a lonesome triangle; one Strip removed!
- nRet = -1;
- }
- pTri->sNew.pFwd = NULL;
- pTri->sNew.pRev = pRevNew;
- pTri->bInStrip = true;
- pTri->sNew.bWindFwd = bFwd;
- if(pRevNew)
- {
- _ASSERT(!pRevNew->sNew.pFwd);
- pRevNew->sNew.pFwd = pTri;
- }
- return nRet;
- }
- /*!***************************************************************************
- @Function TryLinkEdge
- @Input src The source triangle
- @Input cmp The triangle to compare with
- @Input nSrcEdge The edge of souce triangle to compare
- @Input idx0 Vertex index 0 of the compare triangle
- @Input idx1 Vertex index 1 of the compare triangle
- @Description If the triangle to compare currently has no adjacent
- triangle along the specified edge, link the source triangle
- (along it's specified edge) with the compare triangle.
- *****************************************************************************/
- static bool TryLinkEdge(
- CTri &src,
- CTri &cmp,
- const int nSrcEdge,
- const unsigned int idx0,
- const unsigned int idx1)
- {
- int nCmpEdge;
- nCmpEdge = cmp.FindEdge(idx0, idx1);
- if(nCmpEdge != -1 && !cmp.pAdj[nCmpEdge])
- {
- cmp.pAdj[nCmpEdge] = &src;
- src.pAdj[nSrcEdge] = &cmp;
- return true;
- }
- return false;
- }
- /****************************************************************************
- ** Code: Class: CStrip
- ****************************************************************************/
- CStrip::CStrip(
- const unsigned int * const pui32TriList,
- const unsigned int nTriCnt)
- {
- unsigned int i, j;
- bool b0, b1, b2;
- m_nTriCnt = nTriCnt;
- /*
- Generate adjacency info
- */
- m_pTri = new CTri[nTriCnt];
- for(i = 0; i < nTriCnt; ++i)
- {
- // Set pointer to indices
- m_pTri[i].pIdx = &pui32TriList[3 * i];
- b0 = false;
- b1 = false;
- b2 = false;
- for(j = 0; j < i && !(b0 & b1 & b2); ++j)
- {
- if(!b0)
- b0 = TryLinkEdge(m_pTri[i], m_pTri[j], 0, m_pTri[i].pIdx[1], m_pTri[i].pIdx[0]);
- if(!b1)
- b1 = TryLinkEdge(m_pTri[i], m_pTri[j], 1, m_pTri[i].pIdx[2], m_pTri[i].pIdx[1]);
- if(!b2)
- b2 = TryLinkEdge(m_pTri[i], m_pTri[j], 2, m_pTri[i].pIdx[0], m_pTri[i].pIdx[2]);
- }
- }
- // Initially, every triangle is a strip.
- m_nStrips = m_nTriCnt;
- // Allocate working space for the strippers
- m_psStrip = new CTri*[m_nTriCnt];
- }
- CStrip::~CStrip()
- {
- delete [] m_pTri;
- delete [] m_psStrip;
- }
- /*!***************************************************************************
- @Function StripGrow
- @Input triFrom The triangle to begin from
- @Input nEdgeFrom The edge of the triangle to begin from
- @Input maxChange The maximum number of changes to be made
- @Description Takes triFrom as a starting point of triangles to add to
- the list and adds triangles sequentially by finding the next
- triangle that is adjacent to the current triangle.
- This is repeated until the maximum number of changes
- have been made.
- *****************************************************************************/
- bool CStrip::StripGrow(
- CTri &triFrom,
- const unsigned int nEdgeFrom,
- const int nMaxChange)
- {
- unsigned int i;
- bool bFwd;
- int nDiff, nDiffTot, nEdge;
- CTri *pTri, *pTriPrev, *pTmp;
- unsigned int nStripLen;
- // Start strip from this tri
- pTri = &triFrom;
- pTriPrev = NULL;
- nDiffTot = 0;
- nStripLen = 0;
- // Start strip from this edge
- nEdge = nEdgeFrom;
- bFwd = true;
- // Extend the strip until we run out, or we find an improvement
- nDiff = 1;
- while(nDiff > nMaxChange)
- {
- // Add pTri to the strip
- _ASSERT(pTri);
- nDiff += TakeTri(pTri, pTriPrev, bFwd);
- _ASSERT(nStripLen < m_nTriCnt);
- m_psStrip[nStripLen++] = pTri;
- // Jump to next tri
- pTriPrev = pTri;
- pTri = pTri->pAdj[nEdge];
- if(!pTri)
- break; // No more tris, gotta stop
- if(pTri->bInStrip)
- break; // No more tris, gotta stop
- // Find which edge we came over
- nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
- // Find the edge to leave over
- if(bFwd)
- {
- if(--nEdge < 0)
- nEdge = 2;
- }
- else
- {
- if(++nEdge > 2)
- nEdge = 0;
- }
- // Swap the winding order for the next tri
- bFwd = !bFwd;
- }
- _ASSERT(!pTriPrev->sNew.pFwd);
- /*
- Accept or reject this strip.
- Accepting changes which don't change the number of strips
- adds variety, which can help better strips to develop.
- */
- if(nDiff <= nMaxChange)
- {
- nDiffTot += nDiff;
- // Great, take the Strip
- for(i = 0; i < nStripLen; ++i)
- {
- pTri = m_psStrip[i];
- _ASSERT(pTri->bInStrip);
- // Cement affected tris
- pTmp = pTri->sOld.pFwd;
- if(pTmp && !pTmp->bInStrip)
- {
- if(pTmp->sOld.pFwd && !pTmp->sOld.pFwd->bInStrip)
- pTmp->sOld.pFwd->Cement();
- pTmp->Cement();
- }
- pTmp = pTri->sOld.pRev;
- if(pTmp && !pTmp->bInStrip)
- {
- pTmp->Cement();
- }
- // Cement this tris
- pTri->bInStrip = false;
- pTri->Cement();
- }
- }
- else
- {
- // Shame, undo the strip
- for(i = 0; i < nStripLen; ++i)
- {
- pTri = m_psStrip[i];
- _ASSERT(pTri->bInStrip);
- // Undo affected tris
- pTmp = pTri->sOld.pFwd;
- if(pTmp && !pTmp->bInStrip)
- {
- if(pTmp->sOld.pFwd && !pTmp->sOld.pFwd->bInStrip)
- pTmp->sOld.pFwd->Undo();
- pTmp->Undo();
- }
- pTmp = pTri->sOld.pRev;
- if(pTmp && !pTmp->bInStrip)
- {
- pTmp->Undo();
- }
- // Undo this tris
- pTri->bInStrip = false;
- pTri->Undo();
- }
- }
- #ifdef _DEBUG
- for(int nDbg = 0; nDbg < (int)m_nTriCnt; ++nDbg)
- {
- _ASSERT(m_pTri[nDbg].bInStrip == false);
- _ASSERT(m_pTri[nDbg].bOutput == false);
- _ASSERT(m_pTri[nDbg].sOld.pRev == m_pTri[nDbg].sNew.pRev);
- _ASSERT(m_pTri[nDbg].sOld.pFwd == m_pTri[nDbg].sNew.pFwd);
- if(m_pTri[nDbg].sNew.pRev)
- {
- _ASSERT(m_pTri[nDbg].sNew.pRev->sNew.pFwd == &m_pTri[nDbg]);
- }
- if(m_pTri[nDbg].sNew.pFwd)
- {
- _ASSERT(m_pTri[nDbg].sNew.pFwd->sNew.pRev == &m_pTri[nDbg]);
- }
- }
- #endif
- if(nDiffTot)
- {
- m_nStrips += nDiffTot;
- return true;
- }
- return false;
- }
- /*!***************************************************************************
- @Function StripFromEdges
- @Description Creates a strip from the object's edge information.
- *****************************************************************************/
- void CStrip::StripFromEdges()
- {
- unsigned int i, j, nTest;
- CTri *pTri, *pTriPrev;
- int nEdge = 0;
- /*
- Attempt to create grid-oriented strips.
- */
- for(i = 0; i < m_nTriCnt; ++i)
- {
- pTri = &m_pTri[i];
- // Count the number of empty edges
- nTest = 0;
- for(j = 0; j < 3; ++j)
- {
- if(!pTri->pAdj[j])
- {
- ++nTest;
- }
- else
- {
- nEdge = j;
- }
- }
- if(nTest != 2)
- continue;
- for(;;)
- {
- // A tri with two empty edges is a corner (there are other corners too, but this works so...)
- while(StripGrow(*pTri, nEdge, -1)) {};
- pTriPrev = pTri;
- pTri = pTri->pAdj[nEdge];
- if(!pTri)
- break;
- // Find the edge we came over
- nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
- // Step around to the next edge
- if(++nEdge > 2)
- nEdge = 0;
- pTriPrev = pTri;
- pTri = pTri->pAdj[nEdge];
- if(!pTri)
- break;
- // Find the edge we came over
- nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
- // Step around to the next edge
- if(--nEdge < 0)
- nEdge = 2;
- #if 0
- // If we're not tracking the edge, give up
- nTest = nEdge - 1;
- if(nTest < 0)
- nTest = 2;
- if(pTri->pAdj[nTest])
- break;
- else
- continue;
- #endif
- }
- }
- }
- #ifdef RND_TRIS_ORDER
- struct pair
- {
- unsigned int i, o;
- };
- static int compare(const void *arg1, const void *arg2)
- {
- return ((pair*)arg1)->i - ((pair*)arg2)->i;
- }
- #endif
- /*!***************************************************************************
- @Function StripImprove
- @Description Optimises the strip
- *****************************************************************************/
- void CStrip::StripImprove()
- {
- unsigned int i, j;
- bool bChanged;
- int nRepCnt, nChecks;
- int nMaxChange;
- #ifdef RND_TRIS_ORDER
- pair *pnOrder;
- /*
- Create a random order to process the tris
- */
- pnOrder = new pair[m_nTriCnt];
- #endif
- nRepCnt = 0;
- nChecks = 2;
- nMaxChange = 0;
- /*
- Reduce strip count by growing each of the three strips each tri can start.
- */
- while(nChecks)
- {
- --nChecks;
- bChanged = false;
- #ifdef RND_TRIS_ORDER
- /*
- Create a random order to process the tris
- */
- for(i = 0; i < m_nTriCnt; ++i)
- {
- pnOrder[i].i = rand() * rand();
- pnOrder[i].o = i;
- }
- qsort(pnOrder, m_nTriCnt, sizeof(*pnOrder), compare);
- #endif
- /*
- Process the tris
- */
- for(i = 0; i < m_nTriCnt; ++i)
- {
- for(j = 0; j < 3; ++j)
- {
- #ifdef RND_TRIS_ORDER
- bChanged |= StripGrow(m_pTri[pnOrder[i].o], j, nMaxChange);
- #else
- bChanged |= StripGrow(m_pTri[i], j, nMaxChange);
- #endif
- }
- }
- ++nRepCnt;
- // Check the results once or twice
- if(bChanged)
- nChecks = 2;
- nMaxChange = (nMaxChange == 0 ? -1 : 0);
- }
- #ifdef RND_TRIS_ORDER
- delete [] pnOrder;
- #endif
- _RPT1(_CRT_WARN, "Reps: %d\n", nRepCnt);
- }
- /*!***************************************************************************
- @Function Output
- @Output ppui32Strips
- @Output ppnStripLen The length of the strip
- @Output pnStripCnt
- @Description Outputs key information about the strip to the output
- parameters.
- *****************************************************************************/
- void CStrip::Output(
- unsigned int **ppui32Strips,
- unsigned int **ppnStripLen,
- unsigned int *pnStripCnt)
- {
- unsigned int *pui32Strips;
- unsigned int *pnStripLen;
- unsigned int i, j, nIdx, nStrip;
- CTri *pTri;
- /*
- Output Strips
- */
- pnStripLen = (unsigned int*)malloc(m_nStrips * sizeof(*pnStripLen));
- pui32Strips = (unsigned int*)malloc((m_nTriCnt + m_nStrips * 2) * sizeof(*pui32Strips));
- nStrip = 0;
- nIdx = 0;
- for(i = 0; i < m_nTriCnt; ++i)
- {
- pTri = &m_pTri[i];
- if(pTri->sNew.pRev)
- continue;
- _ASSERT(!pTri->sNew.pFwd || pTri->sNew.bWindFwd);
- _ASSERT(pTri->bOutput == false);
- if(!pTri->sNew.pFwd)
- {
- pui32Strips[nIdx++] = pTri->pIdx[0];
- pui32Strips[nIdx++] = pTri->pIdx[1];
- pui32Strips[nIdx++] = pTri->pIdx[2];
- pnStripLen[nStrip] = 1;
- pTri->bOutput = true;
- }
- else
- {
- if(pTri->sNew.pFwd == pTri->pAdj[0])
- {
- pui32Strips[nIdx++] = pTri->pIdx[2];
- pui32Strips[nIdx++] = pTri->pIdx[0];
- }
- else if(pTri->sNew.pFwd == pTri->pAdj[1])
- {
- pui32Strips[nIdx++] = pTri->pIdx[0];
- pui32Strips[nIdx++] = pTri->pIdx[1];
- }
- else
- {
- _ASSERT(pTri->sNew.pFwd == pTri->pAdj[2]);
- pui32Strips[nIdx++] = pTri->pIdx[1];
- pui32Strips[nIdx++] = pTri->pIdx[2];
- }
- pnStripLen[nStrip] = 0;
- do
- {
- _ASSERT(pTri->bOutput == false);
- // Increment tris-in-this-strip counter
- ++pnStripLen[nStrip];
- // Output the new vertex index
- for(j = 0; j < 3; ++j)
- {
- if(
- (pui32Strips[nIdx-2] != pTri->pIdx[j]) &&
- (pui32Strips[nIdx-1] != pTri->pIdx[j]))
- {
- break;
- }
- }
- _ASSERT(j != 3);
- pui32Strips[nIdx++] = pTri->pIdx[j];
- // Double-check that the previous three indices are the indices of this tris (in some order)
- _ASSERT(
- ((pui32Strips[nIdx-3] == pTri->pIdx[0]) && (pui32Strips[nIdx-2] == pTri->pIdx[1]) && (pui32Strips[nIdx-1] == pTri->pIdx[2])) ||
- ((pui32Strips[nIdx-3] == pTri->pIdx[1]) && (pui32Strips[nIdx-2] == pTri->pIdx[2]) && (pui32Strips[nIdx-1] == pTri->pIdx[0])) ||
- ((pui32Strips[nIdx-3] == pTri->pIdx[2]) && (pui32Strips[nIdx-2] == pTri->pIdx[0]) && (pui32Strips[nIdx-1] == pTri->pIdx[1])) ||
- ((pui32Strips[nIdx-3] == pTri->pIdx[2]) && (pui32Strips[nIdx-2] == pTri->pIdx[1]) && (pui32Strips[nIdx-1] == pTri->pIdx[0])) ||
- ((pui32Strips[nIdx-3] == pTri->pIdx[1]) && (pui32Strips[nIdx-2] == pTri->pIdx[0]) && (pui32Strips[nIdx-1] == pTri->pIdx[2])) ||
- ((pui32Strips[nIdx-3] == pTri->pIdx[0]) && (pui32Strips[nIdx-2] == pTri->pIdx[2]) && (pui32Strips[nIdx-1] == pTri->pIdx[1])));
- // Check that the latest three indices are not degenerate
- _ASSERT(pui32Strips[nIdx-1] != pui32Strips[nIdx-2]);
- _ASSERT(pui32Strips[nIdx-1] != pui32Strips[nIdx-3]);
- _ASSERT(pui32Strips[nIdx-2] != pui32Strips[nIdx-3]);
- pTri->bOutput = true;
- // Check that the next triangle is adjacent to this triangle
- _ASSERT(
- (pTri->sNew.pFwd == pTri->pAdj[0]) ||
- (pTri->sNew.pFwd == pTri->pAdj[1]) ||
- (pTri->sNew.pFwd == pTri->pAdj[2]) ||
- (!pTri->sNew.pFwd));
- // Check that this triangle is adjacent to the next triangle
- _ASSERT(
- (!pTri->sNew.pFwd) ||
- (pTri == pTri->sNew.pFwd->pAdj[0]) ||
- (pTri == pTri->sNew.pFwd->pAdj[1]) ||
- (pTri == pTri->sNew.pFwd->pAdj[2]));
- pTri = pTri->sNew.pFwd;
- } while(pTri);
- }
- ++nStrip;
- }
- _ASSERT(nIdx == m_nTriCnt + m_nStrips * 2);
- _ASSERT(nStrip == m_nStrips);
- // Check all triangles have been output
- for(i = 0; i < m_nTriCnt; ++i)
- {
- _ASSERT(m_pTri[i].bOutput == true);
- }
- // Check all triangles are present
- j = 0;
- for(i = 0; i < m_nStrips; ++i)
- {
- j += pnStripLen[i];
- }
- _ASSERT(j == m_nTriCnt);
- // Output data
- *pnStripCnt = m_nStrips;
- *ppui32Strips = pui32Strips;
- *ppnStripLen = pnStripLen;
- }
- /****************************************************************************
- ** Code
- ****************************************************************************/
- /*!***************************************************************************
- @Function PVRTTriStrip
- @Output ppui32Strips
- @Output ppnStripLen
- @Output pnStripCnt
- @Input pui32TriList
- @Input nTriCnt
- @Description Reads a triangle list and generates an optimised triangle strip.
- *****************************************************************************/
- void PVRTTriStrip(
- unsigned int **ppui32Strips,
- unsigned int **ppnStripLen,
- unsigned int *pnStripCnt,
- const unsigned int * const pui32TriList,
- const unsigned int nTriCnt)
- {
- unsigned int *pui32Strips;
- unsigned int *pnStripLen;
- unsigned int nStripCnt;
- /*
- If the order in which triangles are tested as strip roots is
- randomised, then several attempts can be made. Use the best result.
- */
- for(int i = 0; i <
- #ifdef RND_TRIS_ORDER
- 5
- #else
- 1
- #endif
- ; ++i)
- {
- CStrip stripper(pui32TriList, nTriCnt);
- #ifdef RND_TRIS_ORDER
- srand(i);
- #endif
- stripper.StripFromEdges();
- stripper.StripImprove();
- stripper.Output(&pui32Strips, &pnStripLen, &nStripCnt);
- if(!i || nStripCnt < *pnStripCnt)
- {
- if(i)
- {
- FREE(*ppui32Strips);
- FREE(*ppnStripLen);
- }
- *ppui32Strips = pui32Strips;
- *ppnStripLen = pnStripLen;
- *pnStripCnt = nStripCnt;
- }
- else
- {
- FREE(pui32Strips);
- FREE(pnStripLen);
- }
- }
- }
- /*!***************************************************************************
- @Function PVRTTriStripList
- @Modified pui32TriList
- @Input nTriCnt
- @Description Reads a triangle list and generates an optimised triangle strip.
- Result is converted back to a triangle list.
- *****************************************************************************/
- void PVRTTriStripList(unsigned int * const pui32TriList, const unsigned int nTriCnt)
- {
- unsigned int *pui32Strips;
- unsigned int *pnStripLength;
- unsigned int nNumStrips;
- unsigned int *pui32TriPtr, *pui32StripPtr;
- /*
- Strip the geometry
- */
- PVRTTriStrip(&pui32Strips, &pnStripLength, &nNumStrips, pui32TriList, nTriCnt);
- /*
- Convert back to a triangle list
- */
- pui32StripPtr = pui32Strips;
- pui32TriPtr = pui32TriList;
- for(unsigned int i = 0; i < nNumStrips; ++i)
- {
- *pui32TriPtr++ = *pui32StripPtr++;
- *pui32TriPtr++ = *pui32StripPtr++;
- *pui32TriPtr++ = *pui32StripPtr++;
- for(unsigned int j = 1; j < pnStripLength[i]; ++j)
- {
- // Use two indices from previous triangle, flipping tri order alternately.
- if(j & 0x01)
- {
- *pui32TriPtr++ = pui32StripPtr[-1];
- *pui32TriPtr++ = pui32StripPtr[-2];
- }
- else
- {
- *pui32TriPtr++ = pui32StripPtr[-2];
- *pui32TriPtr++ = pui32StripPtr[-1];
- }
- *pui32TriPtr++ = *pui32StripPtr++;
- }
- }
- free(pui32Strips);
- free(pnStripLength);
- }
- /*****************************************************************************
- End of file (PVRTTriStrip.cpp)
- *****************************************************************************/
|