GXS.MeshUtils.pas 65 KB

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