1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501 |
- /******************************************************************************
- @File PVRTGeometry.cpp
- @Title PVRTGeometry
- @Version
- @Copyright Copyright (C) Imagination Technologies Limited.
- @Platform Independant
- @Description Code to affect triangle mesh geometry.
- ******************************************************************************/
- /*****************************************************************************
- For each vertex with only one free triangle
- Start collecting triangles from there
- Add the triangle which gives the highest triangles/vertex number (extra tris usually come for free)
- When full, test against current best
- If markedly better tri/vtx, take new block
- If close-enough to prev tri/vtx, take block which closes the highest number of edges (and opens fewest)
- If not quite full, goto 1 to continue filling block
- If no block has been found, start at any free triangle and use resulting block
- Copy block to output, empty it and goto 1.
- *****************************************************************************/
- /****************************************************************************
- ** Build options
- ****************************************************************************/
- #undef PVRTRISORT_ENABLE_VERIFY_RESULTS
- /****************************************************************************
- ** Includes
- ****************************************************************************/
- #include <vector>
- #include <math.h>
- #include "PVRTGeometry.h"
- #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
- #include "PvrVGPBlockTest.h"
- #endif
- #include "PVRTGlobal.h"
- #include "PVRTContext.h"
- /****************************************************************************
- ** Structures
- ****************************************************************************/
- struct SVtx;
- /****************************************************************************
- @Function SEdg
- @Description Information about an "edge" - the shared boundary between two triangles
- ****************************************************************************/
- struct SEdg {
- const SVtx *psVtx[2]; // Identify the edge by the two vertices it joins
- int nTriNumFree; // Number of triangle using this edge
- };
- /****************************************************************************
- @Function STri
- @Description Information about a triangle
- ****************************************************************************/
- struct STri {
- const PVRTGEOMETRY_IDX *pwIdx; // Vertex indices forming this triangle
- SEdg *psEdg[3]; // Pointer to the three triangle edges
- bool bUsed;
- };
- /****************************************************************************
- @Function SVtx
- @Description Information about a vertex
- ****************************************************************************/
- struct SVtx {
- STri **psTri; // Allocated array of pointers to the triangles sharing this vertex
- int nTriNumTot; // Length of the above array
- int nTriNumFree; // Number of triangles unused in the above array
- SVtx **ppMeshPos; // Position in VtxByMesh list
- };
- /****************************************************************************
- @Function SMesh
- @Description Information about a mesh
- ****************************************************************************/
- struct SMesh {
- SVtx **ppVtx;
- int nVtxNum;
- };
- /****************************************************************************
- @Function CObject
- @Description Information about an object (i.e. collection of mesh's to form
- a single entity)
- ****************************************************************************/
- class CObject {
- public:
- STri *m_pTri; // Array of all the triangles in the mesh
- SEdg *m_pEdg; // Array of all the edges in the mesh
- SVtx *m_pVtx; // Array of all the vertices in a mesh
- int m_nTriNumFree;
- std::vector<SMesh> *m_pvMesh;
- std::vector<SMesh> m_vMeshLg;
- protected:
- int m_nVtxTot; // Total vertices in the object
- int m_nEdgTot; // Total edges in the object
- int m_nTriTot; // Total triangles in the object
- int m_nVtxLimit; // Maximum number of vertices a block can contain
- int m_nTriLimit; // Maximum number of triangles a block can contain
- SVtx **m_ppVtxByMesh;
- public:
- CObject(
- const PVRTGEOMETRY_IDX * const pwIdx,
- const int nVtxTot,
- const int nTriTot,
- const int nVtxLimit,
- const int nTriLimit);
- ~CObject();
- int GetVertexCount() const;
- int GetTriangleCount() const;
- void SplitMesh(
- SMesh * const pMesh,
- const int nVtxNum,
- SVtx ** const ppVtx);
- void ResizeMesh(
- const int nVtxNum,
- SVtx ** const ppVtx);
- protected:
- SEdg *BuildEdgeList(
- const SVtx * const pVtx0,
- const SVtx * const pVtx1);
- void CreateMeshList();
- };
- /****************************************************************************
- @Function CBlockOption
- @Description A possible group of polygons to use
- ****************************************************************************/
- struct CBlockOption {
- protected:
- struct SEdgeDelta {
- const SEdg *pEdg;
- int nRefCnt;
- };
- public:
- int nVtxNum; // Number of vertices in the block
- int nEdgNum; // Number of edges in the block
- int nTriNum; // Number of triangles in the block
- SVtx **psVtx; // Pointers to vertices
- protected:
- SEdgeDelta *psEdgeDelta;
- STri **psTri; // Pointers to triangles
- int m_nVtxLimit; // Maximum number of vertices a block can contain
- int m_nTriLimit; // Maximum number of triangles a block can contain
- public:
- ~CBlockOption();
- void Init(
- const int nVtxLimit,
- const int nTriLimit);
- void Copy(const CBlockOption * const pSrc);
- void Clear();
- void Output(
- PVRTGEOMETRY_IDX * const pwOut,
- int * const pnVtxCnt,
- int * const pnTriCnt,
- const CObject * const pOb) const;
- bool UsingVertex(const SVtx * const pVtx) const;
- bool Contains(const STri * const pTri) const;
- bool IsEmpty() const;
- bool IsFull() const;
- void AddVertex(SVtx * const pVtx);
- void AddVertexCheckDup(SVtx * const pVtx);
- void AddTriangleCheckDup(STri * const pTri);
- void AddEdgeCheckDup(const SEdg * const pEdg);
- void AddTriangle(STri * const pTri);
- void AddOneTriangle(
- STri * const pTri,
- const CObject * const pOb);
- int GetClosedEdgeDelta() const;
- bool IsBetterThan(const CBlockOption * const pCmp) const;
- void Add(
- const CBlockOption * const pSrc,
- const CObject * const pOb);
- void Add(
- const SMesh * const pMesh);
- };
- /****************************************************************************
- @Function CBlock
- @Description A model of a HW block (triangles and vertices)
- ****************************************************************************/
- class CBlock {
- protected:
- CBlockOption m_sOpt, m_sOptBest;
- int m_nVtxLimit; // Maximum number of vertices a block can contain
- int m_nTriLimit; // Maximum number of triangles a block can contain
- CBlockOption m_sJob0, m_sJob1; // Workspace: to find the best triangle to add
- public:
- CBlock(
- const int nBufferVtxLimit,
- const int nBufferTriLimit);
- void Clear();
- bool FillFrom(
- SMesh * const pMesh,
- SVtx * const pVtx,
- CObject * const pOb);
- int Fill(
- CObject * const pOb);
- void Output(
- PVRTGEOMETRY_IDX * const pwOut,
- int * const pnVtxCnt,
- int * const pnTriCnt,
- const CObject * const pOb) const;
- protected:
- bool AddBestTrianglesAppraise(
- CBlockOption * const pJob,
- const CObject * const pOb,
- const STri * const pTriAppraise);
- void AddBestTriangles(CObject * const pOb);
- };
- /****************************************************************************
- ** Local function prototypes
- ****************************************************************************/
- /****************************************************************************
- @Function CObject
- @Input pwIdx Array of indices
- @Input nVrxTot Total number of vertices
- @Input nTriTot Total number of triangles
- @Input nVtxLimit Max number of vertices a block can contain
- @Input nTriLimit Max number of triangles a block can contain
- @Description The class's constructor.
- ****************************************************************************/
- CObject::CObject(
- const PVRTGEOMETRY_IDX * const pwIdx,
- const int nVtxTot,
- const int nTriTot,
- const int nVtxLimit,
- const int nTriLimit)
- {
- int i;
- SVtx *pVtx0, *pVtx1, *pVtx2;
- m_nVtxLimit = nVtxLimit;
- m_nTriLimit = nTriLimit;
- m_pvMesh = new std::vector<SMesh>[nVtxLimit-2];
- _ASSERT(m_pvMesh);
- m_ppVtxByMesh = (SVtx**)calloc(nVtxTot, sizeof(*m_ppVtxByMesh));
- _ASSERT(m_ppVtxByMesh);
- m_nVtxTot = nVtxTot;
- m_nEdgTot = 0;
- m_nTriTot = nTriTot;
- m_nTriNumFree = m_nTriTot;
- m_pTri = (STri*)calloc(nTriTot, sizeof(*m_pTri));
- _ASSERT(m_pTri);
- m_pEdg = (SEdg*)calloc(nTriTot*3, sizeof(*m_pEdg)); // Allocate the maximum possible number of edges, though it should be far fewer than this
- _ASSERT(m_pEdg);
- m_pVtx = (SVtx*)calloc(nVtxTot, sizeof(*m_pVtx));
- _ASSERT(m_pVtx);
- // Run through triangles...
- for(i = 0; i < nTriTot; ++i) {
- pVtx0 = &m_pVtx[pwIdx[3*i+0]];
- pVtx1 = &m_pVtx[pwIdx[3*i+1]];
- pVtx2 = &m_pVtx[pwIdx[3*i+2]];
- // Mark each vertex for the number of times it's referenced
- ++pVtx0->nTriNumFree;
- ++pVtx1->nTriNumFree;
- ++pVtx2->nTriNumFree;
- // Build the edge list
- m_pTri[i].psEdg[0] = BuildEdgeList(pVtx0, pVtx1);
- m_pTri[i].psEdg[1] = BuildEdgeList(pVtx1, pVtx2);
- m_pTri[i].psEdg[2] = BuildEdgeList(pVtx2, pVtx0);
- }
- // Run through vertices, creating enough space for pointers to each triangle using this vertex
- for(i = 0; i < nVtxTot; ++i)
- m_pVtx[i].psTri = (STri**)calloc(m_pVtx[i].nTriNumFree, sizeof(*m_pVtx[i].psTri));
- // Run through triangles, marking each vertex used with a pointer to this tri
- for(i = 0; i < nTriTot; ++i) {
- pVtx0 = &m_pVtx[pwIdx[3*i+0]];
- pVtx1 = &m_pVtx[pwIdx[3*i+1]];
- pVtx2 = &m_pVtx[pwIdx[3*i+2]];
- pVtx0->psTri[pVtx0->nTriNumTot++] = &m_pTri[i];
- pVtx1->psTri[pVtx1->nTriNumTot++] = &m_pTri[i];
- pVtx2->psTri[pVtx2->nTriNumTot++] = &m_pTri[i];
- // Give each triangle a pointer to its indices
- m_pTri[i].pwIdx = &pwIdx[3*i];
- }
- #ifdef _DEBUG
- for(i = 0; i < nVtxTot; ++i) {
- _ASSERTE(m_pVtx[i].nTriNumFree == m_pVtx[i].nTriNumTot);
- }
- #endif
- CreateMeshList();
- }
- /****************************************************************************
- @Function ~CObject
- @Description Destructor
- ****************************************************************************/
- CObject::~CObject()
- {
- _ASSERT(m_nTriNumFree == 0);
- while(m_nVtxTot) {
- --m_nVtxTot;
- FREE(m_pVtx[m_nVtxTot].psTri);
- _ASSERTE(m_pVtx[m_nVtxTot].nTriNumFree == 0);
- _ASSERTE(m_pVtx[m_nVtxTot].ppMeshPos);
- }
- #ifdef _DEBUG
- while(m_nEdgTot) {
- --m_nEdgTot;
- _ASSERTE(m_pEdg[m_nEdgTot].nTriNumFree == 0);
- }
- while(m_nTriTot) {
- --m_nTriTot;
- _ASSERTE(m_pTri[m_nTriTot].bUsed);
- }
- #endif
- FREE(m_pTri);
- FREE(m_pEdg);
- FREE(m_pVtx);
- delete [] m_pvMesh;
- FREE(m_ppVtxByMesh);
- }
- /****************************************************************************
- @Function GetVertexCount
- @Return int
- @Description Return the vertex count
- ****************************************************************************/
- int CObject::GetVertexCount() const
- {
- return m_nVtxTot;
- }
- /****************************************************************************
- @Function GetTriangleCount
- @Return int
- @Description Return the triangle count
- ****************************************************************************/
- int CObject::GetTriangleCount() const
- {
- return m_nTriTot;
- }
- /****************************************************************************
- @Function BuildEdgeList
- @Input pVtx0 Edge 0
- @Input pVtx1 Edge 1
- @Return SEdg*
- @Description If the vertices that have been passed in are already used by an edge,
- the number of triangles sharing the edge is increased by one and a
- pointer to the edge is returned. If the edge is not already in the
- list, the edge is added to the list.
- ****************************************************************************/
- SEdg *CObject::BuildEdgeList(
- const SVtx * const pVtx0,
- const SVtx * const pVtx1)
- {
- SEdg *pEdg;
- const SVtx *pVtxL, *pVtxH;
- int i;
- pVtxL = pVtx0 < pVtx1 ? pVtx0 : pVtx1;
- pVtxH = pVtx0 > pVtx1 ? pVtx0 : pVtx1;
- // Do nothing if the edge already exists
- i = m_nEdgTot;
- while(i) {
- --i;
- pEdg = &m_pEdg[i];
- if(pEdg->psVtx[0] == pVtxL && pEdg->psVtx[1] == pVtxH)
- {
- ++pEdg->nTriNumFree;
- return pEdg;
- }
- }
- // Add the new edge
- _ASSERT(m_nEdgTot < m_nTriTot*3);
- pEdg = &m_pEdg[m_nEdgTot++];
- pEdg->psVtx[0] = pVtxL;
- pEdg->psVtx[1] = pVtxH;
- pEdg->nTriNumFree = 1;
- return pEdg;
- }
- /****************************************************************************
- @Function CreateMeshList
- @Description Creates the mesh list
- ****************************************************************************/
- void CObject::CreateMeshList()
- {
- SVtx **ppR, **ppW, *pVtx;
- STri *pTri;
- int i, j, k;
- SMesh sMesh;
- int nMeshCnt;
- nMeshCnt = 0;
- ppR = m_ppVtxByMesh;
- ppW = m_ppVtxByMesh;
- for(i = 0; i < m_nVtxTot; ++i) {
- pVtx = &m_pVtx[i];
- if(pVtx->ppMeshPos) {
- _ASSERT(pVtx->ppMeshPos < ppW);
- continue;
- }
- ++nMeshCnt;
- sMesh.ppVtx = ppW;
- *ppW = pVtx;
- pVtx->ppMeshPos = ppW;
- ++ppW;
- do {
- // Add all the vertices of all the triangles of *ppR to the list - unless they're already in there
- for(j = 0; j < (*ppR)->nTriNumTot; ++j) {
- pTri = (*ppR)->psTri[j];
- for(k = 0; k < 3; ++k) {
- pVtx = &m_pVtx[pTri->pwIdx[k]];
- if(pVtx->ppMeshPos) {
- _ASSERT(pVtx->ppMeshPos < ppW);
- continue;
- }
- *ppW = pVtx;
- pVtx->ppMeshPos = ppW;
- ++ppW;
- }
- }
- ++ppR;
- } while(ppR != ppW);
- sMesh.nVtxNum = (int)(ppR - sMesh.ppVtx);
- // _RPT2(_CRT_WARN, "CreateMeshList() mesh %d %dvtx\n", nMeshCnt, sMesh.nVtxNum);
- if(sMesh.nVtxNum >= 3)
- {
- if(sMesh.nVtxNum >= m_nVtxLimit)
- m_vMeshLg.push_back(sMesh);
- else
- m_pvMesh[sMesh.nVtxNum-3].push_back(sMesh);
- }
- else
- {
- /*
- Vertex is not used by any triangles; this may be because we're
- optimising a subset of the mesh (e.g. for bone batching).
- */
- _ASSERT(sMesh.nVtxNum == 1);
- }
- }
- _ASSERT(ppR == &m_ppVtxByMesh[m_nVtxTot]);
- _ASSERT(ppW == &m_ppVtxByMesh[m_nVtxTot]);
- // _RPT1(_CRT_WARN, "CreateMeshList() %d meshes\n", nMeshCnt);
- #ifdef _DEBUG
- /* for(i = 0; i < m_nVtxLimit-2; ++i)
- if(m_pvMesh[i].size())
- _RPT2(_CRT_WARN, "%d:%d ", i+3, m_pvMesh[i].size());
- _RPT1(_CRT_WARN, "lg:%d\n", m_vMeshLg.size());*/
- #endif
- }
- /****************************************************************************
- @Function SplitMesh
- @Input pMesh Pointer to mesh data
- @Input nVtxNum Number of vertices in the mesh?
- @Output ppVtx Array of vertices
- @Description Note: Ask Aaron
- ****************************************************************************/
- void CObject::SplitMesh(
- SMesh * const pMesh,
- const int nVtxNum,
- SVtx ** const ppVtx)
- {
- SVtx *pTmp;
- int i;
- SMesh sNew;
- _ASSERT(nVtxNum);
- for(i = 0; i < nVtxNum; ++i) {
- pTmp = pMesh->ppVtx[i]; // Keep a record of the old vtx that's already here
- pMesh->ppVtx[i] = ppVtx[i]; // Move the new vtx into place
- *ppVtx[i]->ppMeshPos = pTmp; // Move the old vtx into place
- pTmp->ppMeshPos = ppVtx[i]->ppMeshPos; // Tell the old vtx where it is now
- ppVtx[i]->ppMeshPos = &pMesh->ppVtx[i]; // Tell the new vtx where it is now
- _ASSERT(pMesh->ppVtx[i]->nTriNumFree);
- }
- sNew.nVtxNum = nVtxNum;
- sNew.ppVtx = pMesh->ppVtx;
- m_pvMesh[nVtxNum-3].push_back(sNew);
- pMesh->ppVtx = &pMesh->ppVtx[nVtxNum];
- pMesh->nVtxNum -= nVtxNum;
- if(pMesh->nVtxNum < m_nVtxLimit) {
- ResizeMesh(pMesh->nVtxNum, pMesh->ppVtx);
- m_vMeshLg.pop_back();
- #ifdef _DEBUG
- /* } else {
- for(i = 0; i < m_nVtxLimit-2; ++i)
- if(m_pvMesh[i].size())
- _RPT2(_CRT_WARN, "%d:%d ", i+3, m_pvMesh[i].size());
- _RPT1(_CRT_WARN, "lg:%d\n", m_vMeshLg.size());*/
- #endif
- }
- }
- /****************************************************************************
- @Function ResizeMesh
- @Input nVtxNum The size of the array of vertices being passed in
- @Input ppVtx Array of vertices
- @Description Note: Ask Aaron
- ****************************************************************************/
- void CObject::ResizeMesh(
- const int nVtxNum,
- SVtx ** const ppVtx)
- {
- SVtx **ppR, **ppW;
- SMesh sNew;
- int i;
- ppR = ppVtx;
- ppW = ppVtx;
- // Make a list of vertices that have unused triangles in their array of triangles
- for(i = 0; i < nVtxNum; ++i) {
- if((*ppR)->nTriNumFree) {
- (*ppW) = (*ppR);
- ++ppW;
- }
- ++ppR;
- }
- sNew.nVtxNum = (int)(ppW - ppVtx);
- _ASSERT(sNew.nVtxNum <= nVtxNum);
- // If any mesh still exists, add it to the relevant list
- if(sNew.nVtxNum) {
- _ASSERT(sNew.nVtxNum >= 3);
- _ASSERT(sNew.nVtxNum < m_nVtxLimit);
- sNew.ppVtx = ppVtx;
- m_pvMesh[sNew.nVtxNum-3].push_back(sNew);
- }
- #ifdef _DEBUG
- /* for(i = 0; i < m_nVtxLimit-2; ++i)
- if(m_pvMesh[i].size())
- _RPT2(_CRT_WARN, "%d:%d ", i+3, m_pvMesh[i].size());
- _RPT1(_CRT_WARN, "lg:%d\n", m_vMeshLg.size());*/
- #endif
- }
- /****************************************************************************
- @Function ~CBlockOption
- @Description Default destructor
- ****************************************************************************/
- CBlockOption::~CBlockOption()
- {
- FREE(psVtx);
- FREE(psTri);
- FREE(psEdgeDelta);
- }
- /****************************************************************************
- @Function Init
- @Input nVertexLimit The maximum number of vertices a block can contain
- @Input nTriLimit The maximum number of triangles a block can contain
- @Description Initialises the class
- ****************************************************************************/
- void CBlockOption::Init(
- const int nVtxLimit,
- const int nTriLimit)
- {
- m_nVtxLimit = nVtxLimit;
- m_nTriLimit = nTriLimit;
- psVtx = (SVtx**)malloc(nVtxLimit * sizeof(*psVtx));
- psTri = (STri**)malloc(nTriLimit * sizeof(*psTri));
- psEdgeDelta = (SEdgeDelta*)malloc(3 * nTriLimit * sizeof(*psEdgeDelta));
- }
- /****************************************************************************
- @Function Copy
- @Input pSrc Pointer to the source data
- @Description Overwrites the data in the current instance with the data from
- the input CBlockOption.
- ****************************************************************************/
- void CBlockOption::Copy(const CBlockOption * const pSrc)
- {
- nVtxNum = pSrc->nVtxNum;
- nEdgNum = pSrc->nEdgNum;
- nTriNum = pSrc->nTriNum;
- memcpy(psVtx, pSrc->psVtx, nVtxNum * sizeof(*psVtx));
- memcpy(psEdgeDelta, pSrc->psEdgeDelta, nEdgNum * sizeof(*psEdgeDelta));
- memcpy(psTri, pSrc->psTri, nTriNum * sizeof(*psTri));
- }
- /****************************************************************************
- @Function Clear
- @Description Sets the value of the number of vertices, edges and triangles
- to zero.
- ****************************************************************************/
- void CBlockOption::Clear()
- {
- nVtxNum = 0;
- nEdgNum = 0;
- nTriNum = 0;
- }
- /****************************************************************************
- @Function Output
- @Output pwOut Index output
- @Output pnVtxCnt Vertex count
- @Output pnTriCnt Triangle count
- @Modified pOb Pointer to an object
- @Description Outputs key information about the instance of CBlockOption
- ****************************************************************************/
- void CBlockOption::Output(
- PVRTGEOMETRY_IDX * const pwOut,
- int * const pnVtxCnt,
- int * const pnTriCnt,
- const CObject * const pOb) const
- {
- STri *pTri;
- int i, j;
- for(i = 0; i < nTriNum; ++i) {
- pTri = psTri[i];
- _ASSERT(!pTri->bUsed);
- for(j = 0; j < 3; ++j) {
- _ASSERT(pOb->m_pVtx[pTri->pwIdx[j]].nTriNumFree > 0);
- _ASSERT(pTri->psEdg[j]->nTriNumFree > 0);
- --pOb->m_pVtx[pTri->pwIdx[j]].nTriNumFree;
- --pTri->psEdg[j]->nTriNumFree;
- _ASSERT(pOb->m_pVtx[pTri->pwIdx[j]].nTriNumFree >= 0);
- _ASSERT(pTri->psEdg[j]->nTriNumFree >= 0);
- }
- pTri->bUsed = true;
- // Copy indices into output
- memcpy(&pwOut[3*i], pTri->pwIdx, 3 * sizeof(*pTri->pwIdx));
- }
- *pnVtxCnt = nVtxNum;
- *pnTriCnt = nTriNum;
- }
- /****************************************************************************
- @Function UsingVertex
- @Input pVtx Vertex to compare
- @Return bool True on success
- @Description Returns true if the supplied vertex is already being used
- in the block option.
- ****************************************************************************/
- bool CBlockOption::UsingVertex(
- const SVtx * const pVtx) const
- {
- int i;
- i = nVtxNum;
- while(i) {
- --i;
- if(psVtx[i] == pVtx)
- return true;
- }
- return false;
- }
- /****************************************************************************
- @Function Contains
- @Input pVtx Triangle to compare
- @Return bool True on success
- @Description Returns true if the supplied triangle is already being used
- in the block option.
- ****************************************************************************/
- bool CBlockOption::Contains(const STri * const pTri) const
- {
- int i;
- i = nTriNum;
- while(i) {
- --i;
- if(psTri[i] == pTri)
- return true;
- }
- return false;
- }
- /****************************************************************************
- @Function IsEmpty
- @Return bool True if the block option is empty
- @Description Returns true if the block option is empty.
- ****************************************************************************/
- bool CBlockOption::IsEmpty() const
- {
- return !(nVtxNum + nEdgNum + nTriNum);
- }
- /****************************************************************************
- @Function IsFull
- @Return bool True if the block option is full
- @Description Returns true if the block option is full.
- ****************************************************************************/
- bool CBlockOption::IsFull() const
- {
- return (m_nVtxLimit - nVtxNum) < 3 || nTriNum == m_nTriLimit;
- }
- /****************************************************************************
- @Function AddVertex
- @Input pVtx Vertex to add
- @Description Providing the current number of vertices is less than the
- maximum, the input vertex is added to the end of the array.
- ****************************************************************************/
- void CBlockOption::AddVertex(SVtx * const pVtx)
- {
- _ASSERT(nVtxNum < m_nVtxLimit);
- psVtx[nVtxNum++] = pVtx;
- }
- /****************************************************************************
- @Function AddVertexCheckDup
- @Input pVtx Vertex to add
- @Description Checks that the input vertex is not already contained in the
- vertex array. If it is new, it is added to the array.
- ****************************************************************************/
- void CBlockOption::AddVertexCheckDup(SVtx * const pVtx)
- {
- int i;
- for(i = 0; i < nVtxNum; ++i)
- if(psVtx[i] == pVtx)
- return;
- AddVertex(pVtx);
- }
- /****************************************************************************
- @Function AddTriangleCheckDup
- @Input pTri Triangle to add
- @Description Checks that the input triangle is not already contained in the
- triangle array. If it is new, it is added to the array.
- ****************************************************************************/
- void CBlockOption::AddTriangleCheckDup(STri * const pTri)
- {
- int i;
- for(i = 0; i < nTriNum; ++i)
- if(psTri[i] == pTri)
- return;
- _ASSERT(nTriNum < m_nTriLimit);
- psTri[nTriNum++] = pTri;
- }
- /****************************************************************************
- @Function AddEdgeCheckDup
- @Input pEdg Edge to add
- @Description Checks that the input edge is not already contained in the
- edge array. If it is new, it is added to the array.
- ****************************************************************************/
- void CBlockOption::AddEdgeCheckDup(const SEdg * const pEdg)
- {
- int i;
- for(i = 0; i < nEdgNum; ++i) {
- if(psEdgeDelta[i].pEdg == pEdg) {
- ++psEdgeDelta[i].nRefCnt;
- return;
- }
- }
- _ASSERT(nEdgNum < 3*m_nTriLimit);
- psEdgeDelta[nEdgNum].pEdg = pEdg;
- psEdgeDelta[nEdgNum].nRefCnt = 1;
- ++nEdgNum;
- }
- /****************************************************************************
- @Function AddTriangle
- @Input pTri Triangle to add
- @Description Providing the current number of triangles is less than the
- maximum, the input triangle is added to the end of the array.
- Once this has been done, the array of edges is updated.
- ****************************************************************************/
- // TODO: if this is only used to add fresh triangles, all edges must be added
- void CBlockOption::AddTriangle(STri * const pTri)
- {
- int i;
- _ASSERT(nTriNum < m_nTriLimit);
- psTri[nTriNum++] = pTri;
- // Keep a count of edges and the number of tris which share them
- for(i = 0; i < 3; ++i)
- AddEdgeCheckDup(pTri->psEdg[i]);
- }
- /****************************************************************************
- @Function AddOneTriangle
- @Input pTri Triangle to add
- @Input pOb Object to copy vertices from
- @Description Calls the AddTriangle function.
- Once this has been done, the array of vertices is updated.
- ****************************************************************************/
- // TODO: if this is only called to add a fresh start triangle, all vertices must be added
- void CBlockOption::AddOneTriangle(
- STri * const pTri,
- const CObject * const pOb)
- {
- int i;
- // Add the triangle to the block
- AddTriangle(pTri);
- // Add the vertices to the block
- for(i = 0; i < 3; ++i)
- AddVertexCheckDup(&pOb->m_pVtx[pTri->pwIdx[i]]);
- }
- /****************************************************************************
- @Function GetClosedEdgeDelta
- @Return int The delta value of closed edges
- @Description This method returns a value that represents the average state of
- the edges. If the value is greater than zero, the majority of
- edges are closed. If the value is less than zero, the majority
- of edges are open.
- ****************************************************************************/
- int CBlockOption::GetClosedEdgeDelta() const
- {
- int i, nDelta;
- nDelta = 0;
- for(i = 0; i < nEdgNum; ++i) {
- _ASSERT(psEdgeDelta[i].pEdg->nTriNumFree >= psEdgeDelta[i].nRefCnt);
- // Check how many tris will use the edge if these are taken away
- switch(psEdgeDelta[i].pEdg->nTriNumFree - psEdgeDelta[i].nRefCnt) {
- case 0:
- // If the edge was open, and is now closed, that's good
- if(psEdgeDelta[i].pEdg->nTriNumFree == 1)
- ++nDelta;
- break;
- case 1:
- // if the edge is now open, that's bad
- --nDelta;
- break;
- }
- }
- return nDelta;
- }
- /****************************************************************************
- @Function IsBetterThan
- @Input pCmp The block option to compare with
- @Return bool True if the current block option is best
- @Description Returns true if the current block option is better than the
- block option that has been passed in. Otherwise, it returns false.
- ****************************************************************************/
- bool CBlockOption::IsBetterThan(const CBlockOption * const pCmp) const
- {
- float fWorth0, fWorth1;
- int nClosed0, nClosed1;
- // Check "worth" - TrisAdded/VtxAdded
- fWorth0 = (float)nTriNum / (float)nVtxNum;
- fWorth1 = (float)pCmp->nTriNum / (float)pCmp->nVtxNum;
- nClosed0 = GetClosedEdgeDelta();
- nClosed1 = pCmp->GetClosedEdgeDelta();
- if(fabsf(fWorth0 - fWorth1) > 0.1f) {
- return fWorth0 > fWorth1;
- } else if(nClosed0 != nClosed1) {
- return nClosed0 > nClosed1;
- } else {
- return nTriNum > pCmp->nTriNum;
- }
- }
- /****************************************************************************
- @Function Add
- @Input pSrc The block option to add
- @Input pOb Object to use vertices from
- @Description Add's the input vertex and triangle data to the current block option
- ****************************************************************************/
- void CBlockOption::Add(
- const CBlockOption * const pSrc,
- const CObject * const pOb)
- {
- PVRT_UNREFERENCED_PARAMETER(pOb);
- int i;
- // Add vertices from job to block
- for(i = 0; i < pSrc->nVtxNum; ++i)
- AddVertexCheckDup(pSrc->psVtx[i]);
- // Add triangles from job to block
- for(i = 0; i < pSrc->nTriNum; ++i)
- AddTriangle(pSrc->psTri[i]);
- }
- /****************************************************************************
- @Function Add
- @Input pMesh The mesh to add
- @Description Add's the input mesh to the current block option
- ****************************************************************************/
- void CBlockOption::Add(
- const SMesh * const pMesh)
- {
- int i, j;
- SVtx *pVtx;
- for(i = 0; i < pMesh->nVtxNum; ++i) {
- pVtx = pMesh->ppVtx[i];
- AddVertexCheckDup(pVtx);
- for(j = 0; j < pVtx->nTriNumTot; ++j) {
- if(!pVtx->psTri[j]->bUsed)
- AddTriangleCheckDup(pVtx->psTri[j]);
- }
- }
- }
- /****************************************************************************
- @Function CBlock
- @Description Default constructor
- ****************************************************************************/
- CBlock::CBlock(
- const int nBufferVtxLimit,
- const int nBufferTriLimit)
- {
- m_nVtxLimit = nBufferVtxLimit;
- m_nTriLimit = nBufferTriLimit;
- m_sOpt.Init(m_nVtxLimit, m_nTriLimit);
- m_sOptBest.Init(m_nVtxLimit, m_nTriLimit);
- // Intialise "job" blocks
- m_sJob0.Init(3, m_nTriLimit);
- m_sJob1.Init(3, m_nTriLimit);
- }
- /****************************************************************************
- @Function Clear
- @Description Clears the current and best block options
- ****************************************************************************/
- void CBlock::Clear()
- {
- m_sOpt.Clear();
- m_sOptBest.Clear();
- }
- /****************************************************************************
- @Function Output
- @Output pwOut Index output
- @Output pnVtxCnt Vertex count
- @Output pnTriCnt Triangle count
- @Modified pOb Pointer to an object
- @Description Outputs key information about the instance of CBlockOption
- ****************************************************************************/
- void CBlock::Output(
- PVRTGEOMETRY_IDX * const pwOut,
- int * const pnVtxCnt,
- int * const pnTriCnt,
- const CObject * const pOb) const
- {
- m_sOptBest.Output(pwOut, pnVtxCnt, pnTriCnt, pOb);
- }
- /****************************************************************************
- @Function AddBestTrianglesAppraise
- @Modified pJob The block object to alter
- @Input pOb The object
- @Input pTriAppraise The triangle to appraise
- @Return bool
- @Description Uses the input object and triangle to create a new block option.
- ****************************************************************************/
- bool CBlock::AddBestTrianglesAppraise(
- CBlockOption * const pJob,
- const CObject * const pOb,
- const STri * const pTriAppraise)
- {
- SVtx *pVtx;
- STri *pTri;
- int i, j;
- pJob->Clear();
- // Add vertices
- for(i = 0; i < 3; ++i) {
- pVtx = &pOb->m_pVtx[pTriAppraise->pwIdx[i]];
- if(!m_sOpt.UsingVertex(pVtx))
- pJob->AddVertex(pVtx);
- }
- if(pJob->nVtxNum > (m_nVtxLimit-m_sOpt.nVtxNum))
- return false;
- // Add triangles referenced by each vertex
- for(i = 0; i < 3; ++i) {
- pVtx = &pOb->m_pVtx[pTriAppraise->pwIdx[i]];
- _ASSERT(pVtx->nTriNumFree >= 1);
- _ASSERT(pVtx->nTriNumFree <= pVtx->nTriNumTot);
- for(j = 0; j < pVtx->nTriNumTot; ++j) {
- if(pJob->nTriNum >= (m_nTriLimit-m_sOpt.nTriNum))
- break;
- pTri = pVtx->psTri[j];
- // Don't count the same triangle twice!
- if(pTri->bUsed || m_sOpt.Contains(pTri) || pJob->Contains(pTri))
- continue;
- // If all the triangle's vertices are or will be in the block, then increase nTri
- if(
- (
- pTri->pwIdx[0] == pTriAppraise->pwIdx[0] ||
- pTri->pwIdx[0] == pTriAppraise->pwIdx[1] ||
- pTri->pwIdx[0] == pTriAppraise->pwIdx[2] ||
- m_sOpt.UsingVertex(&pOb->m_pVtx[pTri->pwIdx[0]])
- ) && (
- pTri->pwIdx[1] == pTriAppraise->pwIdx[0] ||
- pTri->pwIdx[1] == pTriAppraise->pwIdx[1] ||
- pTri->pwIdx[1] == pTriAppraise->pwIdx[2] ||
- m_sOpt.UsingVertex(&pOb->m_pVtx[pTri->pwIdx[1]])
- ) && (
- pTri->pwIdx[2] == pTriAppraise->pwIdx[0] ||
- pTri->pwIdx[2] == pTriAppraise->pwIdx[1] ||
- pTri->pwIdx[2] == pTriAppraise->pwIdx[2] ||
- m_sOpt.UsingVertex(&pOb->m_pVtx[pTri->pwIdx[2]])
- )
- )
- {
- pJob->AddTriangle(pTri);
- }
- }
- }
- _ASSERT(pJob->nTriNum);
- _ASSERT(pJob->nTriNum <= (m_nTriLimit-m_sOpt.nTriNum));
- return true;
- }
- /****************************************************************************
- @Function AddBestTriangles
- @Input pOb The object
- @Description Finds the best triangles and adds them to the current block option (m_sOpt)
- ****************************************************************************/
- void CBlock::AddBestTriangles(CObject * const pOb)
- {
- int i, j;
- const SVtx *pVtx;
- STri *pTri;
- CBlockOption *pJob, *pJobBest;
- pJob = &m_sJob0;
- do {
- pJobBest = 0;
- for(i = 0; i < m_sOpt.nVtxNum; ++i) {
- pVtx = m_sOpt.psVtx[i];
- if(!pVtx->nTriNumFree)
- continue;
- for(j = 0; j < pVtx->nTriNumTot; ++j) {
- pTri = pVtx->psTri[j];
- if(pTri->bUsed || m_sOpt.Contains(pTri))
- continue;
- // Find out how many triangles and vertices this tri adds
- if(!AddBestTrianglesAppraise(pJob, pOb, pTri))
- continue;
- if(!pJobBest || pJob->IsBetterThan(pJobBest)) {
- pJobBest = pJob;
- pJob = (pJob == &m_sJob0 ? &m_sJob1 : &m_sJob0);
- }
- }
- }
- if(pJobBest) {
- m_sOpt.Add(pJobBest, pOb);
- }
- } while(pJobBest && m_nTriLimit != m_sOpt.nTriNum);
- }
- /****************************************************************************
- @Function FillFrom
- @Input pMesh Mesh to fill with
- @Input pVtx Vertex to fill with
- @Input pOb Object to fill with
- @Return bool Returns true if the current block option isn't full
- @Description Returns TRUE if Fill() needs to be called again - i.e. blockOption is already filled
- ****************************************************************************/
- bool CBlock::FillFrom(
- SMesh * const pMesh,
- SVtx * const pVtx,
- CObject * const pOb)
- {
- // Let's try starting from this vertex then
- _ASSERT(pVtx->nTriNumFree);
- m_sOpt.Clear();
- m_sOpt.AddVertex(pVtx);
- AddBestTriangles(pOb);
- if(m_sOpt.IsFull()) {
- if(m_sOptBest.IsEmpty() || m_sOpt.IsBetterThan(&m_sOptBest))
- m_sOptBest.Copy(&m_sOpt);
- return false;
- }
- else
- {
- _ASSERT(!m_sOpt.IsEmpty());
- pOb->SplitMesh(pMesh, m_sOpt.nVtxNum, m_sOpt.psVtx); // Split the sub-mesh into its own mesh
- return true;
- }
- }
- /****************************************************************************
- @Function Fill
- @Input pOb Object to fill with
- @Return int -1 if the block if the best option is already full
- @Description Note: Ask Aaron
- ****************************************************************************/
- int CBlock::Fill(
- CObject * const pOb)
- {
- SVtx *pVtx;
- int i;
- SMesh *pMesh;
- /*
- Build blocks from the large meshes
- */
- if(!pOb->m_vMeshLg.empty()) {
- pMesh = &pOb->m_vMeshLg.back();
- // _RPT1(_CRT_WARN, "Fill() using large with %d vtx\n", pMesh->nVtxNum);
- // Find the vertex with the fewest unused triangles
- for(i = 0; i < pMesh->nVtxNum; ++i) {
- pVtx = pMesh->ppVtx[i];
- if(pVtx->nTriNumFree == 1) {
- if(FillFrom(pMesh, pVtx, pOb))
- return Fill(pOb);
- }
- }
- if(m_sOptBest.IsEmpty()) {
- // Just start from any old vertex
- for(i = 0; i < pMesh->nVtxNum; ++i) {
- pVtx = pMesh->ppVtx[i];
- if(pVtx->nTriNumFree) {
- if(FillFrom(pMesh, pVtx, pOb))
- return Fill(pOb);
- break;
- }
- }
- if(m_sOptBest.IsEmpty()) {
- pOb->m_vMeshLg.pop_back(); // Delete the mesh from the list
- return Fill(pOb);
- }
- }
- if(m_sOptBest.IsFull())
- return -1;
- }
- /*
- Match together the small meshes into blocks
- */
- _ASSERT(m_sOptBest.IsEmpty());
- i = m_nVtxLimit - m_sOptBest.nVtxNum - 3;
- // _RPT0(_CRT_WARN, "Fill() grouping small ");
- // Starting with the largest meshes, lump them into this block
- while(i >= 0 && (m_nVtxLimit - m_sOptBest.nVtxNum) >= 3) {
- if(pOb->m_pvMesh[i].empty()) {
- --i;
- continue;
- }
- pMesh = &pOb->m_pvMesh[i].back();
- m_sOptBest.Add(pMesh);
- // _RPT1(_CRT_WARN, "+%d", pMesh->nVtxNum);
- pOb->m_pvMesh[i].pop_back();
- i = PVRT_MIN(i, m_nVtxLimit - m_sOptBest.nVtxNum - 3);
- }
- // If there's any space left in this block (and clearly there are no blocks
- // just the right size to fit) then take SOME of the largest block available.
- if(!m_sOptBest.IsFull()) {
- m_sOpt.Copy(&m_sOptBest);
- // Note: This loop purposely does not check m_pvMesh[0] - any block
- // which is looking to grab more geometry would have already sucked
- // up those meshes
- for(i = (m_nVtxLimit-3); i; --i) {
- if(!pOb->m_pvMesh[i].empty()) {
- pMesh = &pOb->m_pvMesh[i].back();
- _ASSERT(pMesh->ppVtx[0]->nTriNumFree);
- _ASSERT(!m_sOpt.UsingVertex(pMesh->ppVtx[0]));
- m_sOpt.AddVertex(pMesh->ppVtx[0]);
- // _RPT1(_CRT_WARN, "(+%d)\n", pMesh->nVtxNum);
- AddBestTriangles(pOb);
- m_sOptBest.Copy(&m_sOpt);
- _ASSERT(m_sOptBest.IsFull());
- return i;
- }
- }
- }
- // _RPT0(_CRT_WARN, "\n");
- return -1;
- }
- /****************************************************************************
- ** Local functions
- ****************************************************************************/
- /****************************************************************************
- @Function Fill
- @Input pVtxData Vertex data
- @Input pwIdx Index array
- @Input nStride Stride
- @Input nVertNum Number of vertices
- @Input nIdxNum Number of indices
- @Description Sorts the vertices.
- ****************************************************************************/
- static void SortVertices(
- void * const pVtxData,
- PVRTGEOMETRY_IDX * const pwIdx,
- const int nStride,
- const int nVertNum,
- const int nIdxNum)
- {
- void *pVtxNew;
- int *pnVtxDest;
- int i;
- PVRTGEOMETRY_IDX wNext;
- pVtxNew = malloc(nVertNum * nStride);
- _ASSERT(pVtxNew);
- pnVtxDest = (int*)malloc(nVertNum * sizeof(*pnVtxDest));
- _ASSERT(pnVtxDest);
- wNext = 0;
- // Default all indices to an invalid number
- for(i = 0; i < nVertNum; ++i)
- pnVtxDest[i] = -1;
- // Let's get on with it then.
- for(i = 0; i < nIdxNum; ++i) {
- if(pnVtxDest[pwIdx[i]] == -1) {
- _ASSERT((int) wNext < nVertNum);
- memcpy((char*)pVtxNew+(wNext*nStride), (char*)pVtxData+(pwIdx[i]*nStride), nStride);
- pnVtxDest[pwIdx[i]] = wNext++;
- }
- pwIdx[i] = pnVtxDest[pwIdx[i]];
- }
- /*
- This assert will fail if sorting a sub-set of the triangles (e.g. if
- the mesh is bone-batched).
- In that situation vertex sorting should be performed only once after
- all the tri sorting is finished, not per tri-sort.
- */
- _ASSERT((int) wNext == nVertNum);
- memcpy(pVtxData, pVtxNew, nVertNum * nStride);
- FREE(pnVtxDest);
- FREE(pVtxNew);
- }
- /****************************************************************************
- ** Functions
- ****************************************************************************/
- /*!***************************************************************************
- @Function PVRTGeometrySort
- @Modified pVtxData Pointer to array of vertices
- @Modified pwIdx Pointer to array of indices
- @Input nStride Size of a vertex (in bytes)
- @Input nVertNum Number of vertices. Length of pVtxData array
- @Input nTriNum Number of triangles. Length of pwIdx array is 3* this
- @Input nBufferVtxLimit Number of vertices that can be stored in a buffer
- @Input nBufferTriLimit Number of triangles that can be stored in a buffer
- @Input dwFlags PVRTGEOMETRY_SORT_* flags
- @Description Triangle sorter
- *****************************************************************************/
- void PVRTGeometrySort(
- void * const pVtxData,
- PVRTGEOMETRY_IDX * const pwIdx,
- const int nStride,
- const int nVertNum,
- const int nTriNum,
- const int nBufferVtxLimit,
- const int nBufferTriLimit,
- const unsigned int dwFlags)
- {
- CObject sOb(pwIdx, nVertNum, nTriNum, nBufferVtxLimit, nBufferTriLimit);
- CBlock sBlock(nBufferVtxLimit, nBufferTriLimit);
- PVRTGEOMETRY_IDX *pwIdxOut;
- int nTriCnt, nVtxCnt;
- int nOutTriCnt, nOutVtxCnt, nOutBlockCnt;
- int nMeshToResize;
- #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
- int i;
- int pnBlockTriCnt[PVRVGPBLOCKTEST_MAX_BLOCKS];
- SVGPModel sVGPMdlBefore;
- SVGPModel sVGPMdlAfter;
- #endif
- if(dwFlags & PVRTGEOMETRY_SORT_VERTEXCACHE) {
- #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
- VGP590Test(&sVGPMdlBefore, pwIdx, nTriNum);
- _RPT4(_CRT_WARN, "OptimiseTriListPVR() Before: Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nTriNum, sVGPMdlBefore.nVtxCnt, (float)sVGPMdlBefore.nVtxCnt / (float)nTriNum, sVGPMdlBefore.nBlockCnt);
- #endif
- pwIdxOut = (PVRTGEOMETRY_IDX*)malloc(nTriNum * 3 * sizeof(*pwIdxOut));
- _ASSERT(pwIdxOut);
- // Sort geometry into blocks
- nOutTriCnt = 0;
- nOutVtxCnt = 0;
- nOutBlockCnt = 0;
- do {
- // Clear & fill the block
- sBlock.Clear();
- nMeshToResize = sBlock.Fill(&sOb);
- // Copy indices into output
- sBlock.Output(&pwIdxOut[3*nOutTriCnt], &nVtxCnt, &nTriCnt, &sOb);
- sOb.m_nTriNumFree -= nTriCnt;
- nOutTriCnt += nTriCnt;
- if(nMeshToResize >= 0) {
- SMesh *pMesh;
- _ASSERT(nMeshToResize <= (nBufferVtxLimit-3));
- pMesh = &sOb.m_pvMesh[nMeshToResize].back();
- sOb.ResizeMesh(pMesh->nVtxNum, pMesh->ppVtx);
- sOb.m_pvMesh[nMeshToResize].pop_back();
- }
- _ASSERT(nVtxCnt <= nBufferVtxLimit);
- _ASSERT(nTriCnt <= nBufferTriLimit);
- #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
- _ASSERT(nOutBlockCnt < PVRVGPBLOCKTEST_MAX_BLOCKS);
- pnBlockTriCnt[nOutBlockCnt] = nTriCnt;
- #endif
- nOutVtxCnt += nVtxCnt;
- nOutBlockCnt++;
- // _RPT4(_CRT_WARN, "%d/%d tris (+%d), %d blocks\n", nOutTriCnt, nTriNum, nTriCnt, nOutBlockCnt);
- _ASSERT(nTriCnt == nBufferTriLimit || (nBufferVtxLimit - nVtxCnt) < 3 || nOutTriCnt == nTriNum);
- } while(nOutTriCnt < nTriNum);
- _ASSERT(nOutTriCnt == nTriNum);
- // The following will fail if optimising a subset of the mesh (e.g. a bone batching)
- //_ASSERT(nOutVtxCnt >= nVertNum);
- // Done!
- memcpy(pwIdx, pwIdxOut, nTriNum * 3 * sizeof(*pwIdx));
- FREE(pwIdxOut);
- _RPT3(_CRT_WARN, "OptimiseTriListPVR() In: Tri: %d, Vtx: %d, vtx/tri=%f\n", nTriNum, nVertNum, (float)nVertNum / (float)nTriNum);
- _RPT4(_CRT_WARN, "OptimiseTriListPVR() HW: Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nOutTriCnt, nOutVtxCnt, (float)nOutVtxCnt / (float)nOutTriCnt, nOutBlockCnt);
- #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
- VGP590Test(&sVGPMdlAfter, pwIdx, nTriNum);
- _RPT4(_CRT_WARN, "OptimiseTriListPVR() After : Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nTriNum, sVGPMdlAfter.nVtxCnt, (float)sVGPMdlAfter.nVtxCnt / (float)nTriNum, sVGPMdlAfter.nBlockCnt);
- _ASSERTE(sVGPMdlAfter.nVtxCnt <= sVGPMdlBefore.nVtxCnt);
- _ASSERTE(sVGPMdlAfter.nBlockCnt <= sVGPMdlBefore.nBlockCnt);
- for(i = 0; i < nOutBlockCnt; ++i) {
- _ASSERT(pnBlockTriCnt[i] == sVGPMdlAfter.pnBlockTriCnt[i]);
- }
- #endif
- }
- if(!(dwFlags & PVRTGEOMETRY_SORT_IGNOREVERTS)) {
- // Re-order the vertices so maybe they're accessed in a more linear
- // manner. Should cut page-breaks on the initial memory read of
- // vertices. Affects both the order of vertices, and the values
- // of indices, but the triangle order is unchanged.
- SortVertices(pVtxData, pwIdx, nStride, nVertNum, nTriNum*3);
- }
- }
- /*****************************************************************************
- End of file (PVRTGeometry.cpp)
- *****************************************************************************/
|