GLS.MeshUtils.pas 65 KB

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