Home | History | Annotate | Download | only in Tools
      1 /******************************************************************************
      2 
      3  @File         PVRTTriStrip.cpp
      4 
      5  @Title        PVRTTriStrip
      6 
      7  @Version       @Version
      8 
      9  @Copyright    Copyright (c) Imagination Technologies Limited.
     10 
     11  @Platform     Independent
     12 
     13  @Description  Strips a triangle list.
     14 
     15 ******************************************************************************/
     16 
     17 /****************************************************************************
     18 ** Includes
     19 ****************************************************************************/
     20 #include <stdlib.h>
     21 
     22 #include "PVRTGlobal.h"
     23 #include "PVRTContext.h"
     24 #include "PVRTTriStrip.h"
     25 
     26 /****************************************************************************
     27 ** Defines
     28 ****************************************************************************/
     29 #define RND_TRIS_ORDER
     30 
     31 /****************************************************************************
     32 ** Structures
     33 ****************************************************************************/
     34 
     35 /****************************************************************************
     36 ** Class: CTri
     37 ****************************************************************************/
     38 class CTri;
     39 
     40 /*!***************************************************************************
     41  @Class				CTriState
     42  @Description		Stores a pointer to the triangles either side of itself,
     43 					as well as it's winding.
     44 *****************************************************************************/
     45 class CTriState
     46 {
     47 public:
     48 	CTri	*pRev, *pFwd;
     49 	bool	bWindFwd;
     50 
     51 	CTriState()
     52 	{
     53 		bWindFwd	= true;		// Initial value irrelevent
     54 		pRev		= NULL;
     55 		pFwd		= NULL;
     56 	}
     57 };
     58 /*!***************************************************************************
     59  @Class				CTri
     60  @Description		Object used to store information about the triangle, such as
     61 					the vertex indices it is made from, which triangles are
     62 					adjacent to it, etc.
     63 *****************************************************************************/
     64 class CTri
     65 {
     66 public:
     67 	CTriState	sNew, sOld;
     68 
     69 	CTri	*pAdj[3];
     70 	bool	bInStrip;
     71 
     72 	const unsigned int	*pIdx;		// three indices for the tri
     73 	bool					bOutput;
     74 
     75 public:
     76 	CTri();
     77 	int FindEdge(const unsigned int pw0, const unsigned int pw1) const;
     78 	void Cement();
     79 	void Undo();
     80 	int EdgeFromAdjTri(const CTri &tri) const;	// Find the index of the adjacent tri
     81 };
     82 
     83 /*!***************************************************************************
     84  @Class				CStrip
     85  @Description		Object used to store the triangles that a given strip is
     86 					composed from.
     87 *****************************************************************************/
     88 class CStrip
     89 {
     90 protected:
     91 	unsigned int	m_nTriCnt;
     92 	CTri			*m_pTri;
     93 	unsigned int	m_nStrips;
     94 
     95 	CTri			**m_psStrip;	// Working space for finding strips
     96 
     97 public:
     98 	CStrip(
     99 		const unsigned int	* const pui32TriList,
    100 		const unsigned int		nTriCnt);
    101 	~CStrip();
    102 
    103 protected:
    104 	bool StripGrow(
    105 		CTri				&triFrom,
    106 		const unsigned int	nEdgeFrom,
    107 		const int			nMaxChange);
    108 
    109 public:
    110 	void StripFromEdges();
    111 	void StripImprove();
    112 
    113 	void Output(
    114 		unsigned int	**ppui32Strips,
    115 		unsigned int	**ppnStripLen,
    116 		unsigned int	*pnStripCnt);
    117 };
    118 
    119 /****************************************************************************
    120 ** Constants
    121 ****************************************************************************/
    122 
    123 /****************************************************************************
    124 ** Code: Class: CTri
    125 ****************************************************************************/
    126 CTri::CTri()
    127 {
    128 	pAdj[0]		= NULL;
    129 	pAdj[1]		= NULL;
    130 	pAdj[2]		= NULL;
    131 	bInStrip	= false;
    132 	bOutput		= false;
    133 }
    134 
    135 /*!***************************************************************************
    136  @Function			FindEdge
    137  @Input				pw0			The first index
    138  @Input				pw1			The second index
    139  @Return			The index of the edge
    140  @Description		Finds the index of the edge that the current object shares
    141 					with the two vertex index values that have been passed in
    142 					(or returns -1 if they dont share an edge).
    143 *****************************************************************************/
    144 int CTri::FindEdge(const unsigned int pw0, const unsigned int pw1) const
    145 {
    146 	if((pIdx[0] == pw0 && pIdx[1] == pw1))
    147 		return 0;
    148 	if((pIdx[1] == pw0 && pIdx[2] == pw1))
    149 		return 1;
    150 	if((pIdx[2] == pw0 && pIdx[0] == pw1))
    151 		return 2;
    152 	return -1;
    153 }
    154 /*!***************************************************************************
    155  @Function			Cement
    156  @Description		Assigns the new state as the old state.
    157 *****************************************************************************/
    158 void CTri::Cement()
    159 {
    160 	sOld = sNew;
    161 }
    162 /*!***************************************************************************
    163  @Function			Undo
    164  @Description		Reverts the new state to the old state.
    165 *****************************************************************************/
    166 void CTri::Undo()
    167 {
    168 	sNew = sOld;
    169 }
    170 /*!***************************************************************************
    171  @Function			EdgeFromAdjTri
    172  @Input				tri			The triangle to compare
    173  @Return			int			Index of adjacent triangle (-1 if not adjacent)
    174  @Description		If the input triangle is adjacent to the current triangle,
    175 					it's index is returned.
    176 *****************************************************************************/
    177 int CTri::EdgeFromAdjTri(const CTri &tri) const
    178 {
    179 	for(int i = 0; i < 3; ++i)
    180 	{
    181 		if(pAdj[i] == &tri)
    182 		{
    183 			return i;
    184 		}
    185 	}
    186 	_ASSERT(false);
    187 	return -1;
    188 }
    189 
    190 /****************************************************************************
    191 ** Local code
    192 ****************************************************************************/
    193 /*!***************************************************************************
    194  @Function			OrphanTri
    195  @Input				tri			The triangle test
    196  @Return			int			Returns 1 if change was made
    197  @Description		If the input triangle is not wound forward and is not the last
    198 					triangle in the strip, the connection with the next triangle
    199 					in the strip is removed.
    200 *****************************************************************************/
    201 static int OrphanTri(
    202 	CTri		* const pTri)
    203 {
    204 	_ASSERT(!pTri->bInStrip);
    205 	if(pTri->sNew.bWindFwd || !pTri->sNew.pFwd)
    206 		return 0;
    207 
    208 	pTri->sNew.pFwd->sNew.pRev = NULL;
    209 	pTri->sNew.pFwd = NULL;
    210 	return 1;
    211 }
    212 /*!***************************************************************************
    213  @Function			TakeTri
    214  @Input				pTri		The triangle to take
    215  @Input				pRevNew		The triangle that is before pTri in the new strip
    216  @Return			int			Returns 1 if a new strip has been created
    217  @Description		Removes the triangle from it's current strip
    218 					and places it in a new one (following pRevNew in the new strip).
    219 *****************************************************************************/
    220 static int TakeTri(
    221 	CTri		* const pTri,
    222 	CTri		* const pRevNew,
    223 	const bool	bFwd)
    224 {
    225 	int	nRet;
    226 
    227 	_ASSERT(!pTri->bInStrip);
    228 
    229 	if(pTri->sNew.pFwd && pTri->sNew.pRev)
    230 	{
    231 		_ASSERT(pTri->sNew.pFwd->sNew.pRev == pTri);
    232 		pTri->sNew.pFwd->sNew.pRev = NULL;
    233 		_ASSERT(pTri->sNew.pRev->sNew.pFwd == pTri);
    234 		pTri->sNew.pRev->sNew.pFwd = NULL;
    235 
    236 		// If in the middle of a Strip, this will generate a new Strip
    237 		nRet = 1;
    238 
    239 		// The second tri in the strip may need to be orphaned, or it will have wrong winding order
    240 		nRet += OrphanTri(pTri->sNew.pFwd);
    241 	}
    242 	else if(pTri->sNew.pFwd)
    243 	{
    244 		_ASSERT(pTri->sNew.pFwd->sNew.pRev == pTri);
    245 		pTri->sNew.pFwd->sNew.pRev = NULL;
    246 
    247 		// If at the beginning of a Strip, no change
    248 		nRet = 0;
    249 
    250 		// The second tri in the strip may need to be orphaned, or it will have wrong winding order
    251 		nRet += OrphanTri(pTri->sNew.pFwd);
    252 	}
    253 	else if(pTri->sNew.pRev)
    254 	{
    255 		_ASSERT(pTri->sNew.pRev->sNew.pFwd == pTri);
    256 		pTri->sNew.pRev->sNew.pFwd = NULL;
    257 
    258 		// If at the end of a Strip, no change
    259 		nRet = 0;
    260 	}
    261 	else
    262 	{
    263 		// Otherwise it's a lonesome triangle; one Strip removed!
    264 		nRet = -1;
    265 	}
    266 
    267 	pTri->sNew.pFwd		= NULL;
    268 	pTri->sNew.pRev		= pRevNew;
    269 	pTri->bInStrip		= true;
    270 	pTri->sNew.bWindFwd	= bFwd;
    271 
    272 	if(pRevNew)
    273 	{
    274 		_ASSERT(!pRevNew->sNew.pFwd);
    275 		pRevNew->sNew.pFwd	= pTri;
    276 	}
    277 
    278 	return nRet;
    279 }
    280 /*!***************************************************************************
    281  @Function			TryLinkEdge
    282  @Input				src			The source triangle
    283  @Input				cmp			The triangle to compare with
    284  @Input				nSrcEdge	The edge of souce triangle to compare
    285  @Input				idx0		Vertex index 0 of the compare triangle
    286  @Input				idx1		Vertex index 1 of the compare triangle
    287  @Description		If the triangle to compare currently has no adjacent
    288 					triangle along the specified edge, link the source triangle
    289 					(along it's specified edge) with the compare triangle.
    290 *****************************************************************************/
    291 static bool TryLinkEdge(
    292 	CTri				&src,
    293 	CTri				&cmp,
    294 	const int			nSrcEdge,
    295 	const unsigned int	idx0,
    296 	const unsigned int	idx1)
    297 {
    298 	int nCmpEdge;
    299 
    300 	nCmpEdge = cmp.FindEdge(idx0, idx1);
    301 	if(nCmpEdge != -1 && !cmp.pAdj[nCmpEdge])
    302 	{
    303 		cmp.pAdj[nCmpEdge] = &src;
    304 		src.pAdj[nSrcEdge] = &cmp;
    305 		return true;
    306 	}
    307 	return false;
    308 }
    309 
    310 /****************************************************************************
    311 ** Code: Class: CStrip
    312 ****************************************************************************/
    313 CStrip::CStrip(
    314 	const unsigned int	* const pui32TriList,
    315 	const unsigned int	nTriCnt)
    316 {
    317 	unsigned int	i, j;
    318 	bool			b0, b1, b2;
    319 
    320 	m_nTriCnt = nTriCnt;
    321 
    322 	/*
    323 		Generate adjacency info
    324 	*/
    325 	m_pTri = new CTri[nTriCnt];
    326 	for(i = 0; i < nTriCnt; ++i)
    327 	{
    328 		// Set pointer to indices
    329 		m_pTri[i].pIdx = &pui32TriList[3 * i];
    330 
    331 		b0 = false;
    332 		b1 = false;
    333 		b2 = false;
    334 		for(j = 0; j < i && !(b0 & b1 & b2); ++j)
    335 		{
    336 			if(!b0)
    337 				b0 = TryLinkEdge(m_pTri[i], m_pTri[j], 0, m_pTri[i].pIdx[1], m_pTri[i].pIdx[0]);
    338 
    339 			if(!b1)
    340 				b1 = TryLinkEdge(m_pTri[i], m_pTri[j], 1, m_pTri[i].pIdx[2], m_pTri[i].pIdx[1]);
    341 
    342 			if(!b2)
    343 				b2 = TryLinkEdge(m_pTri[i], m_pTri[j], 2, m_pTri[i].pIdx[0], m_pTri[i].pIdx[2]);
    344 		}
    345 	}
    346 
    347 	// Initially, every triangle is a strip.
    348 	m_nStrips = m_nTriCnt;
    349 
    350 	// Allocate working space for the strippers
    351 	m_psStrip = new CTri*[m_nTriCnt];
    352 }
    353 
    354 CStrip::~CStrip()
    355 {
    356 	delete [] m_pTri;
    357 	delete [] m_psStrip;
    358 }
    359 /*!***************************************************************************
    360  @Function			StripGrow
    361  @Input				triFrom			The triangle to begin from
    362  @Input				nEdgeFrom		The edge of the triangle to begin from
    363  @Input				maxChange		The maximum number of changes to be made
    364  @Description		Takes triFrom as a starting point of triangles to add to
    365 					the list and adds triangles sequentially by finding the next
    366 					triangle that is adjacent to the current triangle.
    367 					This is repeated until the maximum number of changes
    368 					have been made.
    369 *****************************************************************************/
    370 bool CStrip::StripGrow(
    371 	CTri				&triFrom,
    372 	const unsigned int	nEdgeFrom,
    373 	const int			nMaxChange)
    374 {
    375 	unsigned int	i;
    376 	bool			bFwd;
    377 	int				nDiff, nDiffTot, nEdge;
    378 	CTri			*pTri, *pTriPrev, *pTmp;
    379 	unsigned int	nStripLen;
    380 
    381 	// Start strip from this tri
    382 	pTri		= &triFrom;
    383 	pTriPrev	= NULL;
    384 
    385 	nDiffTot	= 0;
    386 	nStripLen	= 0;
    387 
    388 	// Start strip from this edge
    389 	nEdge	= nEdgeFrom;
    390 	bFwd	= true;
    391 
    392 	// Extend the strip until we run out, or we find an improvement
    393 	nDiff = 1;
    394 	while(nDiff > nMaxChange)
    395 	{
    396 		// Add pTri to the strip
    397 		_ASSERT(pTri);
    398 		nDiff += TakeTri(pTri, pTriPrev, bFwd);
    399 		_ASSERT(nStripLen < m_nTriCnt);
    400 		m_psStrip[nStripLen++] = pTri;
    401 
    402 		// Jump to next tri
    403 		pTriPrev = pTri;
    404 		pTri = pTri->pAdj[nEdge];
    405 		if(!pTri)
    406 			break;	// No more tris, gotta stop
    407 
    408 		if(pTri->bInStrip)
    409 			break;	// No more tris, gotta stop
    410 
    411 		// Find which edge we came over
    412 		nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
    413 
    414 		// Find the edge to leave over
    415 		if(bFwd)
    416 		{
    417 			if(--nEdge < 0)
    418 				nEdge = 2;
    419 		}
    420 		else
    421 		{
    422 			if(++nEdge > 2)
    423 				nEdge = 0;
    424 		}
    425 
    426 		// Swap the winding order for the next tri
    427 		bFwd = !bFwd;
    428 	}
    429 	_ASSERT(!pTriPrev->sNew.pFwd);
    430 
    431 	/*
    432 		Accept or reject this strip.
    433 
    434 		Accepting changes which don't change the number of strips
    435 		adds variety, which can help better strips to develop.
    436 	*/
    437 	if(nDiff <= nMaxChange)
    438 	{
    439 		nDiffTot += nDiff;
    440 
    441 		// Great, take the Strip
    442 		for(i = 0; i < nStripLen; ++i)
    443 		{
    444 			pTri = m_psStrip[i];
    445 			_ASSERT(pTri->bInStrip);
    446 
    447 			// Cement affected tris
    448 			pTmp = pTri->sOld.pFwd;
    449 			if(pTmp && !pTmp->bInStrip)
    450 			{
    451 				if(pTmp->sOld.pFwd && !pTmp->sOld.pFwd->bInStrip)
    452 					pTmp->sOld.pFwd->Cement();
    453 				pTmp->Cement();
    454 			}
    455 
    456 			pTmp = pTri->sOld.pRev;
    457 			if(pTmp && !pTmp->bInStrip)
    458 			{
    459 				pTmp->Cement();
    460 			}
    461 
    462 			// Cement this tris
    463 			pTri->bInStrip = false;
    464 			pTri->Cement();
    465 		}
    466 	}
    467 	else
    468 	{
    469 		// Shame, undo the strip
    470 		for(i = 0; i < nStripLen; ++i)
    471 		{
    472 			pTri = m_psStrip[i];
    473 			_ASSERT(pTri->bInStrip);
    474 
    475 			// Undo affected tris
    476 			pTmp = pTri->sOld.pFwd;
    477 			if(pTmp && !pTmp->bInStrip)
    478 			{
    479 				if(pTmp->sOld.pFwd && !pTmp->sOld.pFwd->bInStrip)
    480 					pTmp->sOld.pFwd->Undo();
    481 				pTmp->Undo();
    482 			}
    483 
    484 			pTmp = pTri->sOld.pRev;
    485 			if(pTmp && !pTmp->bInStrip)
    486 			{
    487 				pTmp->Undo();
    488 			}
    489 
    490 			// Undo this tris
    491 			pTri->bInStrip = false;
    492 			pTri->Undo();
    493 		}
    494 	}
    495 
    496 #ifdef _DEBUG
    497 	for(int nDbg = 0; nDbg < (int)m_nTriCnt; ++nDbg)
    498 	{
    499 		_ASSERT(m_pTri[nDbg].bInStrip == false);
    500 		_ASSERT(m_pTri[nDbg].bOutput == false);
    501 		_ASSERT(m_pTri[nDbg].sOld.pRev == m_pTri[nDbg].sNew.pRev);
    502 		_ASSERT(m_pTri[nDbg].sOld.pFwd == m_pTri[nDbg].sNew.pFwd);
    503 
    504 		if(m_pTri[nDbg].sNew.pRev)
    505 		{
    506 			_ASSERT(m_pTri[nDbg].sNew.pRev->sNew.pFwd == &m_pTri[nDbg]);
    507 		}
    508 
    509 		if(m_pTri[nDbg].sNew.pFwd)
    510 		{
    511 			_ASSERT(m_pTri[nDbg].sNew.pFwd->sNew.pRev == &m_pTri[nDbg]);
    512 		}
    513 	}
    514 #endif
    515 
    516 	if(nDiffTot)
    517 	{
    518 		m_nStrips += nDiffTot;
    519 		return true;
    520 	}
    521 	return false;
    522 }
    523 
    524 /*!***************************************************************************
    525  @Function			StripFromEdges
    526  @Description		Creates a strip from the object's edge information.
    527 *****************************************************************************/
    528 void CStrip::StripFromEdges()
    529 {
    530 	unsigned int	i, j, nTest;
    531 	CTri			*pTri, *pTriPrev;
    532 	int				nEdge = 0;
    533 
    534 	/*
    535 		Attempt to create grid-oriented strips.
    536 	*/
    537 	for(i = 0; i < m_nTriCnt; ++i)
    538 	{
    539 		pTri = &m_pTri[i];
    540 
    541 		// Count the number of empty edges
    542 		nTest = 0;
    543 		for(j = 0; j < 3; ++j)
    544 		{
    545 			if(!pTri->pAdj[j])
    546 			{
    547 				++nTest;
    548 			}
    549 			else
    550 			{
    551 				nEdge = j;
    552 			}
    553 		}
    554 
    555 		if(nTest != 2)
    556 			continue;
    557 
    558 		for(;;)
    559 		{
    560 			// A tri with two empty edges is a corner (there are other corners too, but this works so...)
    561 			while(StripGrow(*pTri, nEdge, -1)) {};
    562 
    563 			pTriPrev = pTri;
    564 			pTri = pTri->pAdj[nEdge];
    565 			if(!pTri)
    566 				break;
    567 
    568 			// Find the edge we came over
    569 			nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
    570 
    571 			// Step around to the next edge
    572 			if(++nEdge > 2)
    573 				nEdge = 0;
    574 
    575 			pTriPrev = pTri;
    576 			pTri = pTri->pAdj[nEdge];
    577 			if(!pTri)
    578 				break;
    579 
    580 			// Find the edge we came over
    581 			nEdge = pTri->EdgeFromAdjTri(*pTriPrev);
    582 
    583 			// Step around to the next edge
    584 			if(--nEdge < 0)
    585 				nEdge = 2;
    586 
    587 #if 0
    588 			// If we're not tracking the edge, give up
    589 			nTest = nEdge - 1;
    590 			if(nTest < 0)
    591 				nTest = 2;
    592 			if(pTri->pAdj[nTest])
    593 				break;
    594 			else
    595 				continue;
    596 #endif
    597 		}
    598 	}
    599 }
    600 
    601 #ifdef RND_TRIS_ORDER
    602 struct pair
    603 {
    604 	unsigned int i, o;
    605 };
    606 
    607 static int compare(const void *arg1, const void *arg2)
    608 {
    609 	return ((pair*)arg1)->i - ((pair*)arg2)->i;
    610 }
    611 #endif
    612 /*!***************************************************************************
    613  @Function			StripImprove
    614  @Description		Optimises the strip
    615 *****************************************************************************/
    616 void CStrip::StripImprove()
    617 {
    618 	unsigned int	i, j;
    619 	bool			bChanged;
    620 	int				nRepCnt, nChecks;
    621 	int				nMaxChange;
    622 #ifdef RND_TRIS_ORDER
    623 	pair			*pnOrder;
    624 
    625 	/*
    626 		Create a random order to process the tris
    627 	*/
    628 	pnOrder = new pair[m_nTriCnt];
    629 #endif
    630 
    631 	nRepCnt = 0;
    632 	nChecks = 2;
    633 	nMaxChange	= 0;
    634 
    635 	/*
    636 		Reduce strip count by growing each of the three strips each tri can start.
    637 	*/
    638 	while(nChecks)
    639 	{
    640 		--nChecks;
    641 
    642 		bChanged = false;
    643 
    644 #ifdef RND_TRIS_ORDER
    645 		/*
    646 			Create a random order to process the tris
    647 		*/
    648 		for(i = 0; i < m_nTriCnt; ++i)
    649 		{
    650 			pnOrder[i].i = rand() * rand();
    651 			pnOrder[i].o = i;
    652 		}
    653 		qsort(pnOrder, m_nTriCnt, sizeof(*pnOrder), compare);
    654 #endif
    655 
    656 		/*
    657 			Process the tris
    658 		*/
    659 		for(i = 0; i < m_nTriCnt; ++i)
    660 		{
    661 			for(j = 0; j < 3; ++j)
    662 			{
    663 #ifdef RND_TRIS_ORDER
    664 				bChanged |= StripGrow(m_pTri[pnOrder[i].o], j, nMaxChange);
    665 #else
    666 				bChanged |= StripGrow(m_pTri[i], j, nMaxChange);
    667 #endif
    668 			}
    669 		}
    670 		++nRepCnt;
    671 
    672 		// Check the results once or twice
    673 		if(bChanged)
    674 			nChecks = 2;
    675 
    676 		nMaxChange = (nMaxChange == 0 ? -1 : 0);
    677 	}
    678 
    679 #ifdef RND_TRIS_ORDER
    680 	delete [] pnOrder;
    681 #endif
    682 	_RPT1(_CRT_WARN, "Reps: %d\n", nRepCnt);
    683 }
    684 /*!***************************************************************************
    685  @Function			Output
    686  @Output			ppui32Strips
    687  @Output			ppnStripLen			The length of the strip
    688  @Output			pnStripCnt
    689  @Description		Outputs key information about the strip to the output
    690 					parameters.
    691 *****************************************************************************/
    692 void CStrip::Output(
    693 	unsigned int	**ppui32Strips,
    694 	unsigned int	**ppnStripLen,
    695 	unsigned int	*pnStripCnt)
    696 {
    697 	unsigned int	*pui32Strips;
    698 	unsigned int	*pnStripLen;
    699 	unsigned int	i, j, nIdx, nStrip;
    700 	CTri			*pTri;
    701 
    702 	/*
    703 		Output Strips
    704 	*/
    705 	pnStripLen = (unsigned int*)malloc(m_nStrips * sizeof(*pnStripLen));
    706 	pui32Strips = (unsigned int*)malloc((m_nTriCnt + m_nStrips * 2) * sizeof(*pui32Strips));
    707 	nStrip = 0;
    708 	nIdx = 0;
    709 	for(i = 0; i < m_nTriCnt; ++i)
    710 	{
    711 		pTri = &m_pTri[i];
    712 
    713 		if(pTri->sNew.pRev)
    714 			continue;
    715 		_ASSERT(!pTri->sNew.pFwd || pTri->sNew.bWindFwd);
    716 		_ASSERT(pTri->bOutput == false);
    717 
    718 		if(!pTri->sNew.pFwd)
    719 		{
    720 			pui32Strips[nIdx++] = pTri->pIdx[0];
    721 			pui32Strips[nIdx++] = pTri->pIdx[1];
    722 			pui32Strips[nIdx++] = pTri->pIdx[2];
    723 			pnStripLen[nStrip] = 1;
    724 			pTri->bOutput = true;
    725 		}
    726 		else
    727 		{
    728 			if(pTri->sNew.pFwd == pTri->pAdj[0])
    729 			{
    730 				pui32Strips[nIdx++] = pTri->pIdx[2];
    731 				pui32Strips[nIdx++] = pTri->pIdx[0];
    732 			}
    733 			else if(pTri->sNew.pFwd == pTri->pAdj[1])
    734 			{
    735 				pui32Strips[nIdx++] = pTri->pIdx[0];
    736 				pui32Strips[nIdx++] = pTri->pIdx[1];
    737 			}
    738 			else
    739 			{
    740 				_ASSERT(pTri->sNew.pFwd == pTri->pAdj[2]);
    741 				pui32Strips[nIdx++] = pTri->pIdx[1];
    742 				pui32Strips[nIdx++] = pTri->pIdx[2];
    743 			}
    744 
    745 			pnStripLen[nStrip] = 0;
    746 			do
    747 			{
    748 				_ASSERT(pTri->bOutput == false);
    749 
    750 				// Increment tris-in-this-strip counter
    751 				++pnStripLen[nStrip];
    752 
    753 				// Output the new vertex index
    754 				for(j = 0; j < 3; ++j)
    755 				{
    756 					if(
    757 						(pui32Strips[nIdx-2] != pTri->pIdx[j]) &&
    758 						(pui32Strips[nIdx-1] != pTri->pIdx[j]))
    759 					{
    760 						break;
    761 					}
    762 				}
    763 				_ASSERT(j != 3);
    764 				pui32Strips[nIdx++] = pTri->pIdx[j];
    765 
    766 				// Double-check that the previous three indices are the indices of this tris (in some order)
    767 				_ASSERT(
    768 					((pui32Strips[nIdx-3] == pTri->pIdx[0]) && (pui32Strips[nIdx-2] == pTri->pIdx[1]) && (pui32Strips[nIdx-1] == pTri->pIdx[2])) ||
    769 					((pui32Strips[nIdx-3] == pTri->pIdx[1]) && (pui32Strips[nIdx-2] == pTri->pIdx[2]) && (pui32Strips[nIdx-1] == pTri->pIdx[0])) ||
    770 					((pui32Strips[nIdx-3] == pTri->pIdx[2]) && (pui32Strips[nIdx-2] == pTri->pIdx[0]) && (pui32Strips[nIdx-1] == pTri->pIdx[1])) ||
    771 					((pui32Strips[nIdx-3] == pTri->pIdx[2]) && (pui32Strips[nIdx-2] == pTri->pIdx[1]) && (pui32Strips[nIdx-1] == pTri->pIdx[0])) ||
    772 					((pui32Strips[nIdx-3] == pTri->pIdx[1]) && (pui32Strips[nIdx-2] == pTri->pIdx[0]) && (pui32Strips[nIdx-1] == pTri->pIdx[2])) ||
    773 					((pui32Strips[nIdx-3] == pTri->pIdx[0]) && (pui32Strips[nIdx-2] == pTri->pIdx[2]) && (pui32Strips[nIdx-1] == pTri->pIdx[1])));
    774 
    775 				// Check that the latest three indices are not degenerate
    776 				_ASSERT(pui32Strips[nIdx-1] != pui32Strips[nIdx-2]);
    777 				_ASSERT(pui32Strips[nIdx-1] != pui32Strips[nIdx-3]);
    778 				_ASSERT(pui32Strips[nIdx-2] != pui32Strips[nIdx-3]);
    779 
    780 				pTri->bOutput = true;
    781 
    782 				// Check that the next triangle is adjacent to this triangle
    783 				_ASSERT(
    784 					(pTri->sNew.pFwd == pTri->pAdj[0]) ||
    785 					(pTri->sNew.pFwd == pTri->pAdj[1]) ||
    786 					(pTri->sNew.pFwd == pTri->pAdj[2]) ||
    787 					(!pTri->sNew.pFwd));
    788 				// Check that this triangle is adjacent to the next triangle
    789 				_ASSERT(
    790 					(!pTri->sNew.pFwd) ||
    791 					(pTri == pTri->sNew.pFwd->pAdj[0]) ||
    792 					(pTri == pTri->sNew.pFwd->pAdj[1]) ||
    793 					(pTri == pTri->sNew.pFwd->pAdj[2]));
    794 
    795 				pTri = pTri->sNew.pFwd;
    796 			} while(pTri);
    797 		}
    798 
    799 		++nStrip;
    800 	}
    801 	_ASSERT(nIdx == m_nTriCnt + m_nStrips * 2);
    802 	_ASSERT(nStrip == m_nStrips);
    803 
    804 	// Check all triangles have been output
    805 	for(i = 0; i < m_nTriCnt; ++i)
    806 	{
    807 		_ASSERT(m_pTri[i].bOutput == true);
    808 	}
    809 
    810 	// Check all triangles are present
    811 	j = 0;
    812 	for(i = 0; i < m_nStrips; ++i)
    813 	{
    814 		j += pnStripLen[i];
    815 	}
    816 	_ASSERT(j == m_nTriCnt);
    817 
    818 	// Output data
    819 	*pnStripCnt		= m_nStrips;
    820 	*ppui32Strips		= pui32Strips;
    821 	*ppnStripLen	= pnStripLen;
    822 }
    823 
    824 /****************************************************************************
    825 ** Code
    826 ****************************************************************************/
    827 
    828 /*!***************************************************************************
    829  @Function			PVRTTriStrip
    830  @Output			ppui32Strips
    831  @Output			ppnStripLen
    832  @Output			pnStripCnt
    833  @Input				pui32TriList
    834  @Input				nTriCnt
    835  @Description		Reads a triangle list and generates an optimised triangle strip.
    836 *****************************************************************************/
    837 void PVRTTriStrip(
    838 	unsigned int			**ppui32Strips,
    839 	unsigned int			**ppnStripLen,
    840 	unsigned int			*pnStripCnt,
    841 	const unsigned int	* const pui32TriList,
    842 	const unsigned int		nTriCnt)
    843 {
    844 	unsigned int	*pui32Strips;
    845 	unsigned int	*pnStripLen;
    846 	unsigned int	nStripCnt;
    847 
    848 	/*
    849 		If the order in which triangles are tested as strip roots is
    850 		randomised, then several attempts can be made. Use the best result.
    851 	*/
    852 	for(int i = 0; i <
    853 #ifdef RND_TRIS_ORDER
    854 		5
    855 #else
    856 		1
    857 #endif
    858 		; ++i)
    859 	{
    860 		CStrip stripper(pui32TriList, nTriCnt);
    861 
    862 #ifdef RND_TRIS_ORDER
    863 		srand(i);
    864 #endif
    865 
    866 		stripper.StripFromEdges();
    867 		stripper.StripImprove();
    868 		stripper.Output(&pui32Strips, &pnStripLen, &nStripCnt);
    869 
    870 		if(!i || nStripCnt < *pnStripCnt)
    871 		{
    872 			if(i)
    873 			{
    874 				FREE(*ppui32Strips);
    875 				FREE(*ppnStripLen);
    876 			}
    877 
    878 			*ppui32Strips		= pui32Strips;
    879 			*ppnStripLen	= pnStripLen;
    880 			*pnStripCnt		= nStripCnt;
    881 		}
    882 		else
    883 		{
    884 			FREE(pui32Strips);
    885 			FREE(pnStripLen);
    886 		}
    887 	}
    888 }
    889 
    890 /*!***************************************************************************
    891  @Function			PVRTTriStripList
    892  @Modified			pui32TriList
    893  @Input				nTriCnt
    894  @Description		Reads a triangle list and generates an optimised triangle strip.
    895  					Result is converted back to a triangle list.
    896 *****************************************************************************/
    897 void PVRTTriStripList(unsigned int * const pui32TriList, const unsigned int nTriCnt)
    898 {
    899 	unsigned int	*pui32Strips;
    900 	unsigned int	*pnStripLength;
    901 	unsigned int	nNumStrips;
    902 	unsigned int	*pui32TriPtr, *pui32StripPtr;
    903 
    904 	/*
    905 		Strip the geometry
    906 	*/
    907 	PVRTTriStrip(&pui32Strips, &pnStripLength, &nNumStrips, pui32TriList, nTriCnt);
    908 
    909 	/*
    910 		Convert back to a triangle list
    911 	*/
    912 	pui32StripPtr	= pui32Strips;
    913 	pui32TriPtr	= pui32TriList;
    914 	for(unsigned int i = 0; i < nNumStrips; ++i)
    915 	{
    916 		*pui32TriPtr++ = *pui32StripPtr++;
    917 		*pui32TriPtr++ = *pui32StripPtr++;
    918 		*pui32TriPtr++ = *pui32StripPtr++;
    919 
    920 		for(unsigned int j = 1; j < pnStripLength[i]; ++j)
    921 		{
    922 			// Use two indices from previous triangle, flipping tri order alternately.
    923 			if(j & 0x01)
    924 			{
    925 				*pui32TriPtr++ = pui32StripPtr[-1];
    926 				*pui32TriPtr++ = pui32StripPtr[-2];
    927 			}
    928 			else
    929 			{
    930 				*pui32TriPtr++ = pui32StripPtr[-2];
    931 				*pui32TriPtr++ = pui32StripPtr[-1];
    932 			}
    933 
    934 			*pui32TriPtr++ = *pui32StripPtr++;
    935 		}
    936 	}
    937 
    938 	free(pui32Strips);
    939 	free(pnStripLength);
    940 }
    941 
    942 /*****************************************************************************
    943  End of file (PVRTTriStrip.cpp)
    944 *****************************************************************************/
    945 
    946