PVRTGeometry.cpp 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501
  1. /******************************************************************************
  2. @File PVRTGeometry.cpp
  3. @Title PVRTGeometry
  4. @Version
  5. @Copyright Copyright (C) Imagination Technologies Limited.
  6. @Platform Independant
  7. @Description Code to affect triangle mesh geometry.
  8. ******************************************************************************/
  9. /*****************************************************************************
  10. For each vertex with only one free triangle
  11. Start collecting triangles from there
  12. Add the triangle which gives the highest triangles/vertex number (extra tris usually come for free)
  13. When full, test against current best
  14. If markedly better tri/vtx, take new block
  15. If close-enough to prev tri/vtx, take block which closes the highest number of edges (and opens fewest)
  16. If not quite full, goto 1 to continue filling block
  17. If no block has been found, start at any free triangle and use resulting block
  18. Copy block to output, empty it and goto 1.
  19. *****************************************************************************/
  20. /****************************************************************************
  21. ** Build options
  22. ****************************************************************************/
  23. #undef PVRTRISORT_ENABLE_VERIFY_RESULTS
  24. /****************************************************************************
  25. ** Includes
  26. ****************************************************************************/
  27. #include <vector>
  28. #include <math.h>
  29. #include "PVRTGeometry.h"
  30. #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
  31. #include "PvrVGPBlockTest.h"
  32. #endif
  33. #include "PVRTGlobal.h"
  34. #include "PVRTContext.h"
  35. /****************************************************************************
  36. ** Structures
  37. ****************************************************************************/
  38. struct SVtx;
  39. /****************************************************************************
  40. @Function SEdg
  41. @Description Information about an "edge" - the shared boundary between two triangles
  42. ****************************************************************************/
  43. struct SEdg {
  44. const SVtx *psVtx[2]; // Identify the edge by the two vertices it joins
  45. int nTriNumFree; // Number of triangle using this edge
  46. };
  47. /****************************************************************************
  48. @Function STri
  49. @Description Information about a triangle
  50. ****************************************************************************/
  51. struct STri {
  52. const PVRTGEOMETRY_IDX *pwIdx; // Vertex indices forming this triangle
  53. SEdg *psEdg[3]; // Pointer to the three triangle edges
  54. bool bUsed;
  55. };
  56. /****************************************************************************
  57. @Function SVtx
  58. @Description Information about a vertex
  59. ****************************************************************************/
  60. struct SVtx {
  61. STri **psTri; // Allocated array of pointers to the triangles sharing this vertex
  62. int nTriNumTot; // Length of the above array
  63. int nTriNumFree; // Number of triangles unused in the above array
  64. SVtx **ppMeshPos; // Position in VtxByMesh list
  65. };
  66. /****************************************************************************
  67. @Function SMesh
  68. @Description Information about a mesh
  69. ****************************************************************************/
  70. struct SMesh {
  71. SVtx **ppVtx;
  72. int nVtxNum;
  73. };
  74. /****************************************************************************
  75. @Function CObject
  76. @Description Information about an object (i.e. collection of mesh's to form
  77. a single entity)
  78. ****************************************************************************/
  79. class CObject {
  80. public:
  81. STri *m_pTri; // Array of all the triangles in the mesh
  82. SEdg *m_pEdg; // Array of all the edges in the mesh
  83. SVtx *m_pVtx; // Array of all the vertices in a mesh
  84. int m_nTriNumFree;
  85. std::vector<SMesh> *m_pvMesh;
  86. std::vector<SMesh> m_vMeshLg;
  87. protected:
  88. int m_nVtxTot; // Total vertices in the object
  89. int m_nEdgTot; // Total edges in the object
  90. int m_nTriTot; // Total triangles in the object
  91. int m_nVtxLimit; // Maximum number of vertices a block can contain
  92. int m_nTriLimit; // Maximum number of triangles a block can contain
  93. SVtx **m_ppVtxByMesh;
  94. public:
  95. CObject(
  96. const PVRTGEOMETRY_IDX * const pwIdx,
  97. const int nVtxTot,
  98. const int nTriTot,
  99. const int nVtxLimit,
  100. const int nTriLimit);
  101. ~CObject();
  102. int GetVertexCount() const;
  103. int GetTriangleCount() const;
  104. void SplitMesh(
  105. SMesh * const pMesh,
  106. const int nVtxNum,
  107. SVtx ** const ppVtx);
  108. void ResizeMesh(
  109. const int nVtxNum,
  110. SVtx ** const ppVtx);
  111. protected:
  112. SEdg *BuildEdgeList(
  113. const SVtx * const pVtx0,
  114. const SVtx * const pVtx1);
  115. void CreateMeshList();
  116. };
  117. /****************************************************************************
  118. @Function CBlockOption
  119. @Description A possible group of polygons to use
  120. ****************************************************************************/
  121. struct CBlockOption {
  122. protected:
  123. struct SEdgeDelta {
  124. const SEdg *pEdg;
  125. int nRefCnt;
  126. };
  127. public:
  128. int nVtxNum; // Number of vertices in the block
  129. int nEdgNum; // Number of edges in the block
  130. int nTriNum; // Number of triangles in the block
  131. SVtx **psVtx; // Pointers to vertices
  132. protected:
  133. SEdgeDelta *psEdgeDelta;
  134. STri **psTri; // Pointers to triangles
  135. int m_nVtxLimit; // Maximum number of vertices a block can contain
  136. int m_nTriLimit; // Maximum number of triangles a block can contain
  137. public:
  138. ~CBlockOption();
  139. void Init(
  140. const int nVtxLimit,
  141. const int nTriLimit);
  142. void Copy(const CBlockOption * const pSrc);
  143. void Clear();
  144. void Output(
  145. PVRTGEOMETRY_IDX * const pwOut,
  146. int * const pnVtxCnt,
  147. int * const pnTriCnt,
  148. const CObject * const pOb) const;
  149. bool UsingVertex(const SVtx * const pVtx) const;
  150. bool Contains(const STri * const pTri) const;
  151. bool IsEmpty() const;
  152. bool IsFull() const;
  153. void AddVertex(SVtx * const pVtx);
  154. void AddVertexCheckDup(SVtx * const pVtx);
  155. void AddTriangleCheckDup(STri * const pTri);
  156. void AddEdgeCheckDup(const SEdg * const pEdg);
  157. void AddTriangle(STri * const pTri);
  158. void AddOneTriangle(
  159. STri * const pTri,
  160. const CObject * const pOb);
  161. int GetClosedEdgeDelta() const;
  162. bool IsBetterThan(const CBlockOption * const pCmp) const;
  163. void Add(
  164. const CBlockOption * const pSrc,
  165. const CObject * const pOb);
  166. void Add(
  167. const SMesh * const pMesh);
  168. };
  169. /****************************************************************************
  170. @Function CBlock
  171. @Description A model of a HW block (triangles and vertices)
  172. ****************************************************************************/
  173. class CBlock {
  174. protected:
  175. CBlockOption m_sOpt, m_sOptBest;
  176. int m_nVtxLimit; // Maximum number of vertices a block can contain
  177. int m_nTriLimit; // Maximum number of triangles a block can contain
  178. CBlockOption m_sJob0, m_sJob1; // Workspace: to find the best triangle to add
  179. public:
  180. CBlock(
  181. const int nBufferVtxLimit,
  182. const int nBufferTriLimit);
  183. void Clear();
  184. bool FillFrom(
  185. SMesh * const pMesh,
  186. SVtx * const pVtx,
  187. CObject * const pOb);
  188. int Fill(
  189. CObject * const pOb);
  190. void Output(
  191. PVRTGEOMETRY_IDX * const pwOut,
  192. int * const pnVtxCnt,
  193. int * const pnTriCnt,
  194. const CObject * const pOb) const;
  195. protected:
  196. bool AddBestTrianglesAppraise(
  197. CBlockOption * const pJob,
  198. const CObject * const pOb,
  199. const STri * const pTriAppraise);
  200. void AddBestTriangles(CObject * const pOb);
  201. };
  202. /****************************************************************************
  203. ** Local function prototypes
  204. ****************************************************************************/
  205. /****************************************************************************
  206. @Function CObject
  207. @Input pwIdx Array of indices
  208. @Input nVrxTot Total number of vertices
  209. @Input nTriTot Total number of triangles
  210. @Input nVtxLimit Max number of vertices a block can contain
  211. @Input nTriLimit Max number of triangles a block can contain
  212. @Description The class's constructor.
  213. ****************************************************************************/
  214. CObject::CObject(
  215. const PVRTGEOMETRY_IDX * const pwIdx,
  216. const int nVtxTot,
  217. const int nTriTot,
  218. const int nVtxLimit,
  219. const int nTriLimit)
  220. {
  221. int i;
  222. SVtx *pVtx0, *pVtx1, *pVtx2;
  223. m_nVtxLimit = nVtxLimit;
  224. m_nTriLimit = nTriLimit;
  225. m_pvMesh = new std::vector<SMesh>[nVtxLimit-2];
  226. _ASSERT(m_pvMesh);
  227. m_ppVtxByMesh = (SVtx**)calloc(nVtxTot, sizeof(*m_ppVtxByMesh));
  228. _ASSERT(m_ppVtxByMesh);
  229. m_nVtxTot = nVtxTot;
  230. m_nEdgTot = 0;
  231. m_nTriTot = nTriTot;
  232. m_nTriNumFree = m_nTriTot;
  233. m_pTri = (STri*)calloc(nTriTot, sizeof(*m_pTri));
  234. _ASSERT(m_pTri);
  235. m_pEdg = (SEdg*)calloc(nTriTot*3, sizeof(*m_pEdg)); // Allocate the maximum possible number of edges, though it should be far fewer than this
  236. _ASSERT(m_pEdg);
  237. m_pVtx = (SVtx*)calloc(nVtxTot, sizeof(*m_pVtx));
  238. _ASSERT(m_pVtx);
  239. // Run through triangles...
  240. for(i = 0; i < nTriTot; ++i) {
  241. pVtx0 = &m_pVtx[pwIdx[3*i+0]];
  242. pVtx1 = &m_pVtx[pwIdx[3*i+1]];
  243. pVtx2 = &m_pVtx[pwIdx[3*i+2]];
  244. // Mark each vertex for the number of times it's referenced
  245. ++pVtx0->nTriNumFree;
  246. ++pVtx1->nTriNumFree;
  247. ++pVtx2->nTriNumFree;
  248. // Build the edge list
  249. m_pTri[i].psEdg[0] = BuildEdgeList(pVtx0, pVtx1);
  250. m_pTri[i].psEdg[1] = BuildEdgeList(pVtx1, pVtx2);
  251. m_pTri[i].psEdg[2] = BuildEdgeList(pVtx2, pVtx0);
  252. }
  253. // Run through vertices, creating enough space for pointers to each triangle using this vertex
  254. for(i = 0; i < nVtxTot; ++i)
  255. m_pVtx[i].psTri = (STri**)calloc(m_pVtx[i].nTriNumFree, sizeof(*m_pVtx[i].psTri));
  256. // Run through triangles, marking each vertex used with a pointer to this tri
  257. for(i = 0; i < nTriTot; ++i) {
  258. pVtx0 = &m_pVtx[pwIdx[3*i+0]];
  259. pVtx1 = &m_pVtx[pwIdx[3*i+1]];
  260. pVtx2 = &m_pVtx[pwIdx[3*i+2]];
  261. pVtx0->psTri[pVtx0->nTriNumTot++] = &m_pTri[i];
  262. pVtx1->psTri[pVtx1->nTriNumTot++] = &m_pTri[i];
  263. pVtx2->psTri[pVtx2->nTriNumTot++] = &m_pTri[i];
  264. // Give each triangle a pointer to its indices
  265. m_pTri[i].pwIdx = &pwIdx[3*i];
  266. }
  267. #ifdef _DEBUG
  268. for(i = 0; i < nVtxTot; ++i) {
  269. _ASSERTE(m_pVtx[i].nTriNumFree == m_pVtx[i].nTriNumTot);
  270. }
  271. #endif
  272. CreateMeshList();
  273. }
  274. /****************************************************************************
  275. @Function ~CObject
  276. @Description Destructor
  277. ****************************************************************************/
  278. CObject::~CObject()
  279. {
  280. _ASSERT(m_nTriNumFree == 0);
  281. while(m_nVtxTot) {
  282. --m_nVtxTot;
  283. FREE(m_pVtx[m_nVtxTot].psTri);
  284. _ASSERTE(m_pVtx[m_nVtxTot].nTriNumFree == 0);
  285. _ASSERTE(m_pVtx[m_nVtxTot].ppMeshPos);
  286. }
  287. #ifdef _DEBUG
  288. while(m_nEdgTot) {
  289. --m_nEdgTot;
  290. _ASSERTE(m_pEdg[m_nEdgTot].nTriNumFree == 0);
  291. }
  292. while(m_nTriTot) {
  293. --m_nTriTot;
  294. _ASSERTE(m_pTri[m_nTriTot].bUsed);
  295. }
  296. #endif
  297. FREE(m_pTri);
  298. FREE(m_pEdg);
  299. FREE(m_pVtx);
  300. delete [] m_pvMesh;
  301. FREE(m_ppVtxByMesh);
  302. }
  303. /****************************************************************************
  304. @Function GetVertexCount
  305. @Return int
  306. @Description Return the vertex count
  307. ****************************************************************************/
  308. int CObject::GetVertexCount() const
  309. {
  310. return m_nVtxTot;
  311. }
  312. /****************************************************************************
  313. @Function GetTriangleCount
  314. @Return int
  315. @Description Return the triangle count
  316. ****************************************************************************/
  317. int CObject::GetTriangleCount() const
  318. {
  319. return m_nTriTot;
  320. }
  321. /****************************************************************************
  322. @Function BuildEdgeList
  323. @Input pVtx0 Edge 0
  324. @Input pVtx1 Edge 1
  325. @Return SEdg*
  326. @Description If the vertices that have been passed in are already used by an edge,
  327. the number of triangles sharing the edge is increased by one and a
  328. pointer to the edge is returned. If the edge is not already in the
  329. list, the edge is added to the list.
  330. ****************************************************************************/
  331. SEdg *CObject::BuildEdgeList(
  332. const SVtx * const pVtx0,
  333. const SVtx * const pVtx1)
  334. {
  335. SEdg *pEdg;
  336. const SVtx *pVtxL, *pVtxH;
  337. int i;
  338. pVtxL = pVtx0 < pVtx1 ? pVtx0 : pVtx1;
  339. pVtxH = pVtx0 > pVtx1 ? pVtx0 : pVtx1;
  340. // Do nothing if the edge already exists
  341. i = m_nEdgTot;
  342. while(i) {
  343. --i;
  344. pEdg = &m_pEdg[i];
  345. if(pEdg->psVtx[0] == pVtxL && pEdg->psVtx[1] == pVtxH)
  346. {
  347. ++pEdg->nTriNumFree;
  348. return pEdg;
  349. }
  350. }
  351. // Add the new edge
  352. _ASSERT(m_nEdgTot < m_nTriTot*3);
  353. pEdg = &m_pEdg[m_nEdgTot++];
  354. pEdg->psVtx[0] = pVtxL;
  355. pEdg->psVtx[1] = pVtxH;
  356. pEdg->nTriNumFree = 1;
  357. return pEdg;
  358. }
  359. /****************************************************************************
  360. @Function CreateMeshList
  361. @Description Creates the mesh list
  362. ****************************************************************************/
  363. void CObject::CreateMeshList()
  364. {
  365. SVtx **ppR, **ppW, *pVtx;
  366. STri *pTri;
  367. int i, j, k;
  368. SMesh sMesh;
  369. int nMeshCnt;
  370. nMeshCnt = 0;
  371. ppR = m_ppVtxByMesh;
  372. ppW = m_ppVtxByMesh;
  373. for(i = 0; i < m_nVtxTot; ++i) {
  374. pVtx = &m_pVtx[i];
  375. if(pVtx->ppMeshPos) {
  376. _ASSERT(pVtx->ppMeshPos < ppW);
  377. continue;
  378. }
  379. ++nMeshCnt;
  380. sMesh.ppVtx = ppW;
  381. *ppW = pVtx;
  382. pVtx->ppMeshPos = ppW;
  383. ++ppW;
  384. do {
  385. // Add all the vertices of all the triangles of *ppR to the list - unless they're already in there
  386. for(j = 0; j < (*ppR)->nTriNumTot; ++j) {
  387. pTri = (*ppR)->psTri[j];
  388. for(k = 0; k < 3; ++k) {
  389. pVtx = &m_pVtx[pTri->pwIdx[k]];
  390. if(pVtx->ppMeshPos) {
  391. _ASSERT(pVtx->ppMeshPos < ppW);
  392. continue;
  393. }
  394. *ppW = pVtx;
  395. pVtx->ppMeshPos = ppW;
  396. ++ppW;
  397. }
  398. }
  399. ++ppR;
  400. } while(ppR != ppW);
  401. sMesh.nVtxNum = (int)(ppR - sMesh.ppVtx);
  402. // _RPT2(_CRT_WARN, "CreateMeshList() mesh %d %dvtx\n", nMeshCnt, sMesh.nVtxNum);
  403. if(sMesh.nVtxNum >= 3)
  404. {
  405. if(sMesh.nVtxNum >= m_nVtxLimit)
  406. m_vMeshLg.push_back(sMesh);
  407. else
  408. m_pvMesh[sMesh.nVtxNum-3].push_back(sMesh);
  409. }
  410. else
  411. {
  412. /*
  413. Vertex is not used by any triangles; this may be because we're
  414. optimising a subset of the mesh (e.g. for bone batching).
  415. */
  416. _ASSERT(sMesh.nVtxNum == 1);
  417. }
  418. }
  419. _ASSERT(ppR == &m_ppVtxByMesh[m_nVtxTot]);
  420. _ASSERT(ppW == &m_ppVtxByMesh[m_nVtxTot]);
  421. // _RPT1(_CRT_WARN, "CreateMeshList() %d meshes\n", nMeshCnt);
  422. #ifdef _DEBUG
  423. /* for(i = 0; i < m_nVtxLimit-2; ++i)
  424. if(m_pvMesh[i].size())
  425. _RPT2(_CRT_WARN, "%d:%d ", i+3, m_pvMesh[i].size());
  426. _RPT1(_CRT_WARN, "lg:%d\n", m_vMeshLg.size());*/
  427. #endif
  428. }
  429. /****************************************************************************
  430. @Function SplitMesh
  431. @Input pMesh Pointer to mesh data
  432. @Input nVtxNum Number of vertices in the mesh?
  433. @Output ppVtx Array of vertices
  434. @Description Note: Ask Aaron
  435. ****************************************************************************/
  436. void CObject::SplitMesh(
  437. SMesh * const pMesh,
  438. const int nVtxNum,
  439. SVtx ** const ppVtx)
  440. {
  441. SVtx *pTmp;
  442. int i;
  443. SMesh sNew;
  444. _ASSERT(nVtxNum);
  445. for(i = 0; i < nVtxNum; ++i) {
  446. pTmp = pMesh->ppVtx[i]; // Keep a record of the old vtx that's already here
  447. pMesh->ppVtx[i] = ppVtx[i]; // Move the new vtx into place
  448. *ppVtx[i]->ppMeshPos = pTmp; // Move the old vtx into place
  449. pTmp->ppMeshPos = ppVtx[i]->ppMeshPos; // Tell the old vtx where it is now
  450. ppVtx[i]->ppMeshPos = &pMesh->ppVtx[i]; // Tell the new vtx where it is now
  451. _ASSERT(pMesh->ppVtx[i]->nTriNumFree);
  452. }
  453. sNew.nVtxNum = nVtxNum;
  454. sNew.ppVtx = pMesh->ppVtx;
  455. m_pvMesh[nVtxNum-3].push_back(sNew);
  456. pMesh->ppVtx = &pMesh->ppVtx[nVtxNum];
  457. pMesh->nVtxNum -= nVtxNum;
  458. if(pMesh->nVtxNum < m_nVtxLimit) {
  459. ResizeMesh(pMesh->nVtxNum, pMesh->ppVtx);
  460. m_vMeshLg.pop_back();
  461. #ifdef _DEBUG
  462. /* } else {
  463. for(i = 0; i < m_nVtxLimit-2; ++i)
  464. if(m_pvMesh[i].size())
  465. _RPT2(_CRT_WARN, "%d:%d ", i+3, m_pvMesh[i].size());
  466. _RPT1(_CRT_WARN, "lg:%d\n", m_vMeshLg.size());*/
  467. #endif
  468. }
  469. }
  470. /****************************************************************************
  471. @Function ResizeMesh
  472. @Input nVtxNum The size of the array of vertices being passed in
  473. @Input ppVtx Array of vertices
  474. @Description Note: Ask Aaron
  475. ****************************************************************************/
  476. void CObject::ResizeMesh(
  477. const int nVtxNum,
  478. SVtx ** const ppVtx)
  479. {
  480. SVtx **ppR, **ppW;
  481. SMesh sNew;
  482. int i;
  483. ppR = ppVtx;
  484. ppW = ppVtx;
  485. // Make a list of vertices that have unused triangles in their array of triangles
  486. for(i = 0; i < nVtxNum; ++i) {
  487. if((*ppR)->nTriNumFree) {
  488. (*ppW) = (*ppR);
  489. ++ppW;
  490. }
  491. ++ppR;
  492. }
  493. sNew.nVtxNum = (int)(ppW - ppVtx);
  494. _ASSERT(sNew.nVtxNum <= nVtxNum);
  495. // If any mesh still exists, add it to the relevant list
  496. if(sNew.nVtxNum) {
  497. _ASSERT(sNew.nVtxNum >= 3);
  498. _ASSERT(sNew.nVtxNum < m_nVtxLimit);
  499. sNew.ppVtx = ppVtx;
  500. m_pvMesh[sNew.nVtxNum-3].push_back(sNew);
  501. }
  502. #ifdef _DEBUG
  503. /* for(i = 0; i < m_nVtxLimit-2; ++i)
  504. if(m_pvMesh[i].size())
  505. _RPT2(_CRT_WARN, "%d:%d ", i+3, m_pvMesh[i].size());
  506. _RPT1(_CRT_WARN, "lg:%d\n", m_vMeshLg.size());*/
  507. #endif
  508. }
  509. /****************************************************************************
  510. @Function ~CBlockOption
  511. @Description Default destructor
  512. ****************************************************************************/
  513. CBlockOption::~CBlockOption()
  514. {
  515. FREE(psVtx);
  516. FREE(psTri);
  517. FREE(psEdgeDelta);
  518. }
  519. /****************************************************************************
  520. @Function Init
  521. @Input nVertexLimit The maximum number of vertices a block can contain
  522. @Input nTriLimit The maximum number of triangles a block can contain
  523. @Description Initialises the class
  524. ****************************************************************************/
  525. void CBlockOption::Init(
  526. const int nVtxLimit,
  527. const int nTriLimit)
  528. {
  529. m_nVtxLimit = nVtxLimit;
  530. m_nTriLimit = nTriLimit;
  531. psVtx = (SVtx**)malloc(nVtxLimit * sizeof(*psVtx));
  532. psTri = (STri**)malloc(nTriLimit * sizeof(*psTri));
  533. psEdgeDelta = (SEdgeDelta*)malloc(3 * nTriLimit * sizeof(*psEdgeDelta));
  534. }
  535. /****************************************************************************
  536. @Function Copy
  537. @Input pSrc Pointer to the source data
  538. @Description Overwrites the data in the current instance with the data from
  539. the input CBlockOption.
  540. ****************************************************************************/
  541. void CBlockOption::Copy(const CBlockOption * const pSrc)
  542. {
  543. nVtxNum = pSrc->nVtxNum;
  544. nEdgNum = pSrc->nEdgNum;
  545. nTriNum = pSrc->nTriNum;
  546. memcpy(psVtx, pSrc->psVtx, nVtxNum * sizeof(*psVtx));
  547. memcpy(psEdgeDelta, pSrc->psEdgeDelta, nEdgNum * sizeof(*psEdgeDelta));
  548. memcpy(psTri, pSrc->psTri, nTriNum * sizeof(*psTri));
  549. }
  550. /****************************************************************************
  551. @Function Clear
  552. @Description Sets the value of the number of vertices, edges and triangles
  553. to zero.
  554. ****************************************************************************/
  555. void CBlockOption::Clear()
  556. {
  557. nVtxNum = 0;
  558. nEdgNum = 0;
  559. nTriNum = 0;
  560. }
  561. /****************************************************************************
  562. @Function Output
  563. @Output pwOut Index output
  564. @Output pnVtxCnt Vertex count
  565. @Output pnTriCnt Triangle count
  566. @Modified pOb Pointer to an object
  567. @Description Outputs key information about the instance of CBlockOption
  568. ****************************************************************************/
  569. void CBlockOption::Output(
  570. PVRTGEOMETRY_IDX * const pwOut,
  571. int * const pnVtxCnt,
  572. int * const pnTriCnt,
  573. const CObject * const pOb) const
  574. {
  575. STri *pTri;
  576. int i, j;
  577. for(i = 0; i < nTriNum; ++i) {
  578. pTri = psTri[i];
  579. _ASSERT(!pTri->bUsed);
  580. for(j = 0; j < 3; ++j) {
  581. _ASSERT(pOb->m_pVtx[pTri->pwIdx[j]].nTriNumFree > 0);
  582. _ASSERT(pTri->psEdg[j]->nTriNumFree > 0);
  583. --pOb->m_pVtx[pTri->pwIdx[j]].nTriNumFree;
  584. --pTri->psEdg[j]->nTriNumFree;
  585. _ASSERT(pOb->m_pVtx[pTri->pwIdx[j]].nTriNumFree >= 0);
  586. _ASSERT(pTri->psEdg[j]->nTriNumFree >= 0);
  587. }
  588. pTri->bUsed = true;
  589. // Copy indices into output
  590. memcpy(&pwOut[3*i], pTri->pwIdx, 3 * sizeof(*pTri->pwIdx));
  591. }
  592. *pnVtxCnt = nVtxNum;
  593. *pnTriCnt = nTriNum;
  594. }
  595. /****************************************************************************
  596. @Function UsingVertex
  597. @Input pVtx Vertex to compare
  598. @Return bool True on success
  599. @Description Returns true if the supplied vertex is already being used
  600. in the block option.
  601. ****************************************************************************/
  602. bool CBlockOption::UsingVertex(
  603. const SVtx * const pVtx) const
  604. {
  605. int i;
  606. i = nVtxNum;
  607. while(i) {
  608. --i;
  609. if(psVtx[i] == pVtx)
  610. return true;
  611. }
  612. return false;
  613. }
  614. /****************************************************************************
  615. @Function Contains
  616. @Input pVtx Triangle to compare
  617. @Return bool True on success
  618. @Description Returns true if the supplied triangle is already being used
  619. in the block option.
  620. ****************************************************************************/
  621. bool CBlockOption::Contains(const STri * const pTri) const
  622. {
  623. int i;
  624. i = nTriNum;
  625. while(i) {
  626. --i;
  627. if(psTri[i] == pTri)
  628. return true;
  629. }
  630. return false;
  631. }
  632. /****************************************************************************
  633. @Function IsEmpty
  634. @Return bool True if the block option is empty
  635. @Description Returns true if the block option is empty.
  636. ****************************************************************************/
  637. bool CBlockOption::IsEmpty() const
  638. {
  639. return !(nVtxNum + nEdgNum + nTriNum);
  640. }
  641. /****************************************************************************
  642. @Function IsFull
  643. @Return bool True if the block option is full
  644. @Description Returns true if the block option is full.
  645. ****************************************************************************/
  646. bool CBlockOption::IsFull() const
  647. {
  648. return (m_nVtxLimit - nVtxNum) < 3 || nTriNum == m_nTriLimit;
  649. }
  650. /****************************************************************************
  651. @Function AddVertex
  652. @Input pVtx Vertex to add
  653. @Description Providing the current number of vertices is less than the
  654. maximum, the input vertex is added to the end of the array.
  655. ****************************************************************************/
  656. void CBlockOption::AddVertex(SVtx * const pVtx)
  657. {
  658. _ASSERT(nVtxNum < m_nVtxLimit);
  659. psVtx[nVtxNum++] = pVtx;
  660. }
  661. /****************************************************************************
  662. @Function AddVertexCheckDup
  663. @Input pVtx Vertex to add
  664. @Description Checks that the input vertex is not already contained in the
  665. vertex array. If it is new, it is added to the array.
  666. ****************************************************************************/
  667. void CBlockOption::AddVertexCheckDup(SVtx * const pVtx)
  668. {
  669. int i;
  670. for(i = 0; i < nVtxNum; ++i)
  671. if(psVtx[i] == pVtx)
  672. return;
  673. AddVertex(pVtx);
  674. }
  675. /****************************************************************************
  676. @Function AddTriangleCheckDup
  677. @Input pTri Triangle to add
  678. @Description Checks that the input triangle is not already contained in the
  679. triangle array. If it is new, it is added to the array.
  680. ****************************************************************************/
  681. void CBlockOption::AddTriangleCheckDup(STri * const pTri)
  682. {
  683. int i;
  684. for(i = 0; i < nTriNum; ++i)
  685. if(psTri[i] == pTri)
  686. return;
  687. _ASSERT(nTriNum < m_nTriLimit);
  688. psTri[nTriNum++] = pTri;
  689. }
  690. /****************************************************************************
  691. @Function AddEdgeCheckDup
  692. @Input pEdg Edge to add
  693. @Description Checks that the input edge is not already contained in the
  694. edge array. If it is new, it is added to the array.
  695. ****************************************************************************/
  696. void CBlockOption::AddEdgeCheckDup(const SEdg * const pEdg)
  697. {
  698. int i;
  699. for(i = 0; i < nEdgNum; ++i) {
  700. if(psEdgeDelta[i].pEdg == pEdg) {
  701. ++psEdgeDelta[i].nRefCnt;
  702. return;
  703. }
  704. }
  705. _ASSERT(nEdgNum < 3*m_nTriLimit);
  706. psEdgeDelta[nEdgNum].pEdg = pEdg;
  707. psEdgeDelta[nEdgNum].nRefCnt = 1;
  708. ++nEdgNum;
  709. }
  710. /****************************************************************************
  711. @Function AddTriangle
  712. @Input pTri Triangle to add
  713. @Description Providing the current number of triangles is less than the
  714. maximum, the input triangle is added to the end of the array.
  715. Once this has been done, the array of edges is updated.
  716. ****************************************************************************/
  717. // TODO: if this is only used to add fresh triangles, all edges must be added
  718. void CBlockOption::AddTriangle(STri * const pTri)
  719. {
  720. int i;
  721. _ASSERT(nTriNum < m_nTriLimit);
  722. psTri[nTriNum++] = pTri;
  723. // Keep a count of edges and the number of tris which share them
  724. for(i = 0; i < 3; ++i)
  725. AddEdgeCheckDup(pTri->psEdg[i]);
  726. }
  727. /****************************************************************************
  728. @Function AddOneTriangle
  729. @Input pTri Triangle to add
  730. @Input pOb Object to copy vertices from
  731. @Description Calls the AddTriangle function.
  732. Once this has been done, the array of vertices is updated.
  733. ****************************************************************************/
  734. // TODO: if this is only called to add a fresh start triangle, all vertices must be added
  735. void CBlockOption::AddOneTriangle(
  736. STri * const pTri,
  737. const CObject * const pOb)
  738. {
  739. int i;
  740. // Add the triangle to the block
  741. AddTriangle(pTri);
  742. // Add the vertices to the block
  743. for(i = 0; i < 3; ++i)
  744. AddVertexCheckDup(&pOb->m_pVtx[pTri->pwIdx[i]]);
  745. }
  746. /****************************************************************************
  747. @Function GetClosedEdgeDelta
  748. @Return int The delta value of closed edges
  749. @Description This method returns a value that represents the average state of
  750. the edges. If the value is greater than zero, the majority of
  751. edges are closed. If the value is less than zero, the majority
  752. of edges are open.
  753. ****************************************************************************/
  754. int CBlockOption::GetClosedEdgeDelta() const
  755. {
  756. int i, nDelta;
  757. nDelta = 0;
  758. for(i = 0; i < nEdgNum; ++i) {
  759. _ASSERT(psEdgeDelta[i].pEdg->nTriNumFree >= psEdgeDelta[i].nRefCnt);
  760. // Check how many tris will use the edge if these are taken away
  761. switch(psEdgeDelta[i].pEdg->nTriNumFree - psEdgeDelta[i].nRefCnt) {
  762. case 0:
  763. // If the edge was open, and is now closed, that's good
  764. if(psEdgeDelta[i].pEdg->nTriNumFree == 1)
  765. ++nDelta;
  766. break;
  767. case 1:
  768. // if the edge is now open, that's bad
  769. --nDelta;
  770. break;
  771. }
  772. }
  773. return nDelta;
  774. }
  775. /****************************************************************************
  776. @Function IsBetterThan
  777. @Input pCmp The block option to compare with
  778. @Return bool True if the current block option is best
  779. @Description Returns true if the current block option is better than the
  780. block option that has been passed in. Otherwise, it returns false.
  781. ****************************************************************************/
  782. bool CBlockOption::IsBetterThan(const CBlockOption * const pCmp) const
  783. {
  784. float fWorth0, fWorth1;
  785. int nClosed0, nClosed1;
  786. // Check "worth" - TrisAdded/VtxAdded
  787. fWorth0 = (float)nTriNum / (float)nVtxNum;
  788. fWorth1 = (float)pCmp->nTriNum / (float)pCmp->nVtxNum;
  789. nClosed0 = GetClosedEdgeDelta();
  790. nClosed1 = pCmp->GetClosedEdgeDelta();
  791. if(fabsf(fWorth0 - fWorth1) > 0.1f) {
  792. return fWorth0 > fWorth1;
  793. } else if(nClosed0 != nClosed1) {
  794. return nClosed0 > nClosed1;
  795. } else {
  796. return nTriNum > pCmp->nTriNum;
  797. }
  798. }
  799. /****************************************************************************
  800. @Function Add
  801. @Input pSrc The block option to add
  802. @Input pOb Object to use vertices from
  803. @Description Add's the input vertex and triangle data to the current block option
  804. ****************************************************************************/
  805. void CBlockOption::Add(
  806. const CBlockOption * const pSrc,
  807. const CObject * const pOb)
  808. {
  809. PVRT_UNREFERENCED_PARAMETER(pOb);
  810. int i;
  811. // Add vertices from job to block
  812. for(i = 0; i < pSrc->nVtxNum; ++i)
  813. AddVertexCheckDup(pSrc->psVtx[i]);
  814. // Add triangles from job to block
  815. for(i = 0; i < pSrc->nTriNum; ++i)
  816. AddTriangle(pSrc->psTri[i]);
  817. }
  818. /****************************************************************************
  819. @Function Add
  820. @Input pMesh The mesh to add
  821. @Description Add's the input mesh to the current block option
  822. ****************************************************************************/
  823. void CBlockOption::Add(
  824. const SMesh * const pMesh)
  825. {
  826. int i, j;
  827. SVtx *pVtx;
  828. for(i = 0; i < pMesh->nVtxNum; ++i) {
  829. pVtx = pMesh->ppVtx[i];
  830. AddVertexCheckDup(pVtx);
  831. for(j = 0; j < pVtx->nTriNumTot; ++j) {
  832. if(!pVtx->psTri[j]->bUsed)
  833. AddTriangleCheckDup(pVtx->psTri[j]);
  834. }
  835. }
  836. }
  837. /****************************************************************************
  838. @Function CBlock
  839. @Description Default constructor
  840. ****************************************************************************/
  841. CBlock::CBlock(
  842. const int nBufferVtxLimit,
  843. const int nBufferTriLimit)
  844. {
  845. m_nVtxLimit = nBufferVtxLimit;
  846. m_nTriLimit = nBufferTriLimit;
  847. m_sOpt.Init(m_nVtxLimit, m_nTriLimit);
  848. m_sOptBest.Init(m_nVtxLimit, m_nTriLimit);
  849. // Intialise "job" blocks
  850. m_sJob0.Init(3, m_nTriLimit);
  851. m_sJob1.Init(3, m_nTriLimit);
  852. }
  853. /****************************************************************************
  854. @Function Clear
  855. @Description Clears the current and best block options
  856. ****************************************************************************/
  857. void CBlock::Clear()
  858. {
  859. m_sOpt.Clear();
  860. m_sOptBest.Clear();
  861. }
  862. /****************************************************************************
  863. @Function Output
  864. @Output pwOut Index output
  865. @Output pnVtxCnt Vertex count
  866. @Output pnTriCnt Triangle count
  867. @Modified pOb Pointer to an object
  868. @Description Outputs key information about the instance of CBlockOption
  869. ****************************************************************************/
  870. void CBlock::Output(
  871. PVRTGEOMETRY_IDX * const pwOut,
  872. int * const pnVtxCnt,
  873. int * const pnTriCnt,
  874. const CObject * const pOb) const
  875. {
  876. m_sOptBest.Output(pwOut, pnVtxCnt, pnTriCnt, pOb);
  877. }
  878. /****************************************************************************
  879. @Function AddBestTrianglesAppraise
  880. @Modified pJob The block object to alter
  881. @Input pOb The object
  882. @Input pTriAppraise The triangle to appraise
  883. @Return bool
  884. @Description Uses the input object and triangle to create a new block option.
  885. ****************************************************************************/
  886. bool CBlock::AddBestTrianglesAppraise(
  887. CBlockOption * const pJob,
  888. const CObject * const pOb,
  889. const STri * const pTriAppraise)
  890. {
  891. SVtx *pVtx;
  892. STri *pTri;
  893. int i, j;
  894. pJob->Clear();
  895. // Add vertices
  896. for(i = 0; i < 3; ++i) {
  897. pVtx = &pOb->m_pVtx[pTriAppraise->pwIdx[i]];
  898. if(!m_sOpt.UsingVertex(pVtx))
  899. pJob->AddVertex(pVtx);
  900. }
  901. if(pJob->nVtxNum > (m_nVtxLimit-m_sOpt.nVtxNum))
  902. return false;
  903. // Add triangles referenced by each vertex
  904. for(i = 0; i < 3; ++i) {
  905. pVtx = &pOb->m_pVtx[pTriAppraise->pwIdx[i]];
  906. _ASSERT(pVtx->nTriNumFree >= 1);
  907. _ASSERT(pVtx->nTriNumFree <= pVtx->nTriNumTot);
  908. for(j = 0; j < pVtx->nTriNumTot; ++j) {
  909. if(pJob->nTriNum >= (m_nTriLimit-m_sOpt.nTriNum))
  910. break;
  911. pTri = pVtx->psTri[j];
  912. // Don't count the same triangle twice!
  913. if(pTri->bUsed || m_sOpt.Contains(pTri) || pJob->Contains(pTri))
  914. continue;
  915. // If all the triangle's vertices are or will be in the block, then increase nTri
  916. if(
  917. (
  918. pTri->pwIdx[0] == pTriAppraise->pwIdx[0] ||
  919. pTri->pwIdx[0] == pTriAppraise->pwIdx[1] ||
  920. pTri->pwIdx[0] == pTriAppraise->pwIdx[2] ||
  921. m_sOpt.UsingVertex(&pOb->m_pVtx[pTri->pwIdx[0]])
  922. ) && (
  923. pTri->pwIdx[1] == pTriAppraise->pwIdx[0] ||
  924. pTri->pwIdx[1] == pTriAppraise->pwIdx[1] ||
  925. pTri->pwIdx[1] == pTriAppraise->pwIdx[2] ||
  926. m_sOpt.UsingVertex(&pOb->m_pVtx[pTri->pwIdx[1]])
  927. ) && (
  928. pTri->pwIdx[2] == pTriAppraise->pwIdx[0] ||
  929. pTri->pwIdx[2] == pTriAppraise->pwIdx[1] ||
  930. pTri->pwIdx[2] == pTriAppraise->pwIdx[2] ||
  931. m_sOpt.UsingVertex(&pOb->m_pVtx[pTri->pwIdx[2]])
  932. )
  933. )
  934. {
  935. pJob->AddTriangle(pTri);
  936. }
  937. }
  938. }
  939. _ASSERT(pJob->nTriNum);
  940. _ASSERT(pJob->nTriNum <= (m_nTriLimit-m_sOpt.nTriNum));
  941. return true;
  942. }
  943. /****************************************************************************
  944. @Function AddBestTriangles
  945. @Input pOb The object
  946. @Description Finds the best triangles and adds them to the current block option (m_sOpt)
  947. ****************************************************************************/
  948. void CBlock::AddBestTriangles(CObject * const pOb)
  949. {
  950. int i, j;
  951. const SVtx *pVtx;
  952. STri *pTri;
  953. CBlockOption *pJob, *pJobBest;
  954. pJob = &m_sJob0;
  955. do {
  956. pJobBest = 0;
  957. for(i = 0; i < m_sOpt.nVtxNum; ++i) {
  958. pVtx = m_sOpt.psVtx[i];
  959. if(!pVtx->nTriNumFree)
  960. continue;
  961. for(j = 0; j < pVtx->nTriNumTot; ++j) {
  962. pTri = pVtx->psTri[j];
  963. if(pTri->bUsed || m_sOpt.Contains(pTri))
  964. continue;
  965. // Find out how many triangles and vertices this tri adds
  966. if(!AddBestTrianglesAppraise(pJob, pOb, pTri))
  967. continue;
  968. if(!pJobBest || pJob->IsBetterThan(pJobBest)) {
  969. pJobBest = pJob;
  970. pJob = (pJob == &m_sJob0 ? &m_sJob1 : &m_sJob0);
  971. }
  972. }
  973. }
  974. if(pJobBest) {
  975. m_sOpt.Add(pJobBest, pOb);
  976. }
  977. } while(pJobBest && m_nTriLimit != m_sOpt.nTriNum);
  978. }
  979. /****************************************************************************
  980. @Function FillFrom
  981. @Input pMesh Mesh to fill with
  982. @Input pVtx Vertex to fill with
  983. @Input pOb Object to fill with
  984. @Return bool Returns true if the current block option isn't full
  985. @Description Returns TRUE if Fill() needs to be called again - i.e. blockOption is already filled
  986. ****************************************************************************/
  987. bool CBlock::FillFrom(
  988. SMesh * const pMesh,
  989. SVtx * const pVtx,
  990. CObject * const pOb)
  991. {
  992. // Let's try starting from this vertex then
  993. _ASSERT(pVtx->nTriNumFree);
  994. m_sOpt.Clear();
  995. m_sOpt.AddVertex(pVtx);
  996. AddBestTriangles(pOb);
  997. if(m_sOpt.IsFull()) {
  998. if(m_sOptBest.IsEmpty() || m_sOpt.IsBetterThan(&m_sOptBest))
  999. m_sOptBest.Copy(&m_sOpt);
  1000. return false;
  1001. }
  1002. else
  1003. {
  1004. _ASSERT(!m_sOpt.IsEmpty());
  1005. pOb->SplitMesh(pMesh, m_sOpt.nVtxNum, m_sOpt.psVtx); // Split the sub-mesh into its own mesh
  1006. return true;
  1007. }
  1008. }
  1009. /****************************************************************************
  1010. @Function Fill
  1011. @Input pOb Object to fill with
  1012. @Return int -1 if the block if the best option is already full
  1013. @Description Note: Ask Aaron
  1014. ****************************************************************************/
  1015. int CBlock::Fill(
  1016. CObject * const pOb)
  1017. {
  1018. SVtx *pVtx;
  1019. int i;
  1020. SMesh *pMesh;
  1021. /*
  1022. Build blocks from the large meshes
  1023. */
  1024. if(!pOb->m_vMeshLg.empty()) {
  1025. pMesh = &pOb->m_vMeshLg.back();
  1026. // _RPT1(_CRT_WARN, "Fill() using large with %d vtx\n", pMesh->nVtxNum);
  1027. // Find the vertex with the fewest unused triangles
  1028. for(i = 0; i < pMesh->nVtxNum; ++i) {
  1029. pVtx = pMesh->ppVtx[i];
  1030. if(pVtx->nTriNumFree == 1) {
  1031. if(FillFrom(pMesh, pVtx, pOb))
  1032. return Fill(pOb);
  1033. }
  1034. }
  1035. if(m_sOptBest.IsEmpty()) {
  1036. // Just start from any old vertex
  1037. for(i = 0; i < pMesh->nVtxNum; ++i) {
  1038. pVtx = pMesh->ppVtx[i];
  1039. if(pVtx->nTriNumFree) {
  1040. if(FillFrom(pMesh, pVtx, pOb))
  1041. return Fill(pOb);
  1042. break;
  1043. }
  1044. }
  1045. if(m_sOptBest.IsEmpty()) {
  1046. pOb->m_vMeshLg.pop_back(); // Delete the mesh from the list
  1047. return Fill(pOb);
  1048. }
  1049. }
  1050. if(m_sOptBest.IsFull())
  1051. return -1;
  1052. }
  1053. /*
  1054. Match together the small meshes into blocks
  1055. */
  1056. _ASSERT(m_sOptBest.IsEmpty());
  1057. i = m_nVtxLimit - m_sOptBest.nVtxNum - 3;
  1058. // _RPT0(_CRT_WARN, "Fill() grouping small ");
  1059. // Starting with the largest meshes, lump them into this block
  1060. while(i >= 0 && (m_nVtxLimit - m_sOptBest.nVtxNum) >= 3) {
  1061. if(pOb->m_pvMesh[i].empty()) {
  1062. --i;
  1063. continue;
  1064. }
  1065. pMesh = &pOb->m_pvMesh[i].back();
  1066. m_sOptBest.Add(pMesh);
  1067. // _RPT1(_CRT_WARN, "+%d", pMesh->nVtxNum);
  1068. pOb->m_pvMesh[i].pop_back();
  1069. i = PVRT_MIN(i, m_nVtxLimit - m_sOptBest.nVtxNum - 3);
  1070. }
  1071. // If there's any space left in this block (and clearly there are no blocks
  1072. // just the right size to fit) then take SOME of the largest block available.
  1073. if(!m_sOptBest.IsFull()) {
  1074. m_sOpt.Copy(&m_sOptBest);
  1075. // Note: This loop purposely does not check m_pvMesh[0] - any block
  1076. // which is looking to grab more geometry would have already sucked
  1077. // up those meshes
  1078. for(i = (m_nVtxLimit-3); i; --i) {
  1079. if(!pOb->m_pvMesh[i].empty()) {
  1080. pMesh = &pOb->m_pvMesh[i].back();
  1081. _ASSERT(pMesh->ppVtx[0]->nTriNumFree);
  1082. _ASSERT(!m_sOpt.UsingVertex(pMesh->ppVtx[0]));
  1083. m_sOpt.AddVertex(pMesh->ppVtx[0]);
  1084. // _RPT1(_CRT_WARN, "(+%d)\n", pMesh->nVtxNum);
  1085. AddBestTriangles(pOb);
  1086. m_sOptBest.Copy(&m_sOpt);
  1087. _ASSERT(m_sOptBest.IsFull());
  1088. return i;
  1089. }
  1090. }
  1091. }
  1092. // _RPT0(_CRT_WARN, "\n");
  1093. return -1;
  1094. }
  1095. /****************************************************************************
  1096. ** Local functions
  1097. ****************************************************************************/
  1098. /****************************************************************************
  1099. @Function Fill
  1100. @Input pVtxData Vertex data
  1101. @Input pwIdx Index array
  1102. @Input nStride Stride
  1103. @Input nVertNum Number of vertices
  1104. @Input nIdxNum Number of indices
  1105. @Description Sorts the vertices.
  1106. ****************************************************************************/
  1107. static void SortVertices(
  1108. void * const pVtxData,
  1109. PVRTGEOMETRY_IDX * const pwIdx,
  1110. const int nStride,
  1111. const int nVertNum,
  1112. const int nIdxNum)
  1113. {
  1114. void *pVtxNew;
  1115. int *pnVtxDest;
  1116. int i;
  1117. PVRTGEOMETRY_IDX wNext;
  1118. pVtxNew = malloc(nVertNum * nStride);
  1119. _ASSERT(pVtxNew);
  1120. pnVtxDest = (int*)malloc(nVertNum * sizeof(*pnVtxDest));
  1121. _ASSERT(pnVtxDest);
  1122. wNext = 0;
  1123. // Default all indices to an invalid number
  1124. for(i = 0; i < nVertNum; ++i)
  1125. pnVtxDest[i] = -1;
  1126. // Let's get on with it then.
  1127. for(i = 0; i < nIdxNum; ++i) {
  1128. if(pnVtxDest[pwIdx[i]] == -1) {
  1129. _ASSERT((int) wNext < nVertNum);
  1130. memcpy((char*)pVtxNew+(wNext*nStride), (char*)pVtxData+(pwIdx[i]*nStride), nStride);
  1131. pnVtxDest[pwIdx[i]] = wNext++;
  1132. }
  1133. pwIdx[i] = pnVtxDest[pwIdx[i]];
  1134. }
  1135. /*
  1136. This assert will fail if sorting a sub-set of the triangles (e.g. if
  1137. the mesh is bone-batched).
  1138. In that situation vertex sorting should be performed only once after
  1139. all the tri sorting is finished, not per tri-sort.
  1140. */
  1141. _ASSERT((int) wNext == nVertNum);
  1142. memcpy(pVtxData, pVtxNew, nVertNum * nStride);
  1143. FREE(pnVtxDest);
  1144. FREE(pVtxNew);
  1145. }
  1146. /****************************************************************************
  1147. ** Functions
  1148. ****************************************************************************/
  1149. /*!***************************************************************************
  1150. @Function PVRTGeometrySort
  1151. @Modified pVtxData Pointer to array of vertices
  1152. @Modified pwIdx Pointer to array of indices
  1153. @Input nStride Size of a vertex (in bytes)
  1154. @Input nVertNum Number of vertices. Length of pVtxData array
  1155. @Input nTriNum Number of triangles. Length of pwIdx array is 3* this
  1156. @Input nBufferVtxLimit Number of vertices that can be stored in a buffer
  1157. @Input nBufferTriLimit Number of triangles that can be stored in a buffer
  1158. @Input dwFlags PVRTGEOMETRY_SORT_* flags
  1159. @Description Triangle sorter
  1160. *****************************************************************************/
  1161. void PVRTGeometrySort(
  1162. void * const pVtxData,
  1163. PVRTGEOMETRY_IDX * const pwIdx,
  1164. const int nStride,
  1165. const int nVertNum,
  1166. const int nTriNum,
  1167. const int nBufferVtxLimit,
  1168. const int nBufferTriLimit,
  1169. const unsigned int dwFlags)
  1170. {
  1171. CObject sOb(pwIdx, nVertNum, nTriNum, nBufferVtxLimit, nBufferTriLimit);
  1172. CBlock sBlock(nBufferVtxLimit, nBufferTriLimit);
  1173. PVRTGEOMETRY_IDX *pwIdxOut;
  1174. int nTriCnt, nVtxCnt;
  1175. int nOutTriCnt, nOutVtxCnt, nOutBlockCnt;
  1176. int nMeshToResize;
  1177. #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
  1178. int i;
  1179. int pnBlockTriCnt[PVRVGPBLOCKTEST_MAX_BLOCKS];
  1180. SVGPModel sVGPMdlBefore;
  1181. SVGPModel sVGPMdlAfter;
  1182. #endif
  1183. if(dwFlags & PVRTGEOMETRY_SORT_VERTEXCACHE) {
  1184. #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
  1185. VGP590Test(&sVGPMdlBefore, pwIdx, nTriNum);
  1186. _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);
  1187. #endif
  1188. pwIdxOut = (PVRTGEOMETRY_IDX*)malloc(nTriNum * 3 * sizeof(*pwIdxOut));
  1189. _ASSERT(pwIdxOut);
  1190. // Sort geometry into blocks
  1191. nOutTriCnt = 0;
  1192. nOutVtxCnt = 0;
  1193. nOutBlockCnt = 0;
  1194. do {
  1195. // Clear & fill the block
  1196. sBlock.Clear();
  1197. nMeshToResize = sBlock.Fill(&sOb);
  1198. // Copy indices into output
  1199. sBlock.Output(&pwIdxOut[3*nOutTriCnt], &nVtxCnt, &nTriCnt, &sOb);
  1200. sOb.m_nTriNumFree -= nTriCnt;
  1201. nOutTriCnt += nTriCnt;
  1202. if(nMeshToResize >= 0) {
  1203. SMesh *pMesh;
  1204. _ASSERT(nMeshToResize <= (nBufferVtxLimit-3));
  1205. pMesh = &sOb.m_pvMesh[nMeshToResize].back();
  1206. sOb.ResizeMesh(pMesh->nVtxNum, pMesh->ppVtx);
  1207. sOb.m_pvMesh[nMeshToResize].pop_back();
  1208. }
  1209. _ASSERT(nVtxCnt <= nBufferVtxLimit);
  1210. _ASSERT(nTriCnt <= nBufferTriLimit);
  1211. #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
  1212. _ASSERT(nOutBlockCnt < PVRVGPBLOCKTEST_MAX_BLOCKS);
  1213. pnBlockTriCnt[nOutBlockCnt] = nTriCnt;
  1214. #endif
  1215. nOutVtxCnt += nVtxCnt;
  1216. nOutBlockCnt++;
  1217. // _RPT4(_CRT_WARN, "%d/%d tris (+%d), %d blocks\n", nOutTriCnt, nTriNum, nTriCnt, nOutBlockCnt);
  1218. _ASSERT(nTriCnt == nBufferTriLimit || (nBufferVtxLimit - nVtxCnt) < 3 || nOutTriCnt == nTriNum);
  1219. } while(nOutTriCnt < nTriNum);
  1220. _ASSERT(nOutTriCnt == nTriNum);
  1221. // The following will fail if optimising a subset of the mesh (e.g. a bone batching)
  1222. //_ASSERT(nOutVtxCnt >= nVertNum);
  1223. // Done!
  1224. memcpy(pwIdx, pwIdxOut, nTriNum * 3 * sizeof(*pwIdx));
  1225. FREE(pwIdxOut);
  1226. _RPT3(_CRT_WARN, "OptimiseTriListPVR() In: Tri: %d, Vtx: %d, vtx/tri=%f\n", nTriNum, nVertNum, (float)nVertNum / (float)nTriNum);
  1227. _RPT4(_CRT_WARN, "OptimiseTriListPVR() HW: Tri: %d, Vtx: %d, vtx/tri=%f Blocks=%d\n", nOutTriCnt, nOutVtxCnt, (float)nOutVtxCnt / (float)nOutTriCnt, nOutBlockCnt);
  1228. #ifdef PVRTRISORT_ENABLE_VERIFY_RESULTS
  1229. VGP590Test(&sVGPMdlAfter, pwIdx, nTriNum);
  1230. _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);
  1231. _ASSERTE(sVGPMdlAfter.nVtxCnt <= sVGPMdlBefore.nVtxCnt);
  1232. _ASSERTE(sVGPMdlAfter.nBlockCnt <= sVGPMdlBefore.nBlockCnt);
  1233. for(i = 0; i < nOutBlockCnt; ++i) {
  1234. _ASSERT(pnBlockTriCnt[i] == sVGPMdlAfter.pnBlockTriCnt[i]);
  1235. }
  1236. #endif
  1237. }
  1238. if(!(dwFlags & PVRTGEOMETRY_SORT_IGNOREVERTS)) {
  1239. // Re-order the vertices so maybe they're accessed in a more linear
  1240. // manner. Should cut page-breaks on the initial memory read of
  1241. // vertices. Affects both the order of vertices, and the values
  1242. // of indices, but the triangle order is unchanged.
  1243. SortVertices(pVtxData, pwIdx, nStride, nVertNum, nTriNum*3);
  1244. }
  1245. }
  1246. /*****************************************************************************
  1247. End of file (PVRTGeometry.cpp)
  1248. *****************************************************************************/