GLMeshUtils.pas 69 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLMeshUtils;
  5. (* General utilities for mesh manipulations *)
  6. interface
  7. {$I GLScene.inc}
  8. uses
  9. System.Classes,
  10. System.SysUtils,
  11. System.Math,
  12. GLPersistentClasses,
  13. GLVectorLists,
  14. GLVectorGeometry,
  15. GLVectorTypes;
  16. {Converts a triangle strips into a triangle list.
  17. Vertices are added to list, based on the content of strip. Both non-indexed
  18. and indexed variants are available, the output is *always* non indexed. }
  19. procedure ConvertStripToList(const strip : TAffineVectorList;
  20. list : TAffineVectorList); overload;
  21. procedure ConvertStripToList(const strip : TIntegerList;
  22. list : TIntegerList); overload;
  23. procedure ConvertStripToList(const strip : TAffineVectorList;
  24. const indices : TIntegerList;
  25. list : TAffineVectorList); overload;
  26. function ConvertStripToList(
  27. const AindicesList: PLongWordArray;
  28. Count: LongWord;
  29. RestartIndex: LongWord): TLongWordList; overload;
  30. function ConvertFansToList(
  31. const AindicesList: PLongWordArray;
  32. Count: LongWord;
  33. RestartIndex: LongWord): TLongWordList;
  34. {Expands an indexed structure into a non-indexed structure. }
  35. procedure ConvertIndexedListToList(const data : TAffineVectorList;
  36. const indices : TIntegerList;
  37. list : TAffineVectorList);
  38. {Builds a vector-count optimized indices list.
  39. The returned list (to be freed by caller) contains an "optimized" indices
  40. list in which duplicates coordinates in the original vertices list are used
  41. only once (the first available duplicate in the list is used).
  42. The vertices list is left untouched, to remap/cleanup, you may use the
  43. RemapAndCleanupReferences function. }
  44. function BuildVectorCountOptimizedIndices(const vertices : TAffineVectorList;
  45. const normals : TAffineVectorList = nil;
  46. const texCoords : TAffineVectorList = nil) : TIntegerList;
  47. {Alters a reference array and removes unused reference values.
  48. This functions scans the reference list and removes all values that aren't
  49. referred in the indices list, the indices list is *not* remapped. }
  50. procedure RemapReferences(reference : TAffineVectorList;
  51. const indices : TIntegerList); overload;
  52. procedure RemapReferences(reference : TIntegerList;
  53. const indices : TIntegerList); overload;
  54. {Alters a reference/indice pair and removes unused reference values.
  55. This functions scans the reference list and removes all values that aren't
  56. referred in the indices list, and the indices list is remapped so as to remain
  57. coherent. }
  58. procedure RemapAndCleanupReferences(reference : TAffineVectorList; indices : TIntegerList);
  59. {Creates an indices map from a remap list.
  60. The remap list is what BuildVectorCountOptimizedIndices, a list of indices
  61. to distinct/unique items, the indices map contains the indices of these items
  62. after a remap and cleanup of the set referred by remapIndices... Clear?
  63. In short it takes the output of BuildVectorCountOptimizedIndices and can change
  64. it to something suitable for RemapTrianglesIndices.
  65. Any simpler documentation of this function welcome ;) }
  66. function RemapIndicesToIndicesMap(remapIndices : TIntegerList) : TIntegerList;
  67. {Remaps a list of triangles vertex indices and remove degenerate triangles.
  68. The indicesMap provides newVertexIndex:=indicesMap[oldVertexIndex] }
  69. procedure RemapTrianglesIndices(indices, indicesMap : TIntegerList);
  70. {Remaps a list of indices.
  71. The indicesMap provides newVertexIndex:=indicesMap[oldVertexIndex] }
  72. procedure RemapIndices(indices, indicesMap : TIntegerList);
  73. {Attempts to unify triangle winding.
  74. Depending on topology, this may or may not be successful (some topologies
  75. can't be unified, f.i. those that have duplicate triangles, those that
  76. have edges shared by more than two triangles, those that have unconnected
  77. submeshes etc.) }
  78. procedure UnifyTrianglesWinding(indices : TIntegerList);
  79. {Inverts the triangles winding (vertex order). }
  80. procedure InvertTrianglesWinding(indices : TIntegerList);
  81. {Builds normals for a triangles list.
  82. Builds one normal per reference vertex (may be NullVector is reference isn't
  83. used), which is the averaged for normals of all adjacent triangles.
  84. Returned list must be freed by caller. }
  85. function BuildNormals(reference : TAffineVectorList;
  86. indices : TIntegerList) : TAffineVectorList;
  87. {Builds a list of non-oriented (non duplicated) edges list.
  88. Each edge is represented by the two integers of its vertices,
  89. sorted in ascending order.
  90. If not nil, triangleEdges is filled with the 3 indices of the 3 edges
  91. of the triangle, the edges ordering respecting the original triangle
  92. orientation. }
  93. function BuildNonOrientedEdgesList(triangleIndices : TIntegerList;
  94. triangleEdges : TIntegerList = nil;
  95. edgesTriangles : TIntegerList = nil) : TIntegerList;
  96. {Welds all vertices separated by a distance inferior to weldRadius.
  97. Any two vertices whose distance is inferior to weldRadius will be merged
  98. (ie. one of them will be removed, and the other replaced by the barycenter).
  99. The indicesMap is constructed to allow remapping of indices lists with the
  100. simple rule: newVertexIndex:=indicesMap[oldVertexIndex].
  101. The logic is protected from chain welding, and only vertices that were
  102. initially closer than weldRadius will be welded in the same resulting vertex.
  103. This procedure can be used for mesh simplification, but preferably at design-time
  104. for it is not optimized for speed. This is more a "fixing" utility for meshes
  105. exported from high-polycount CAD tools (to remove duplicate vertices,
  106. quantification errors, etc.) }
  107. procedure WeldVertices(vertices : TAffineVectorList;
  108. indicesMap : TIntegerList;
  109. weldRadius : Single);
  110. {Attempts to create as few as possible triangle strips to cover the mesh.
  111. The indices parameters define a set of triangles as a set of indices to
  112. vertices in a vertex pool, free of duplicate vertices (or resulting
  113. stripification will be of lower quality).
  114. The function returns a list of TIntegerList, each of these lists hosting
  115. a triangle strip, returned objects must be freed by caller.
  116. If agglomerateLoneTriangles is True, the first of the lists actually contains
  117. the agglomerated list of the triangles that couldn't be stripified. }
  118. function StripifyMesh(indices : TIntegerList; maxVertexIndex : Integer;
  119. agglomerateLoneTriangles : Boolean = False) : TPersistentObjectList;
  120. {Increases indices coherency wrt vertex caches.
  121. The indices parameters is understood as vertex indices of a triangles set,
  122. the triangles are reordered to maximize coherency (vertex reuse) over the
  123. cacheSize latest indices. This allows higher rendering performance from
  124. hardware renderers that implement vertex cache (nVidia GeForce family f.i.),
  125. allowing reuse of T&L performance (similar to stripification without
  126. the normals issues of strips).
  127. This procedure performs a coherency optimization via a greedy hill-climber
  128. algorithm (ie. not optimal but fast). }
  129. procedure IncreaseCoherency(indices : TIntegerList; cacheSize : Integer);
  130. type
  131. TSubdivideEdgeEvent = procedure (const idxA, idxB, newIdx : Integer); register;
  132. {Subdivides mesh triangles.
  133. Splits along edges, each triangle becomes four. The smoothFactor can be
  134. used to control subdivision smoothing, zero means no smoothing (tesselation
  135. only), while 1 means "sphere" subdivision (a low res sphere will be subdivided
  136. in a higher-res sphere), values outside of the [0..1] range are for, er,
  137. artistic purposes.
  138. The procedure is not intended for real-time use. }
  139. procedure SubdivideTriangles(smoothFactor : Single;
  140. vertices : TAffineVectorList;
  141. triangleIndices : TIntegerList;
  142. normals : TAffineVectorList = nil;
  143. onSubdivideEdge : TSubdivideEdgeEvent = nil);
  144. {Create list of indices of triangles with adjacency from triangle list }
  145. function MakeTriangleAdjacencyList(
  146. const AindicesList: PLongWordArray; Count: LongWord;
  147. const AVerticesList: PAffineVectorArray): TLongWordList;
  148. var
  149. vImprovedFixingOpenTriangleEdge: Boolean = False;
  150. vEdgeInfoReserveSize: LongWord = 64;
  151. // ------------------------------------------------------------------
  152. implementation
  153. // ------------------------------------------------------------------
  154. uses
  155. GLCrossPlatform;
  156. var
  157. v0to255reciproquals : array of Single;
  158. function Get0to255reciproquals : PSingleArray;
  159. var
  160. i : Integer;
  161. begin
  162. if Length(v0to255reciproquals)<>256 then begin
  163. SetLength(v0to255reciproquals, 256);
  164. for i:=1 to 255 do
  165. v0to255reciproquals[i]:=1/i;
  166. end;
  167. Result:=@v0to255reciproquals[0];
  168. end;
  169. procedure ConvertStripToList(const strip : TAffineVectorList;
  170. list : TAffineVectorList);
  171. var
  172. i : Integer;
  173. stripList : PAffineVectorArray;
  174. begin
  175. list.AdjustCapacityToAtLeast(list.Count+3*(strip.Count-2));
  176. stripList:=strip.List;
  177. for i:=0 to strip.Count-3 do begin
  178. if (i and 1)=0 then
  179. list.Add(stripList[i+0], stripList[i+1], stripList[i+2])
  180. else list.Add(stripList[i+2], stripList[i+1], stripList[i+0]);
  181. end;
  182. end;
  183. procedure ConvertStripToList(const strip : TIntegerList;
  184. list : TIntegerList);
  185. var
  186. i : Integer;
  187. stripList : PIntegerArray;
  188. begin
  189. list.AdjustCapacityToAtLeast(list.Count+3*(strip.Count-2));
  190. stripList:=strip.List;
  191. for i:=0 to strip.Count-3 do begin
  192. if (i and 1)=0 then
  193. list.Add(stripList[i+0], stripList[i+1], stripList[i+2])
  194. else list.Add(stripList[i+2], stripList[i+1], stripList[i+0]);
  195. end;
  196. end;
  197. procedure ConvertStripToList(const strip : TAffineVectorList;
  198. const indices : TIntegerList;
  199. list : TAffineVectorList);
  200. var
  201. i : Integer;
  202. stripList : PAffineVectorArray;
  203. begin
  204. list.AdjustCapacityToAtLeast(list.Count+3*(indices.Count-2));
  205. stripList:=strip.List;
  206. for i:=0 to indices.Count-3 do begin
  207. if (i and 1)=0 then
  208. list.Add(stripList[indices[i+0]],
  209. stripList[indices[i+1]],
  210. stripList[indices[i+2]])
  211. else list.Add(stripList[indices[i+2]],
  212. stripList[indices[i+1]],
  213. stripList[indices[i+0]])
  214. end;
  215. end;
  216. procedure ConvertIndexedListToList(const data : TAffineVectorList;
  217. const indices : TIntegerList;
  218. list : TAffineVectorList);
  219. var
  220. i : Integer;
  221. indicesList : PIntegerArray;
  222. dataList, listList : PAffineVectorArray;
  223. oldResetMem : Boolean;
  224. begin
  225. Assert(data<>list); // this is not allowed
  226. oldResetMem:=list.SetCountResetsMemory;
  227. list.SetCountResetsMemory:=False;
  228. list.Count:=indices.Count;
  229. list.SetCountResetsMemory:=oldResetMem;
  230. indicesList:=indices.List;
  231. dataList:=data.List;
  232. listList:=list.List;
  233. for i:=0 to indices.Count-1 do
  234. listList[i]:=dataList[indicesList[i]];
  235. end;
  236. function BuildVectorCountOptimizedIndices(const vertices : TAffineVectorList;
  237. const normals : TAffineVectorList = nil;
  238. const texCoords : TAffineVectorList = nil) : TIntegerList;
  239. var
  240. i, j, k : Integer;
  241. found : Boolean;
  242. hashSize : Integer;
  243. hashTable : array of TIntegerlist;
  244. list : TIntegerList;
  245. verticesList, normalsList, texCoordsList : PAffineVectorArray;
  246. const
  247. cVerticesPerHashKey = 48;
  248. cInvVerticesPerHashKey = 1/cVerticesPerHashKey;
  249. function HashKey(const v : TAffineVector; hashSize : Integer) : Integer;
  250. begin
  251. Result:=(( Integer(PIntegerArray(@v)[0])
  252. xor Integer(PIntegerArray(@v)[1])
  253. xor Integer(PIntegerArray(@v)[2])) shr 16) and hashSize;
  254. end;
  255. begin
  256. Result:=TIntegerList.Create;
  257. Result.Capacity:=vertices.Count;
  258. if Assigned(normals) then begin
  259. Assert(normals.Count>=vertices.Count);
  260. normalsList:=normals.List
  261. end else normalsList:=nil;
  262. if Assigned(texCoords) then begin
  263. Assert(texCoords.Count>=vertices.Count);
  264. texCoordsList:=texCoords.List
  265. end else texCoordsList:=nil;
  266. verticesList:=vertices.List;
  267. // This method is very fast, at the price of memory requirement its
  268. // probable complexity is only O(n) (it's a kind of bucket-sort hellspawn)
  269. // Initialize data structures for a hash table
  270. // (each vertex will only be compared to vertices of similar hash value)
  271. hashSize:=(1 shl MaxInteger(Integer(0), Integer(Trunc(Log2(vertices.Count*cInvVerticesPerHashKey)))))-1;
  272. if hashSize<7 then hashSize:=7;
  273. if hashSize>65535 then hashSize:=65535;
  274. SetLength(hashTable, hashSize+1);
  275. // allocate and fill our hashtable (will store "reference" vertex indices)
  276. for i:=0 to hashSize do begin
  277. hashTable[i]:=TIntegerList.Create;
  278. hashTable[i].GrowthDelta:=cVerticesPerHashKey div 2;
  279. end;
  280. // here we go for all vertices
  281. if Assigned(texCoordsList) or Assigned(normalsList) then begin
  282. for i:=0 to vertices.Count-1 do begin
  283. list:=hashTable[HashKey(verticesList[i], hashSize)];
  284. found:=False;
  285. // Check each vertex against its hashkey siblings
  286. if list.Count>0 then begin
  287. if Assigned(texCoordsList) then begin
  288. if Assigned(normalsList) then begin
  289. for j:=0 to list.Count-1 do begin
  290. k:=list.List[j];
  291. if VectorEquals(verticesList[k], verticesList[i])
  292. and VectorEquals(normalsList[k], normalsList[i])
  293. and VectorEquals(texCoordsList[k], texCoordsList[i]) then begin
  294. // vertex known, just store its index
  295. Result.Add(k);
  296. found:=True;
  297. Break;
  298. end;
  299. end;
  300. end else begin
  301. for j:=0 to list.Count-1 do begin
  302. k:=list.List[j];
  303. if VectorEquals(verticesList[k], verticesList[i])
  304. and VectorEquals(texCoordsList[k], texCoordsList[i]) then begin
  305. // vertex known, just store its index
  306. Result.Add(k);
  307. found:=True;
  308. Break;
  309. end;
  310. end;
  311. end;
  312. end else begin
  313. for j:=0 to list.Count-1 do begin
  314. k:=list.List[j];
  315. if VectorEquals(verticesList[k], verticesList[i])
  316. and VectorEquals(normalsList[k], normalsList[i]) then begin
  317. // vertex known, just store its index
  318. Result.Add(k);
  319. found:=True;
  320. Break;
  321. end;
  322. end;
  323. end;
  324. end;
  325. if not found then begin
  326. // vertex unknown, store index and add to the hashTable's list
  327. list.Add(i);
  328. Result.Add(i);
  329. end;
  330. end;
  331. end else begin
  332. for i:=0 to vertices.Count-1 do begin
  333. list:=hashTable[HashKey(verticesList[i], hashSize)];
  334. found:=False;
  335. // Check each vertex against its hashkey siblings
  336. for j:=0 to list.Count-1 do begin
  337. k:=list.List[j];
  338. if VectorEquals(verticesList[k], verticesList[i]) then begin
  339. // vertex known, just store its index
  340. Result.Add(k);
  341. found:=True;
  342. Break;
  343. end;
  344. end;
  345. if not found then begin
  346. // vertex unknown, store index and add to the hashTable's list
  347. list.Add(i);
  348. Result.Add(i);
  349. end;
  350. end;
  351. end;
  352. // free hash data
  353. for i:=0 to hashSize do
  354. hashTable[i].Free;
  355. SetLength(hashTable, 0);
  356. end;
  357. // RemapReferences (vectors)
  358. //
  359. procedure RemapReferences(reference : TAffineVectorList;
  360. const indices : TIntegerList);
  361. var
  362. i : Integer;
  363. tag : array of Byte;
  364. refListI, refListN : PAffineVector;
  365. indicesList : PIntegerArray;
  366. begin
  367. Assert(reference.Count=indices.Count);
  368. SetLength(tag, reference.Count);
  369. indicesList:=indices.List;
  370. // 1st step, tag all used references
  371. for i:=0 to indices.Count-1 do
  372. Tag[indicesList[i]]:=1;
  373. // 2nd step, build remap indices and cleanup references
  374. refListI:[email protected][0];
  375. refListN:=refListI;
  376. for i:=0 to High(tag) do begin
  377. if tag[i]<>0 then begin
  378. if refListN<>refListI then
  379. refListN^:=refListI^;
  380. Inc(refListN);
  381. end;
  382. Inc(refListI);
  383. end;
  384. reference.Count:=(Cardinal(refListN)-Cardinal(@reference.List[0])) div SizeOf(TAffineVector);
  385. end;
  386. procedure RemapReferences(reference : TIntegerList;
  387. const indices : TIntegerList);
  388. var
  389. i, n : Integer;
  390. tag : array of Byte;
  391. refList : PIntegerArray;
  392. indicesList : PIntegerArray;
  393. begin
  394. Assert(reference.Count=indices.Count);
  395. SetLength(tag, reference.Count);
  396. indicesList:=indices.List;
  397. // 1st step, tag all used references
  398. for i:=0 to indices.Count-1 do
  399. Tag[indicesList[i]]:=1;
  400. // 2nd step, build remap indices and cleanup references
  401. n:=0;
  402. refList:=reference.List;
  403. for i:=0 to High(tag) do begin
  404. if tag[i]<>0 then begin
  405. if n<>i then
  406. refList[n]:=refList[i];
  407. Inc(n);
  408. end;
  409. end;
  410. reference.Count:=n;
  411. end;
  412. procedure RemapAndCleanupReferences(reference : TAffineVectorList;
  413. indices : TIntegerList);
  414. var
  415. i, n : Integer;
  416. tag : array of Integer;
  417. refList : PAffineVectorArray;
  418. indicesList : PIntegerArray;
  419. begin
  420. Assert(reference.Count=indices.Count);
  421. SetLength(tag, reference.Count);
  422. indicesList:=indices.List;
  423. // 1st step, tag all used references
  424. for i:=0 to indices.Count-1 do
  425. tag[indicesList[i]]:=1;
  426. // 2nd step, build remap indices and cleanup references
  427. n:=0;
  428. refList:=reference.List;
  429. for i:=0 to High(tag) do begin
  430. if tag[i]<>0 then begin
  431. tag[i]:=n;
  432. if n<>i then
  433. refList[n]:=refList[i];
  434. Inc(n);
  435. end;
  436. end;
  437. reference.Count:=n;
  438. // 3rd step, remap indices
  439. for i:=0 to indices.Count-1 do
  440. indicesList[i]:=tag[indicesList[i]];
  441. end;
  442. function RemapIndicesToIndicesMap(remapIndices : TIntegerList) : TIntegerList;
  443. var
  444. i, n : Integer;
  445. tag : array of Integer;
  446. remapList, indicesMap : PIntegerArray;
  447. begin
  448. SetLength(tag, remapIndices.Count);
  449. // 1st step, tag all used indices
  450. remapList:=remapIndices.List;
  451. for i:=0 to remapIndices.Count-1 do
  452. tag[remapList[i]]:=1;
  453. // 2nd step, build indices offset table
  454. n:=0;
  455. for i:=0 to remapIndices.Count-1 do begin
  456. if tag[i]>0 then begin
  457. tag[i]:=n;
  458. Inc(n);
  459. end;
  460. end;
  461. // 3rd step, fillup indices map
  462. Result:=TIntegerList.Create;
  463. Result.Count:=remapIndices.Count;
  464. indicesMap:=Result.List;
  465. for i:=0 to Result.Count-1 do
  466. indicesMap[i]:=tag[remapList[i]];
  467. end;
  468. procedure RemapTrianglesIndices(indices, indicesMap : TIntegerList);
  469. var
  470. i, k, a, b, c, n : Integer;
  471. begin
  472. Assert((indices.Count mod 3)=0); // must be a multiple of 3
  473. n:=indices.Count;
  474. i:=0;
  475. k:=0;
  476. while i<n do begin
  477. a:=indicesMap[indices[i]];
  478. b:=indicesMap[indices[i+1]];
  479. c:=indicesMap[indices[i+2]];
  480. if (a<>b) and (b<>c) and (a<>c) then begin
  481. indices[k]:=a;
  482. indices[k+1]:=b;
  483. indices[k+2]:=c;
  484. Inc(k, 3);
  485. end;
  486. Inc(i, 3);
  487. end;
  488. indices.Count:=k;
  489. end;
  490. procedure RemapIndices(indices, indicesMap : TIntegerList);
  491. var
  492. i : Integer;
  493. map, ind : PIntegerArray;
  494. begin
  495. ind:=indices.List;
  496. map:=indicesMap.List;
  497. for i:=0 to indices.Count-1 do
  498. ind[i]:=map[ind[i]];
  499. end;
  500. procedure UnifyTrianglesWinding(indices : TIntegerList);
  501. var
  502. nbTris : Integer;
  503. mark : array of ByteBool; // marks triangles that have been processed
  504. triangleStack : TIntegerList; // marks triangles winded, that must be processed
  505. procedure TestRewind(a, b : Integer);
  506. var
  507. i, n : Integer;
  508. x, y, z : Integer;
  509. begin
  510. i:=indices.Count-3;
  511. n:=nbTris-1;
  512. while i>0 do begin
  513. if not mark[n] then begin
  514. x:=indices[i];
  515. y:=indices[i+1];
  516. z:=indices[i+2];
  517. if ((x=a) and (y=b)) or ((y=a) and (z=b)) or ((z=a) and (x=b)) then begin
  518. indices.Exchange(i, i+2);
  519. mark[n]:=True;
  520. triangleStack.Push(n);
  521. end else if ((x=b) and (y=a)) or ((y=b) and (z=a)) or ((z=b) and (x=a)) then begin
  522. mark[n]:=True;
  523. triangleStack.Push(n);
  524. end;
  525. end;
  526. Dec(i, 3);
  527. Dec(n);
  528. end;
  529. end;
  530. procedure ProcessTriangleStack;
  531. var
  532. n, i : Integer;
  533. begin
  534. while triangleStack.Count>0 do begin
  535. // get triangle, it is *assumed* properly winded
  536. n:=triangleStack.Pop;
  537. i:=n*3;
  538. mark[n]:=True;
  539. // rewind neighbours
  540. TestRewind(indices[i+0], indices[i+1]);
  541. TestRewind(indices[i+1], indices[i+2]);
  542. TestRewind(indices[i+2], indices[i+0]);
  543. end;
  544. end;
  545. var
  546. n : Integer;
  547. begin
  548. nbTris:=indices.Count div 3;
  549. SetLength(mark, nbTris);
  550. // Build connectivity data
  551. triangleStack:=TIntegerList.Create;
  552. try
  553. triangleStack.Capacity:=nbTris div 4;
  554. // Pick a triangle, adjust normals of neighboring triangles, recurse
  555. for n:=0 to nbTris-1 do begin
  556. if mark[n] then Continue;
  557. triangleStack.Push(n);
  558. ProcessTriangleStack;
  559. end;
  560. finally
  561. triangleStack.Free;
  562. end;
  563. end;
  564. procedure InvertTrianglesWinding(indices : TIntegerList);
  565. var
  566. i : Integer;
  567. begin
  568. Assert((indices.Count mod 3)=0);
  569. i:=indices.Count-3;
  570. while i>=0 do begin
  571. indices.Exchange(i, i+2);
  572. Dec(i, 3);
  573. end;
  574. end;
  575. function BuildNormals(reference : TAffineVectorList;
  576. indices : TIntegerList) : TAffineVectorList;
  577. var
  578. i, n, k : Integer;
  579. normalsCount : array of Byte;
  580. v : TAffineVector;
  581. refList, resultList : PAffineVectorArray;
  582. indicesList : PIntegerArray;
  583. reciproquals : PSingleArray;
  584. begin
  585. Result:=TAffineVectorList.Create;
  586. Result.Count:=reference.Count;
  587. SetLength(normalsCount, reference.Count);
  588. refList:=reference.List;
  589. indicesList:=indices.List;
  590. resultList:=Result.List;
  591. // 1st step, calculate triangle normals and sum
  592. i:=0; while i<indices.Count do begin
  593. v:=CalcPlaneNormal(refList[indicesList[i]],
  594. refList[indicesList[i+1]],
  595. refList[indicesList[i+2]]);
  596. for n:=i to i+2 do begin
  597. k:=indicesList[n];
  598. AddVector(resultList[k], v);
  599. Inc(normalsCount[k]);
  600. end;
  601. Inc(i, 3);
  602. end;
  603. // 2nd step, average normals
  604. reciproquals:=Get0to255reciproquals;
  605. for i:=0 to reference.Count-1 do
  606. ScaleVector(resultList[i], reciproquals[normalsCount[i]]);
  607. end;
  608. {Builds a list of non-oriented (non duplicated) edges list.
  609. Each edge is represented by the two integers of its vertices,
  610. sorted in ascending order.
  611. If not nil, triangleEdges is filled with the 3 indices of the 3 edges
  612. of the triangle, the edges ordering respecting the original triangle
  613. orientation.
  614. If not nil, edgesTriangles is filled with the indices of the first index
  615. of the triangle in triangleIndices that have this edge. A maximum of two
  616. triangles can be referred by this list, and its final size will be that
  617. of the Result (ie. non oriented edges list). }
  618. function BuildNonOrientedEdgesList(triangleIndices : TIntegerList;
  619. triangleEdges : TIntegerList = nil;
  620. edgesTriangles : TIntegerList = nil) : TIntegerList;
  621. const
  622. cEdgesHashMax = 127; // must be a power of two minus 1
  623. var
  624. edgesHash : array [0..cEdgesHashMax] of TIntegerList;
  625. curTri : Integer;
  626. edges : TIntegerList;
  627. function ProcessEdge(a, b : Integer) : Integer;
  628. var
  629. i, n : Integer;
  630. hashKey : Integer;
  631. edgesList, iList : PIntegerArray;
  632. hashList : TIntegerList;
  633. begin
  634. if a>=b then begin
  635. i:=a;
  636. a:=b;
  637. b:=i;
  638. end;
  639. hashKey:=(a xor b) and cEdgesHashMax;
  640. hashList:=edgesHash[hashKey];
  641. edgesList:=edges.List;
  642. iList:=hashList.List;
  643. for i:=0 to hashList.Count-1 do begin
  644. n:=iList[i];
  645. if (edgesList[n]=a) and (edgesList[n+1]=b) then begin
  646. Result:=n;
  647. Exit;
  648. end;
  649. end;
  650. Result:=edges.Count;
  651. hashList.Add(Result);
  652. edges.Add(a, b);
  653. end;
  654. function ProcessEdge2(a, b : Integer) : Integer;
  655. var
  656. n : Integer;
  657. hashKey : Integer;
  658. edgesList : PIntegerArray;
  659. iList, iListEnd : PInteger;
  660. hashList : TIntegerList;
  661. begin
  662. if a>=b then begin
  663. n:=a;
  664. a:=b;
  665. b:=n;
  666. end;
  667. hashKey:=(a xor (b shl 1)) and cEdgesHashMax;
  668. edgesList:=edges.List;
  669. hashList:=edgesHash[hashKey];
  670. iList:[email protected][0];
  671. iListEnd:[email protected][hashList.Count];
  672. while Cardinal(iList)<Cardinal(iListEnd) do
  673. begin
  674. n:=iList^;
  675. if (edgesList[n]=a) and (edgesList[n+1]=b) then
  676. begin
  677. edgesTriangles[n+1]:=curTri;
  678. Result:=n;
  679. Exit;
  680. end;
  681. Inc(iList);
  682. end;
  683. Result:=edges.Count;
  684. hashList.Add(Result);
  685. edges.Add(a, b);
  686. edgesTriangles.Add(curTri, -1);
  687. end;
  688. var
  689. j, k : Integer;
  690. triIndicesList : PIntegerArray;
  691. begin
  692. Result:=TIntegerList.Create;
  693. Result.Capacity:=1024;
  694. Result.GrowthDelta:=1024;
  695. if Assigned(triangleEdges) then
  696. triangleEdges.Count:=triangleIndices.Count;
  697. if Assigned(edgesTriangles) then
  698. edgesTriangles.Count:=0;
  699. // Creates Hash
  700. k:=(triangleIndices.Count div (cEdgesHashMax+1))+128;
  701. for j:=0 to High(edgesHash) do begin
  702. edgesHash[j]:=TIntegerList.Create;
  703. edgesHash[j].Capacity:=k;
  704. end;
  705. // collect all edges
  706. curTri:=0;
  707. triIndicesList:=triangleIndices.List;
  708. edges:=Result;
  709. if Assigned(triangleEdges) then begin
  710. if Assigned(edgesTriangles) then begin
  711. while curTri<triangleIndices.Count do begin
  712. triangleEdges[curTri ]:=ProcessEdge2(triIndicesList[curTri ], triIndicesList[curTri+1]);
  713. triangleEdges[curTri+1]:=ProcessEdge2(triIndicesList[curTri+1], triIndicesList[curTri+2]);
  714. triangleEdges[curTri+2]:=ProcessEdge2(triIndicesList[curTri+2], triIndicesList[curTri ]);
  715. Inc(curTri, 3);
  716. end;
  717. end else begin
  718. while curTri<triangleIndices.Count do begin
  719. triangleEdges[curTri ]:=ProcessEdge(triIndicesList[curTri ], triIndicesList[curTri+1]);
  720. triangleEdges[curTri+1]:=ProcessEdge(triIndicesList[curTri+1], triIndicesList[curTri+2]);
  721. triangleEdges[curTri+2]:=ProcessEdge(triIndicesList[curTri+2], triIndicesList[curTri ]);
  722. Inc(curTri, 3);
  723. end;
  724. end;
  725. end else begin
  726. if Assigned(edgesTriangles) then begin
  727. while curTri<triangleIndices.Count do begin
  728. ProcessEdge2(triIndicesList[curTri ], triIndicesList[curTri+1]);
  729. ProcessEdge2(triIndicesList[curTri+1], triIndicesList[curTri+2]);
  730. ProcessEdge2(triIndicesList[curTri+2], triIndicesList[curTri ]);
  731. Inc(curTri, 3);
  732. end;
  733. end else begin
  734. while curTri<triangleIndices.Count do begin
  735. ProcessEdge(triIndicesList[curTri ], triIndicesList[curTri+1]);
  736. ProcessEdge(triIndicesList[curTri+1], triIndicesList[curTri+2]);
  737. ProcessEdge(triIndicesList[curTri+2], triIndicesList[curTri ]);
  738. Inc(curTri, 3);
  739. end;
  740. end;
  741. end;
  742. // remove Hash
  743. for j:=0 to High(edgesHash) do
  744. edgesHash[j].Free;
  745. end;
  746. procedure IncreaseCoherency(indices : TIntegerList; cacheSize : Integer);
  747. var
  748. i, n, maxVertex, bestCandidate, bestScore, candidateIdx, lastCandidate : Integer;
  749. trisOfVertex : array of TIntegerList;
  750. candidates : TIntegerList;
  751. indicesList : PIntegerArray;
  752. begin
  753. // Alloc lookup structure
  754. maxVertex:=indices.MaxInteger;
  755. SetLength(trisOfVertex, maxVertex+1);
  756. for i:=0 to High(trisOfVertex) do
  757. trisOfVertex[i]:=TIntegerList.Create;
  758. candidates:=TIntegerList.Create;
  759. indicesList:=PIntegerArray(indices.List);
  760. // Fillup lookup structure
  761. i:=0;
  762. while i<indices.Count do begin
  763. trisOfVertex[indicesList[i+0]].Add(i);
  764. trisOfVertex[indicesList[i+1]].Add(i);
  765. trisOfVertex[indicesList[i+2]].Add(i);
  766. Inc(i, 3);
  767. end;
  768. // Optimize
  769. i:=0;
  770. while i<indices.Count do begin
  771. n:=i-cacheSize;
  772. if n<0 then n:=0;
  773. candidates.Count:=0;
  774. while n<i do begin
  775. candidates.Add(trisOfVertex[indicesList[n]]);
  776. Inc(n);
  777. end;
  778. bestCandidate:=-1;
  779. if candidates.Count>0 then begin
  780. candidateIdx:=0;
  781. bestScore:=0;
  782. candidates.Sort;
  783. lastCandidate:=candidates.List[0];
  784. for n:=1 to candidates.Count-1 do begin
  785. if candidates.List[n]<>lastCandidate then begin
  786. if n-candidateIdx>bestScore then begin
  787. bestScore:=n-candidateIdx;
  788. bestCandidate:=lastCandidate;
  789. end;
  790. lastCandidate:=candidates.List[n];
  791. candidateIdx:=n;
  792. end;
  793. end;
  794. if candidates.Count-candidateIdx>bestScore then
  795. bestCandidate:=lastCandidate;
  796. end;
  797. if bestCandidate>=0 then begin
  798. trisOfVertex[indicesList[i+0]].Remove(i);
  799. trisOfVertex[indicesList[i+1]].Remove(i);
  800. trisOfVertex[indicesList[i+2]].Remove(i);
  801. trisOfVertex[indicesList[bestCandidate+0]].Remove(bestCandidate);
  802. trisOfVertex[indicesList[bestCandidate+1]].Remove(bestCandidate);
  803. trisOfVertex[indicesList[bestCandidate+2]].Remove(bestCandidate);
  804. trisOfVertex[indicesList[i+0]].Add(bestCandidate);
  805. trisOfVertex[indicesList[i+1]].Add(bestCandidate);
  806. trisOfVertex[indicesList[i+2]].Add(bestCandidate);
  807. indices.Exchange(bestCandidate+0, i+0);
  808. indices.Exchange(bestCandidate+1, i+1);
  809. indices.Exchange(bestCandidate+2, i+2);
  810. end else begin
  811. trisOfVertex[indicesList[i+0]].Remove(i);
  812. trisOfVertex[indicesList[i+1]].Remove(i);
  813. trisOfVertex[indicesList[i+2]].Remove(i);
  814. end;
  815. Inc(i, 3);
  816. end;
  817. // Release lookup structure
  818. candidates.Free;
  819. for i:=0 to High(trisOfVertex) do
  820. trisOfVertex[i].Free;
  821. end;
  822. procedure WeldVertices(vertices : TAffineVectorList;
  823. indicesMap : TIntegerList;
  824. weldRadius : Single);
  825. var
  826. i, j, n, k : Integer;
  827. pivot : PAffineVector;
  828. sum : TAffineVector;
  829. wr2 : Single;
  830. mark : packed array of ByteBool;
  831. begin
  832. indicesMap.Count:=vertices.Count;
  833. SetLength(mark, vertices.Count);
  834. wr2:=Sqr(weldRadius);
  835. // mark duplicates, compute barycenters and indicesMap
  836. i:=0;
  837. k:=0;
  838. while i<vertices.Count do begin
  839. if not mark[i] then begin
  840. pivot:[email protected][i];
  841. indicesMap[i]:=k;
  842. n:=0;
  843. j:=vertices.Count-1;
  844. while j>i do begin
  845. if not mark[j] then begin
  846. if VectorDistance2(pivot^, vertices.List[j])<=wr2 then begin
  847. if n=0 then begin
  848. sum:=VectorAdd(pivot^, vertices.List[j]);
  849. n:=2;
  850. end else begin
  851. AddVector(sum, vertices.List[j]);
  852. Inc(n);
  853. end;
  854. indicesMap[j]:=k;
  855. mark[j]:=True;
  856. end;
  857. end;
  858. Dec(j);
  859. end;
  860. if n>0 then
  861. vertices.List[i]:=VectorScale(sum, 1/n);
  862. Inc(k);
  863. end;
  864. Inc(i);
  865. end;
  866. // pack vertices list
  867. k:=0;
  868. for i:=0 to vertices.Count-1 do begin
  869. if not mark[i] then begin
  870. vertices.List[k]:=vertices.List[i];
  871. Inc(k);
  872. end;
  873. end;
  874. vertices.Count:=k;
  875. end;
  876. function StripifyMesh(indices : TIntegerList; maxVertexIndex : Integer;
  877. agglomerateLoneTriangles : Boolean = False) : TPersistentObjectList;
  878. var
  879. accountedTriangles : array of ByteBool;
  880. vertexTris : array of TIntegerList;
  881. indicesList : PIntegerArray;
  882. indicesCount : Integer;
  883. currentStrip : TIntegerList;
  884. nextTriangle, nextVertex : Integer;
  885. function FindTriangleWithEdge(vertA, vertB : Integer) : Boolean;
  886. var
  887. i, n : Integer;
  888. p : PIntegerArray;
  889. list : TIntegerList;
  890. begin
  891. Result:=False;
  892. list:=vertexTris[vertA];
  893. for n:=0 to list.Count-1 do begin
  894. i:=list.List[n];
  895. if not (accountedTriangles[i]) then begin
  896. p:=@indicesList[i];
  897. if (p[0]=vertA) and (p[1]=vertB) then begin
  898. Result:=True;
  899. nextVertex:=p[2];
  900. nextTriangle:=i;
  901. Break;
  902. end else if (p[1]=vertA) and (p[2]=vertB) then begin
  903. Result:=True;
  904. nextVertex:=p[0];
  905. nextTriangle:=i;
  906. Break;
  907. end else if (p[2]=vertA) and (p[0]=vertB) then begin
  908. Result:=True;
  909. nextVertex:=p[1];
  910. nextTriangle:=i;
  911. Break;
  912. end;
  913. end;
  914. end;
  915. end;
  916. procedure BuildStrip(vertA, vertB : Integer);
  917. var
  918. vertC : Integer;
  919. begin
  920. currentStrip.Add(vertA, vertB);
  921. repeat
  922. vertC:=nextVertex;
  923. currentStrip.Add(vertC);
  924. accountedTriangles[nextTriangle]:=True;
  925. if not FindTriangleWithEdge(vertB, vertC) then Break;
  926. currentStrip.Add(nextVertex);
  927. accountedTriangles[nextTriangle]:=True;
  928. vertB:=nextVertex;
  929. vertA:=vertC;
  930. until not FindTriangleWithEdge(vertB, vertA);
  931. end;
  932. var
  933. i, n, triangle : Integer;
  934. loneTriangles : TIntegerList;
  935. begin
  936. Assert((indices.Count mod 3)=0, 'indices count is not a multiple of 3!');
  937. Result:=TPersistentObjectList.Create;
  938. // direct access and cache vars
  939. indicesList:=indices.List;
  940. indicesCount:=indices.Count;
  941. // Build adjacency lookup table (vertex based, not triangle based)
  942. SetLength(vertexTris, maxVertexIndex+1);
  943. for i:=0 to High(vertexTris) do
  944. vertexTris[i]:=TIntegerList.Create;
  945. n:=0;
  946. triangle:=0;
  947. for i:=0 to indicesCount-1 do begin
  948. vertexTris[indicesList[i]].Add(triangle);
  949. if n=2 then begin
  950. n:=0;
  951. Inc(triangle, 3);
  952. end else Inc(n);
  953. end;
  954. // Now, we use a greedy algo to build triangle strips
  955. SetLength(accountedTriangles, indicesCount); // yeah, waste of memory
  956. if agglomerateLoneTriangles then begin
  957. loneTriangles:=TIntegerList.Create;
  958. Result.Add(loneTriangles);
  959. end else loneTriangles:=nil;
  960. i:=0; while i<indicesCount do begin
  961. if not accountedTriangles[i] then begin
  962. accountedTriangles[i]:=True;
  963. if FindTriangleWithEdge(indicesList[i+1], indicesList[i]) then begin
  964. currentStrip:=TIntegerList.Create;
  965. currentStrip.Add(indicesList[i+2]);
  966. BuildStrip(indicesList[i], indicesList[i+1]);
  967. end else if FindTriangleWithEdge(indicesList[i+2], indicesList[i+1]) then begin
  968. currentStrip:=TIntegerList.Create;
  969. currentStrip.Add(indicesList[i]);
  970. BuildStrip(indicesList[i+1], indicesList[i+2]);
  971. end else if FindTriangleWithEdge(indicesList[i], indicesList[i+2]) then begin
  972. currentStrip:=TIntegerList.Create;
  973. currentStrip.Add(indicesList[i+1]);
  974. BuildStrip(indicesList[i+2], indicesList[i]);
  975. end else begin
  976. if agglomerateLoneTriangles then
  977. currentStrip:=loneTriangles
  978. else currentStrip:=TIntegerList.Create;
  979. currentStrip.Add(indicesList[i], indicesList[i+1], indicesList[i+2]);
  980. end;
  981. if currentStrip<>loneTriangles then
  982. Result.Add(currentStrip);
  983. end;
  984. Inc(i, 3);
  985. end;
  986. // cleanup
  987. for i:=0 to High(vertexTris) do
  988. vertexTris[i].Free;
  989. end;
  990. procedure SubdivideTriangles(smoothFactor : Single;
  991. vertices : TAffineVectorList;
  992. triangleIndices : TIntegerList;
  993. normals : TAffineVectorList = nil;
  994. onSubdivideEdge : TSubdivideEdgeEvent = nil);
  995. var
  996. i, a, b, c, nv : Integer;
  997. edges : TIntegerList;
  998. triangleEdges : TIntegerList;
  999. p, n : TAffineVector;
  1000. f : Single;
  1001. begin
  1002. // build edges list
  1003. triangleEdges:=TIntegerList.Create;
  1004. try
  1005. edges:=BuildNonOrientedEdgesList(triangleIndices, triangleEdges);
  1006. try
  1007. nv:=vertices.Count;
  1008. // split all edges, add corresponding vertex & normal
  1009. i:=0;
  1010. while i<edges.Count do begin
  1011. a:=edges[i];
  1012. b:=edges[i+1];
  1013. p:=VectorLerp(vertices[a], vertices[b], 0.5);
  1014. if Assigned(normals) then begin
  1015. n:=VectorNormalize(VectorLerp(normals[a], normals[b], 0.5));
  1016. normals.Add(n);
  1017. if smoothFactor<>0 then begin
  1018. f:=0.25*smoothFactor*VectorDistance(vertices[a], vertices[b])
  1019. *(1-VectorDotProduct(normals[a], normals[b]));
  1020. if VectorDotProduct(normals[a], VectorSubtract(vertices[b], vertices[a]))
  1021. +VectorDotProduct(normals[b], VectorSubtract(vertices[a], vertices[b]))>0 then
  1022. f:=-f;
  1023. CombineVector(p, n, f);
  1024. end;
  1025. end;
  1026. if Assigned(onSubdivideEdge) then
  1027. onSubdivideEdge(a, b, vertices.Add(p))
  1028. else vertices.Add(p);
  1029. Inc(i, 2);
  1030. end;
  1031. // spawn new triangles geometry
  1032. i:=triangleIndices.Count-3;
  1033. while i>=0 do begin
  1034. a:=nv+triangleEdges[i+0] div 2;
  1035. b:=nv+triangleEdges[i+1] div 2;
  1036. c:=nv+triangleEdges[i+2] div 2;
  1037. triangleIndices.Add(triangleIndices[i+0], a, c);
  1038. triangleIndices.Add(a, triangleIndices[i+1], b);
  1039. triangleIndices.Add(b, triangleIndices[i+2], c);
  1040. triangleIndices[i+0]:=a;
  1041. triangleIndices[i+1]:=b;
  1042. triangleIndices[i+2]:=c;
  1043. Dec(i, 3);
  1044. end;
  1045. finally
  1046. edges.Free;
  1047. end;
  1048. finally
  1049. triangleEdges.Free;
  1050. end;
  1051. end;
  1052. type
  1053. TTriangleEdgeInfo = record
  1054. adjacentTriangle: array[0..2] of LongWord;
  1055. // Bits 0:1 is edge number of adjacent triangle 0
  1056. // Bits 2:3 is edge number of adjacent triangle 1
  1057. // Bits 4:5 is edge number of adjacent triangle 2
  1058. adjacentTriangleEdges: Byte;
  1059. openEdgeMask: Byte;
  1060. end;
  1061. TTriangleEdgeInfoArray = array of TTriangleEdgeInfo;
  1062. TTriangleBoundary = record
  1063. vertexIndex: LongWord;
  1064. triangle: LongWord;
  1065. edge: LongWord;
  1066. prev: LongWord;
  1067. next: array[0..2] of LongWord;
  1068. active: LongWord;
  1069. maxSqArea: Single;
  1070. end;
  1071. TTriangleBoundaryArray = array of TTriangleBoundary;
  1072. TVector3dw = array[0..2] of LongWord;
  1073. PVector3dw = ^TVector3dw;
  1074. var
  1075. indicesList: PLongWordArray; // Reference to indices list of usual triangles
  1076. VerticesList: PAffineVectorArray; // Reference to vertices list
  1077. PrimitiveNum: LongWord; // Number of triangles
  1078. edgeInfo: TTriangleEdgeInfoArray;
  1079. boundaryList: TTriangleBoundaryArray;
  1080. function sameVertex(i0, i1: LongWord): Boolean;
  1081. begin
  1082. Result := (VerticesList[i0].X = VerticesList[i1].X)
  1083. and (VerticesList[i0].Y = VerticesList[i1].Y)
  1084. and (VerticesList[i0].Z = VerticesList[i1].Z);
  1085. end;
  1086. procedure joinTriangles(
  1087. tri1: Integer; edge1: Cardinal;
  1088. tri2: Integer; edge2: Cardinal);
  1089. begin
  1090. Assert((edge1 < 3) and (edge2 < 3), 'joinTriangles: Multiple edge detected.');
  1091. edgeInfo[tri1].adjacentTriangle[edge1] := tri2;
  1092. edgeInfo[tri1].adjacentTriangleEdges := edgeInfo[tri1].adjacentTriangleEdges
  1093. and not (3 shl (2 * edge1));
  1094. edgeInfo[tri1].adjacentTriangleEdges := edgeInfo[tri1].adjacentTriangleEdges
  1095. or (edge2 shl (2 * edge1));
  1096. edgeInfo[tri2].adjacentTriangle[edge2] := tri1;
  1097. edgeInfo[tri2].adjacentTriangleEdges := edgeInfo[tri2].adjacentTriangleEdges
  1098. and not (3 shl (2 * edge2));
  1099. edgeInfo[tri2].adjacentTriangleEdges := edgeInfo[tri2].adjacentTriangleEdges
  1100. or (edge1 shl (2 * edge2));
  1101. end;
  1102. procedure matchWithTriangleSharingEdge(triangle, edge, v0, v1, otherv: LongWord);
  1103. var
  1104. i, j: Integer;
  1105. doubleTri: Integer;
  1106. otherEdge: Integer;
  1107. vertexIndex: PVector3dw;
  1108. begin
  1109. doubleTri := -1;
  1110. otherEdge := 0;
  1111. // Match shared edges based on vertex numbers (relatively fast).
  1112. for i := triangle + 1 to PrimitiveNum - 1 do
  1113. begin
  1114. j := i * 3;
  1115. vertexIndex := @indicesList[j];
  1116. if vertexIndex[0] = v0 then
  1117. if vertexIndex[2] = v1 then
  1118. if edgeInfo[i].adjacentTriangle[2] = $FFFFFFFF then
  1119. if vertexIndex[1] = otherv then
  1120. begin
  1121. if (doubleTri < 0) then
  1122. begin
  1123. doubleTri := i;
  1124. otherEdge := 2;
  1125. end;
  1126. end
  1127. else
  1128. begin
  1129. joinTriangles(i, 2, triangle, edge);
  1130. Exit;
  1131. end;
  1132. if vertexIndex[1] = v0 then
  1133. if vertexIndex[0] = v1 then
  1134. if edgeInfo[i].adjacentTriangle[0] = $FFFFFFFF then
  1135. if vertexIndex[2] = otherv then
  1136. begin
  1137. if doubleTri < 0 then
  1138. begin
  1139. doubleTri := i;
  1140. otherEdge := 0;
  1141. end;
  1142. end
  1143. else
  1144. begin
  1145. joinTriangles(i, 0, triangle, edge);
  1146. Exit;
  1147. end;
  1148. if vertexIndex[2] = v0 then
  1149. if vertexIndex[1] = v1 then
  1150. if edgeInfo[i].adjacentTriangle[1] = $FFFFFFFF then
  1151. if vertexIndex[0] = otherv then
  1152. begin
  1153. if doubleTri < 0 then
  1154. begin
  1155. doubleTri := i;
  1156. otherEdge := 1;
  1157. end;
  1158. end
  1159. else
  1160. begin
  1161. joinTriangles(i, 1, triangle, edge);
  1162. Exit;
  1163. end;
  1164. end;
  1165. // Match shared edges based on vertex XYZ values (slow check).
  1166. for i := triangle + 1 to PrimitiveNum - 1 do
  1167. begin
  1168. j := i * 3;
  1169. vertexIndex := @indicesList[j];
  1170. if sameVertex(vertexIndex[0], v0) then
  1171. if sameVertex(vertexIndex[2], v1) then
  1172. if edgeInfo[i].adjacentTriangle[2] = $FFFFFFFF then
  1173. if vertexIndex[0] = otherv then
  1174. begin
  1175. if doubleTri < 0 then
  1176. begin
  1177. doubleTri := i;
  1178. otherEdge := 2;
  1179. end;
  1180. end
  1181. else
  1182. begin
  1183. joinTriangles(i, 2, triangle, edge);
  1184. Exit;
  1185. end;
  1186. if sameVertex(vertexIndex[1], v0) then
  1187. if sameVertex(vertexIndex[0], v1) then
  1188. if edgeInfo[i].adjacentTriangle[0] = $FFFFFFFF then
  1189. if vertexIndex[0] = otherv then
  1190. begin
  1191. if doubleTri < 0 then
  1192. begin
  1193. doubleTri := i;
  1194. otherEdge := 0;
  1195. end;
  1196. end
  1197. else
  1198. begin
  1199. joinTriangles(i, 0, triangle, edge);
  1200. Exit;
  1201. end;
  1202. if sameVertex(vertexIndex[2], v0) then
  1203. if sameVertex(vertexIndex[1], v1) then
  1204. if edgeInfo[i].adjacentTriangle[1] = $FFFFFFFF then
  1205. if vertexIndex[0] = otherv then
  1206. begin
  1207. if doubleTri < 0 then
  1208. begin
  1209. doubleTri := i;
  1210. otherEdge := 1;
  1211. end;
  1212. end
  1213. else
  1214. begin
  1215. joinTriangles(i, 1, triangle, edge);
  1216. Exit;
  1217. end;
  1218. end;
  1219. // Only connect a triangle to a triangle with the exact
  1220. // same three vertices as a last resort.
  1221. if doubleTri >= 0 then
  1222. joinTriangles(doubleTri, otherEdge, triangle, edge);
  1223. end;
  1224. function ComputeTriangleEdgeInfo: Boolean;
  1225. var
  1226. i, j: Integer;
  1227. vertexIndex: PVector3dw;
  1228. begin
  1229. Result := true;
  1230. try
  1231. // Initialize edge information as if all triangles are fully disconnected.
  1232. for i := 0 to PrimitiveNum - 1 do
  1233. begin
  1234. edgeInfo[i].adjacentTriangle[0] := $FFFFFFFF; // Vertex 0,1 edge
  1235. edgeInfo[i].adjacentTriangle[1] := $FFFFFFFF; // Vertex 1,2 edge
  1236. edgeInfo[i].adjacentTriangle[2] := $FFFFFFFF; // Vertex 2,0 edge
  1237. edgeInfo[i].adjacentTriangleEdges := (3 shl 0) or (3 shl 2) or (3 shl 4);
  1238. edgeInfo[i].openEdgeMask := 0;
  1239. end;
  1240. for i := 0 to PrimitiveNum - 1 do
  1241. begin
  1242. j := i * 3;
  1243. vertexIndex := @indicesList[j];
  1244. if edgeInfo[i].adjacentTriangle[0] = $FFFFFFFF then
  1245. matchWithTriangleSharingEdge(i, 0,
  1246. vertexIndex[0], vertexIndex[1], vertexIndex[2]);
  1247. if edgeInfo[i].adjacentTriangle[1] = $FFFFFFFF then
  1248. matchWithTriangleSharingEdge(i, 1,
  1249. vertexIndex[1], vertexIndex[2], vertexIndex[0]);
  1250. if edgeInfo[i].adjacentTriangle[2] = $FFFFFFFF then
  1251. matchWithTriangleSharingEdge(i, 2,
  1252. vertexIndex[2], vertexIndex[0], vertexIndex[1]);
  1253. end;
  1254. except
  1255. Result := false;
  1256. end;
  1257. end;
  1258. procedure findOpenBoundary(triangle, edge: LongWord;
  1259. var boundaryVertices: LongWord);
  1260. var
  1261. v0, v, nextEdge, otherTriangle, count: LongWord;
  1262. i: Byte;
  1263. finded: Boolean;
  1264. begin
  1265. count := 0;
  1266. if (edgeInfo[triangle].openEdgeMask and (1 shl edge)) <> 0 then
  1267. Exit;
  1268. Assert(edgeInfo[triangle].adjacentTriangle[edge] = $FFFFFFFF);
  1269. edgeInfo[triangle].openEdgeMask := edgeInfo[triangle].openEdgeMask or (1 shl
  1270. edge);
  1271. v0 := indicesList[3 * triangle + edge];
  1272. boundaryList[count].vertexIndex := v0;
  1273. boundaryList[count].triangle := triangle;
  1274. boundaryList[count].edge := edge;
  1275. Inc(count);
  1276. nextEdge := (edge + 1) mod 3;
  1277. v := indicesList[3 * triangle + nextEdge];
  1278. while not sameVertex(v, v0) do
  1279. begin
  1280. otherTriangle := edgeInfo[triangle].adjacentTriangle[nextEdge];
  1281. while otherTriangle <> $FFFFFFFF do
  1282. begin
  1283. finded := false;
  1284. for i := 0 to 2 do
  1285. if edgeInfo[otherTriangle].adjacentTriangle[i] = triangle then
  1286. begin
  1287. Assert(sameVertex(indicesList[3 * otherTriangle + (i + 1) mod 3], v));
  1288. triangle := otherTriangle;
  1289. nextEdge := (i + 1) mod 3;
  1290. finded := true;
  1291. Break;
  1292. end;
  1293. Assert(finded);
  1294. otherTriangle := edgeInfo[triangle].adjacentTriangle[nextEdge];
  1295. end;
  1296. // Mark this edge as processed to avoid reprocessing
  1297. // the boundary multiple times.
  1298. edgeInfo[triangle].openEdgeMask :=
  1299. edgeInfo[triangle].openEdgeMask or (1 shl nextEdge);
  1300. boundaryList[count].vertexIndex := v;
  1301. boundaryList[count].triangle := triangle;
  1302. boundaryList[count].edge := nextEdge;
  1303. Inc(count);
  1304. nextEdge := (nextEdge + 1) mod 3;
  1305. v := indicesList[3 * triangle + nextEdge];
  1306. end;
  1307. boundaryVertices := count;
  1308. end;
  1309. function polygonArea(boundaryIndex: LongWord): Single;
  1310. var
  1311. // Md2TriangleVertex *v;
  1312. d01, d02, prod: TVector3f;
  1313. v0, v1, v2: Integer;
  1314. begin
  1315. // Get the vertices of the triangle along the boundary.
  1316. v0 := boundaryList[boundaryIndex].vertexIndex;
  1317. v1 := boundaryList[boundaryList[boundaryIndex].next[0]].vertexIndex;
  1318. v2 := boundaryList[boundaryList[boundaryIndex].next[1]].vertexIndex;
  1319. // Compute the area of the triangle
  1320. d01 := VectorSubtract(VerticesList[v0], VerticesList[v1]);
  1321. d02 := VectorSubtract(VerticesList[v0], VerticesList[v2]);
  1322. prod := VectorCrossProduct(d01, d02);
  1323. Result := VectorLength(prod);
  1324. end;
  1325. procedure fixOpenTriangle(boundaryIndex: LongWord);
  1326. var
  1327. newTriIndex, b0, bp, b1, b2: LongWord;
  1328. begin
  1329. b0 := boundaryIndex;
  1330. bp := boundaryList[b0].prev;
  1331. b1 := boundaryList[b0].next[0];
  1332. b2 := boundaryList[b0].next[1];
  1333. Assert(boundaryList[b1].next[0] = b2);
  1334. Assert(boundaryList[bp].next[0] = b0);
  1335. Assert(boundaryList[bp].next[1] = b1);
  1336. // Initialize the new triangle.
  1337. indicesList[PrimitiveNum*3+0] := boundaryList[b2].vertexIndex;
  1338. indicesList[PrimitiveNum*3+1] := boundaryList[b1].vertexIndex;
  1339. indicesList[PrimitiveNum*3+2] := boundaryList[b0].vertexIndex;
  1340. Inc(PrimitiveNum);
  1341. // Mark edge 2 unconnected
  1342. newTriIndex := indicesList[PrimitiveNum*3-3];
  1343. edgeInfo[newTriIndex].adjacentTriangle[2] := $FFFFFFFF;
  1344. edgeInfo[newTriIndex].adjacentTriangleEdges := 3 shl 4;
  1345. // Make sure edges we are joining are currently unconnected.
  1346. Assert(edgeInfo[boundaryList[b1].triangle].adjacentTriangle[boundaryList[b1].edge] = $FFFFFFFF);
  1347. Assert(edgeInfo[boundaryList[b0].triangle].adjacentTriangle[boundaryList[b0].edge] = $FFFFFFFF);
  1348. // Join the triangles with the new triangle.
  1349. joinTriangles(newTriIndex, 0, boundaryList[b1].triangle, boundaryList[b1].edge);
  1350. joinTriangles(newTriIndex, 1, boundaryList[b0].triangle, boundaryList[b0].edge);
  1351. // Update the boundary list based on the addition of the new triangle.
  1352. boundaryList[b0].triangle := newTriIndex;
  1353. boundaryList[b0].edge := 2;
  1354. boundaryList[b0].next[0] := b2;
  1355. boundaryList[b0].next[1] := boundaryList[b2].next[0];
  1356. boundaryList[b0].maxSqArea := GLMeshUtils.polygonArea(b0);
  1357. boundaryList[bp].next[1] := b2;
  1358. boundaryList[b1].active := 0;
  1359. boundaryList[b2].prev := b0;
  1360. end;
  1361. procedure fixOpenBoundary(Count: LongWord);
  1362. var
  1363. b0, b1, b2: LongWord;
  1364. i: Integer;
  1365. maxMaxSqArea: Single;
  1366. numActive: LongWord;
  1367. minIndex: LongWord;
  1368. min: Single;
  1369. begin
  1370. if Count = 1 then
  1371. {Ugh, a degenerate triangle with two (or perhaps three)
  1372. identical vertices tricking us into thinking that there
  1373. is an open edge. Hopefully these should be eliminated
  1374. by an earlier "eliminate" pass, but such triangles are
  1375. harmless. }
  1376. exit;
  1377. Assert(count >= 3);
  1378. if count = 3 then
  1379. begin
  1380. {Often a common case. Save bookkeeping and close the triangle
  1381. boundary immediately. }
  1382. b0 := 0;
  1383. b1 := 1;
  1384. b2 := 2;
  1385. end
  1386. else
  1387. begin
  1388. minIndex := 0;
  1389. boundaryList[0].prev := count - 1;
  1390. boundaryList[0].next[0] := 1;
  1391. boundaryList[0].next[1] := 2;
  1392. boundaryList[0].active := 1;
  1393. for i := 1 to count - 3 do
  1394. begin
  1395. boundaryList[i].prev := i - 1;
  1396. boundaryList[i].next[0] := i + 1;
  1397. boundaryList[i].next[1] := i + 2;
  1398. boundaryList[i].active := 1;
  1399. end;
  1400. i := count - 3;
  1401. boundaryList[i].prev := i - 1;
  1402. boundaryList[i].next[0] := i + 1;
  1403. boundaryList[i].next[1] := 0;
  1404. boundaryList[i].active := 1;
  1405. boundaryList[i + 1].prev := i;
  1406. boundaryList[i + 1].next[0] := 0;
  1407. boundaryList[i + 1].next[1] := 1;
  1408. boundaryList[i + 1].active := 1;
  1409. boundaryList[0].maxSqArea := GLMeshUtils.polygonArea(0);
  1410. maxMaxSqArea := boundaryList[0].maxSqArea;
  1411. for i := 1 to count - 1 do
  1412. begin
  1413. boundaryList[i].maxSqArea := GLMeshUtils.polygonArea(i);
  1414. if boundaryList[i].maxSqArea > maxMaxSqArea then
  1415. maxMaxSqArea := boundaryList[i].maxSqArea;
  1416. end;
  1417. {If triangles are formed from adjacent edges along the
  1418. boundary, at least front-facing such triangle should
  1419. be front-facing (ie, have a non-negative area). }
  1420. Assert(maxMaxSqArea >= 0.0);
  1421. maxMaxSqArea := 2.0 * maxMaxSqArea;
  1422. numActive := count;
  1423. while numActive > 3 do
  1424. begin
  1425. min := maxMaxSqArea;
  1426. for i := 0 to count - 1 do
  1427. if boundaryList[i].active > 0 then
  1428. if boundaryList[i].maxSqArea < min then
  1429. if boundaryList[i].maxSqArea >= 0.0 then
  1430. begin
  1431. min := boundaryList[i].maxSqArea;
  1432. minIndex := i;
  1433. end;
  1434. Assert(min < maxMaxSqArea);
  1435. fixOpenTriangle(minIndex);
  1436. {Newly created triangle formed from adjacent edges
  1437. along the boundary could be larger than the
  1438. previous largest triangle. }
  1439. if (boundaryList[minIndex].maxSqArea > maxMaxSqArea) then
  1440. maxMaxSqArea := 2.0 * boundaryList[minIndex].maxSqArea;
  1441. Dec(numActive);
  1442. end;
  1443. for i := 0 to count - 1 do
  1444. if boundaryList[i].active > 0 then
  1445. begin
  1446. minIndex := i;
  1447. Break;
  1448. end;
  1449. Assert(LongWord(i) < count);
  1450. b0 := minIndex;
  1451. b1 := boundaryList[b0].next[0];
  1452. b2 := boundaryList[b0].next[1];
  1453. Assert(boundaryList[b0].prev = b2);
  1454. Assert(boundaryList[b1].prev = b0);
  1455. Assert(boundaryList[b1].next[0] = b2);
  1456. Assert(boundaryList[b1].next[1] = b0);
  1457. Assert(boundaryList[b2].prev = b1);
  1458. Assert(boundaryList[b2].next[0] = b0);
  1459. Assert(boundaryList[b2].next[1] = b1);
  1460. end;
  1461. {Place final "keystone" triangle to fill completely
  1462. the open boundary. }
  1463. if LongWord(Length(edgeInfo)) < (PrimitiveNum + 1) then
  1464. SetLength(edgeInfo, Length(edgeInfo) + Integer(vEdgeInfoReserveSize));
  1465. // Initialize the new triangle.
  1466. indicesList[PrimitiveNum*3+0] := boundaryList[b2].vertexIndex;
  1467. indicesList[PrimitiveNum*3+1] := boundaryList[b1].vertexIndex;
  1468. indicesList[PrimitiveNum*3+2] := boundaryList[b0].vertexIndex;
  1469. // Join keystone triangle.
  1470. joinTriangles(PrimitiveNum, 0, boundaryList[b1].triangle,
  1471. boundaryList[b1].edge);
  1472. joinTriangles(PrimitiveNum, 1, boundaryList[b0].triangle,
  1473. boundaryList[b0].edge);
  1474. joinTriangles(PrimitiveNum, 2, boundaryList[b2].triangle,
  1475. boundaryList[b2].edge);
  1476. Inc(PrimitiveNum);
  1477. end;
  1478. procedure findAndFixOpenTriangleGroups(triangle: LongWord);
  1479. var
  1480. Count: LongWord;
  1481. begin
  1482. if Length(boundaryList)<Integer(1 + 2 * PrimitiveNum) then
  1483. SetLength(boundaryList, 1 + 2 * PrimitiveNum);
  1484. if edgeInfo[triangle].adjacentTriangle[0] = $FFFFFFFF then
  1485. begin
  1486. findOpenBoundary(triangle, 0, Count);
  1487. fixOpenBoundary(Count);
  1488. end;
  1489. if edgeInfo[triangle].adjacentTriangle[1] = $FFFFFFFF then
  1490. begin
  1491. findOpenBoundary(triangle, 1, Count);
  1492. fixOpenBoundary(Count);
  1493. end;
  1494. if edgeInfo[triangle].adjacentTriangle[2] = $FFFFFFFF then
  1495. begin
  1496. findOpenBoundary(triangle, 2, Count);
  1497. fixOpenBoundary(Count);
  1498. end;
  1499. end;
  1500. procedure CloseOpenTriangleGroups;
  1501. var
  1502. i: LongWord;
  1503. begin
  1504. i := 0;
  1505. while i < PrimitiveNum do
  1506. begin
  1507. if (edgeInfo[i].adjacentTriangle[0] = $FFFFFFFF)
  1508. or (edgeInfo[i].adjacentTriangle[1] = $FFFFFFFF)
  1509. or (edgeInfo[i].adjacentTriangle[2] = $FFFFFFFF) then
  1510. findAndFixOpenTriangleGroups(i);
  1511. Inc(i);
  1512. end;
  1513. end;
  1514. procedure CheckForBogusAdjacency;
  1515. function AdjacentEdge(x, n: Integer): Integer;
  1516. begin
  1517. Result := (x shr (2 * n)) and 3;
  1518. end;
  1519. var
  1520. i, j: Integer;
  1521. adjacentTriangle, adjacentTriangleSharedEdge: LongWord;
  1522. begin
  1523. for i := 0 to PrimitiveNum - 1 do
  1524. for j := 0 to 2 do
  1525. begin
  1526. adjacentTriangleSharedEdge :=
  1527. AdjacentEdge(edgeInfo[i].adjacentTriangleEdges, j);
  1528. adjacentTriangle := edgeInfo[i].adjacentTriangle[j];
  1529. if adjacentTriangle <> $FFFFFFFF then
  1530. begin
  1531. Assert(adjacentTriangleSharedEdge < 3);
  1532. Assert(edgeInfo[adjacentTriangle].adjacentTriangle[adjacentTriangleSharedEdge] = LongWord(i));
  1533. Assert(AdjacentEdge(edgeInfo[adjacentTriangle].adjacentTriangleEdges,
  1534. adjacentTriangleSharedEdge) = j);
  1535. end
  1536. else Assert(adjacentTriangleSharedEdge = 3);
  1537. end;
  1538. end;
  1539. procedure reconnectSharedEdges(isTri, wasTri: LongWord);
  1540. var
  1541. tri, count: LongWord;
  1542. i, j: Byte;
  1543. begin
  1544. for i := 0 to 3 do
  1545. begin
  1546. tri := edgeInfo[wasTri].adjacentTriangle[i];
  1547. if tri <>$FFFFFFFF then
  1548. begin
  1549. count := 0;
  1550. for j := 0 to 3 do
  1551. begin
  1552. if edgeInfo[tri].adjacentTriangle[j] = wasTri then
  1553. begin
  1554. edgeInfo[tri].adjacentTriangle[j] := isTri;
  1555. Inc(count);
  1556. end;
  1557. if edgeInfo[tri].adjacentTriangle[j] = isTri then
  1558. Inc(count);
  1559. end;
  1560. assert(count > 0);
  1561. end;
  1562. end;
  1563. end;
  1564. procedure possiblyReconnectTriangle(tri, isTri, wasTri: LongWord);
  1565. var
  1566. j: Byte;
  1567. begin
  1568. for j := 0 to 3 do
  1569. if edgeInfo[tri].adjacentTriangle[j] = wasTri then
  1570. edgeInfo[tri].adjacentTriangle[j] := isTri;
  1571. end;
  1572. function eliminateAdjacentDegeneratePair(
  1573. badTri, otherBadTri, goodTri: LongWord): LongWord;
  1574. var
  1575. otherGoodTri: LongWord;
  1576. i: Integer;
  1577. j: Byte;
  1578. begin
  1579. assert(badTri < PrimitiveNum);
  1580. assert(otherBadTri < PrimitiveNum);
  1581. assert(goodTri < PrimitiveNum);
  1582. otherGoodTri := 0;
  1583. {The other good triangle is the triangle adjacent to the other
  1584. bad triangle but which is not the bad triangle. }
  1585. for i :=0 to 3 do
  1586. if edgeInfo[otherBadTri].adjacentTriangle[i] <> badTri then
  1587. begin
  1588. otherGoodTri := edgeInfo[otherBadTri].adjacentTriangle[i];
  1589. break;
  1590. end;
  1591. assert(i < 3);
  1592. {Fix the good triangle so that both edges adjacent to the
  1593. bad triangle are now adjacent to the other good triangle. }
  1594. for i :=0 to 3 do
  1595. if edgeInfo[goodTri].adjacentTriangle[i] = badTri then
  1596. edgeInfo[goodTri].adjacentTriangle[i] := otherGoodTri;
  1597. {Fix the other good triangle so that both edges adjacent to the
  1598. other bad triangle are now adjacent to the good triangle. }
  1599. for i :=0 to 3 do
  1600. if edgeInfo[otherGoodTri].adjacentTriangle[i] = otherBadTri then
  1601. edgeInfo[otherGoodTri].adjacentTriangle[i] := goodTri;
  1602. {Decrement the object's triangle count by 2. Then copy
  1603. non-degenerate triangles from the end of the triangle
  1604. list to the slots once used by the eliminated triangles.
  1605. Be sure to copy the edgeInfo data structure too. Also
  1606. if goodTri is one of the last two triangles, be careful
  1607. to make sure it gets copied. }
  1608. Dec(PrimitiveNum, 2);
  1609. if goodTri < PrimitiveNum then
  1610. begin
  1611. PVector3dw(@indicesList[3*badTri])^ :=
  1612. PVector3dw(@indicesList[3*PrimitiveNum+3])^;
  1613. edgeInfo[badTri] := edgeInfo[PrimitiveNum+1];
  1614. PVector3dw(@indicesList[3*otherBadTri])^ :=
  1615. PVector3dw(@indicesList[3*PrimitiveNum])^;
  1616. edgeInfo[otherBadTri] := edgeInfo[PrimitiveNum];
  1617. reconnectSharedEdges(badTri, PrimitiveNum+1);
  1618. reconnectSharedEdges(otherBadTri, PrimitiveNum);
  1619. {We are moving two triangles and they each might be
  1620. connected to each other. Possibly reconnect the
  1621. edges appropriately if so. }
  1622. possiblyReconnectTriangle(badTri, otherBadTri, PrimitiveNum);
  1623. possiblyReconnectTriangle(otherBadTri, badTri, PrimitiveNum+1);
  1624. end
  1625. else begin
  1626. if goodTri = PrimitiveNum+1 then
  1627. if badTri < PrimitiveNum then
  1628. begin
  1629. PVector3dw(@indicesList[3*badTri])^ :=
  1630. PVector3dw(@indicesList[3*PrimitiveNum+3])^;
  1631. edgeInfo[badTri] := edgeInfo[PrimitiveNum+1];
  1632. PVector3dw(@indicesList[3*otherBadTri])^ :=
  1633. PVector3dw(@indicesList[3*PrimitiveNum])^;
  1634. edgeInfo[otherBadTri] := edgeInfo[PrimitiveNum];
  1635. reconnectSharedEdges(badTri, PrimitiveNum+1);
  1636. possiblyReconnectTriangle(badTri, otherBadTri, PrimitiveNum);
  1637. if otherBadTri < PrimitiveNum then
  1638. begin
  1639. reconnectSharedEdges(otherBadTri, PrimitiveNum);
  1640. possiblyReconnectTriangle(otherBadTri, badTri, PrimitiveNum+1);
  1641. end;
  1642. goodTri := badTri;
  1643. end
  1644. else begin
  1645. assert(otherBadTri < PrimitiveNum);
  1646. PVector3dw(@indicesList[3*otherBadTri])^ :=
  1647. PVector3dw(@indicesList[3*PrimitiveNum+3])^;
  1648. edgeInfo[otherBadTri] := edgeInfo[PrimitiveNum+1];
  1649. PVector3dw(@indicesList[3*badTri])^ :=
  1650. PVector3dw(@indicesList[3*PrimitiveNum])^;
  1651. edgeInfo[badTri] := edgeInfo[PrimitiveNum];
  1652. reconnectSharedEdges(otherBadTri, PrimitiveNum+1);
  1653. possiblyReconnectTriangle(otherBadTri, badTri, PrimitiveNum);
  1654. if badTri < PrimitiveNum then
  1655. begin
  1656. reconnectSharedEdges(badTri, PrimitiveNum);
  1657. possiblyReconnectTriangle(badTri, otherBadTri, PrimitiveNum+1);
  1658. end;
  1659. goodTri := otherBadTri;
  1660. end
  1661. else begin
  1662. assert(goodTri = PrimitiveNum);
  1663. if badTri < PrimitiveNum then
  1664. begin
  1665. PVector3dw(@indicesList[3*badTri])^ :=
  1666. PVector3dw(@indicesList[3*PrimitiveNum])^;
  1667. edgeInfo[badTri] := edgeInfo[PrimitiveNum];
  1668. PVector3dw(@indicesList[3*otherBadTri])^ :=
  1669. PVector3dw(@indicesList[3*PrimitiveNum+3])^;
  1670. edgeInfo[otherBadTri] := edgeInfo[PrimitiveNum+1];
  1671. reconnectSharedEdges(badTri, PrimitiveNum);
  1672. possiblyReconnectTriangle(badTri, otherBadTri, PrimitiveNum+1);
  1673. if otherBadTri < PrimitiveNum then
  1674. begin
  1675. reconnectSharedEdges(otherBadTri, PrimitiveNum+1);
  1676. possiblyReconnectTriangle(otherBadTri, badTri, PrimitiveNum);
  1677. end;
  1678. goodTri := badTri;
  1679. end
  1680. else begin
  1681. assert(otherBadTri < PrimitiveNum);
  1682. PVector3dw(@indicesList[3*otherBadTri])^ :=
  1683. PVector3dw(@indicesList[3*PrimitiveNum])^;
  1684. edgeInfo[otherBadTri] := edgeInfo[PrimitiveNum];
  1685. PVector3dw(@indicesList[3*badTri])^ :=
  1686. PVector3dw(@indicesList[3*PrimitiveNum+3])^;
  1687. edgeInfo[badTri] := edgeInfo[PrimitiveNum+1];
  1688. reconnectSharedEdges(otherBadTri, PrimitiveNum);
  1689. possiblyReconnectTriangle(otherBadTri, badTri, PrimitiveNum+1);
  1690. if badTri < PrimitiveNum then
  1691. begin
  1692. reconnectSharedEdges(badTri, PrimitiveNum+1);
  1693. possiblyReconnectTriangle(badTri, otherBadTri, PrimitiveNum);
  1694. end;
  1695. goodTri := otherBadTri;
  1696. end;
  1697. end;
  1698. end;
  1699. assert(goodTri < PrimitiveNum);
  1700. {Patch up the edge info for the two relocated triangles. }
  1701. for i := PrimitiveNum-1 downto 0 do
  1702. for j := 0 to 3 do
  1703. assert(edgeInfo[i].adjacentTriangle[j] < PrimitiveNum);
  1704. {Two degenerate triangles eliminated. }
  1705. Result := 2;
  1706. end;
  1707. function findAndFixAdjacentDegeneratePair(tri: LongWord): Integer;
  1708. var
  1709. t0, t1, t2: LongWord;
  1710. begin
  1711. t0 := edgeInfo[tri].adjacentTriangle[0];
  1712. t1 := edgeInfo[tri].adjacentTriangle[1];
  1713. t2 := edgeInfo[tri].adjacentTriangle[2];
  1714. {Trivially degnerate triangles should have already been eliminated. }
  1715. assert(t0 <> tri);
  1716. assert(t1 <> tri);
  1717. assert(t2 <> tri);
  1718. if (t0 = t1) and (t1 = t2) then
  1719. begin
  1720. if t0 <> $FFFFFFFF then
  1721. begin
  1722. assert(edgeInfo[t0].adjacentTriangle[0] = tri);
  1723. assert(edgeInfo[t0].adjacentTriangle[1] = tri);
  1724. assert(edgeInfo[t0].adjacentTriangle[2] = tri);
  1725. end;
  1726. Result := 0;
  1727. exit;
  1728. end;
  1729. if t0 = t1 then
  1730. if t0 <> $FFFFFFFF then
  1731. begin
  1732. Result := eliminateAdjacentDegeneratePair(tri, t0, t2);
  1733. exit;
  1734. end;
  1735. if t1 = t2 then
  1736. if t1 <> $FFFFFFFF then
  1737. begin
  1738. Result := eliminateAdjacentDegeneratePair(tri, t1, t0);
  1739. exit;
  1740. end;
  1741. if t2 = t0 then
  1742. if t1 <> $FFFFFFFF then
  1743. begin
  1744. Result := eliminateAdjacentDegeneratePair(tri, t2, t1);
  1745. exit;
  1746. end;
  1747. Result := 0;
  1748. end;
  1749. procedure EliminateAdjacentDegenerateTriangles;
  1750. var
  1751. count: Integer;
  1752. loopCount: Integer;
  1753. i: Integer;
  1754. begin
  1755. {Eliminating two degenerate triangle pairs may
  1756. not be the end of the story if the two "good" triangles
  1757. that get connected are also degenerate. Loop to
  1758. handle this unlikely event. }
  1759. count := 0;
  1760. repeat
  1761. loopCount := count;
  1762. for i := 0 to PrimitiveNum-1 do
  1763. count := count + findAndFixAdjacentDegeneratePair(i);
  1764. until count > loopCount;
  1765. end;
  1766. function MakeTriangleAdjacencyList(
  1767. const AindicesList: PLongWordArray; Count: LongWord;
  1768. const AVerticesList: PAffineVectorArray): TLongWordList;
  1769. function AdjacentEdge(x, n: Integer): Integer;
  1770. begin
  1771. Result := (x shr (2 * n)) and 3;
  1772. end;
  1773. var
  1774. i: Integer;
  1775. j: Byte;
  1776. N, ii, jj: LongWord;
  1777. tri, adjtri: TVector3dw;
  1778. NewIndices: TLongWordList;
  1779. begin
  1780. Result := nil;
  1781. Assert(Assigned(AindicesList));
  1782. Assert(Assigned(AVerticesList));
  1783. PrimitiveNum := Count div 3;
  1784. Assert(PrimitiveNum > 0);
  1785. IndicesList := AindicesList;
  1786. VerticesList := AVerticesList;
  1787. SetLength(edgeInfo, vEdgeInfoReserveSize + PrimitiveNum);
  1788. if not ComputeTriangleEdgeInfo then
  1789. exit;
  1790. CheckForBogusAdjacency;
  1791. if vImprovedFixingOpenTriangleEdge then
  1792. begin
  1793. CloseOpenTriangleGroups;
  1794. EliminateAdjacentDegenerateTriangles;
  1795. end;
  1796. NewIndices := TLongWordList.Create;
  1797. NewIndices.SetCountResetsMemory := false;
  1798. NewIndices.Capacity := 6 * PrimitiveNum;
  1799. for i := 0 to PrimitiveNum - 1 do
  1800. begin
  1801. N := 3 * i;
  1802. tri[0] := indicesList[N + 0];
  1803. tri[1] := indicesList[N + 1];
  1804. tri[2] := indicesList[N + 2];
  1805. for j := 0 to 2 do
  1806. begin
  1807. NewIndices.Add(tri[j]);
  1808. N := edgeInfo[i].adjacentTriangle[j];
  1809. if N=$FFFFFFFF then
  1810. begin
  1811. jj := (j + 2) mod 3;
  1812. NewIndices.Add(tri[jj]);
  1813. end
  1814. else begin
  1815. N := 3 * N;
  1816. adjtri[0] := indicesList[N + 0];
  1817. adjtri[1] := indicesList[N + 1];
  1818. adjtri[2] := indicesList[N + 2];
  1819. ii := (AdjacentEdge(edgeInfo[i].adjacentTriangleEdges, j) + 2) mod 3;
  1820. NewIndices.Add(adjtri[ii]);
  1821. end;
  1822. end;
  1823. end;
  1824. Result := NewIndices;
  1825. end;
  1826. function ConvertStripToList(
  1827. const AindicesList: PLongWordArray;
  1828. Count: LongWord;
  1829. RestartIndex: LongWord): TLongWordList;
  1830. var
  1831. i: Integer;
  1832. Index, prevIndex1, prevIndex2, stripCount: LongWord;
  1833. NewIndices: TLongWordList;
  1834. begin
  1835. Result := nil;
  1836. if not Assigned(AindicesList) or (Count<3) then
  1837. exit;
  1838. NewIndices := TLongWordList.Create;
  1839. stripCount := 0;
  1840. prevIndex1 := 0;
  1841. prevIndex2 := 0;
  1842. for i := 0 to Count - 1 do
  1843. begin
  1844. Index := AindicesList[i];
  1845. if stripCount>2 then
  1846. begin
  1847. // Check for restart index
  1848. if Index=RestartIndex then
  1849. begin
  1850. stripCount := 0;
  1851. continue;
  1852. end
  1853. // Check for degenerate triangles
  1854. else if Index=prevIndex1 then
  1855. begin
  1856. continue;
  1857. end
  1858. else if prevIndex1=prevIndex2 then
  1859. begin
  1860. stripCount := 0;
  1861. continue;
  1862. end;
  1863. if Boolean(stripCount and 1) then
  1864. begin
  1865. NewIndices.Add(prevIndex2);
  1866. NewIndices.Add(prevIndex1);
  1867. end
  1868. else begin
  1869. NewIndices.Add(prevIndex1);
  1870. NewIndices.Add(prevIndex2);
  1871. end;
  1872. end
  1873. else if stripCount=2 then
  1874. begin
  1875. NewIndices.Add(prevIndex1);
  1876. NewIndices.Items[NewIndices.Count-2] := Index;
  1877. prevIndex2 := prevIndex1;
  1878. prevIndex1 := Index;
  1879. Inc(stripCount);
  1880. continue;
  1881. end;
  1882. NewIndices.Add(Index);
  1883. prevIndex2 := prevIndex1;
  1884. prevIndex1 := Index;
  1885. Inc(stripCount);
  1886. end;
  1887. Result := NewIndices;
  1888. end;
  1889. function ConvertFansToList(
  1890. const AindicesList: PLongWordArray;
  1891. Count: LongWord;
  1892. RestartIndex: LongWord): TLongWordList;
  1893. var
  1894. i: Integer;
  1895. Index, centerIndex, prevIndex, fansCount: LongWord;
  1896. NewIndices: TLongWordList;
  1897. degenerate: Boolean;
  1898. begin
  1899. Result := nil;
  1900. if not Assigned(AindicesList) or (Count<3) then
  1901. exit;
  1902. NewIndices := TLongWordList.Create;
  1903. fansCount := 0;
  1904. prevIndex := 0;
  1905. degenerate := false;
  1906. centerIndex := AindicesList[0];
  1907. for i := 0 to Count - 1 do
  1908. begin
  1909. Index := AindicesList[i];
  1910. if fansCount>2 then
  1911. begin
  1912. // Check for restart index
  1913. if Index=RestartIndex then
  1914. begin
  1915. fansCount := 0;
  1916. continue;
  1917. end
  1918. // Check for degenerate triangles
  1919. else if Index=prevIndex then
  1920. begin
  1921. degenerate := true;
  1922. continue;
  1923. end
  1924. else if degenerate then
  1925. begin
  1926. degenerate := false;
  1927. fansCount := 0;
  1928. continue;
  1929. end;
  1930. NewIndices.Add(centerIndex);
  1931. NewIndices.Add(prevIndex);
  1932. end
  1933. else if fansCount=0 then
  1934. centerIndex := Index;
  1935. NewIndices.Add(Index);
  1936. prevIndex := Index;
  1937. Inc(fansCount);
  1938. end;
  1939. Result := NewIndices;
  1940. end;
  1941. end.