mikktspace.c 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914
  1. /** \file
  2. * \ingroup mikktspace
  3. */
  4. /**
  5. * Copyright (C) 2011 by Morten S. Mikkelsen
  6. *
  7. * This software is provided 'as-is', without any express or implied
  8. * warranty. In no event will the authors be held liable for any damages
  9. * arising from the use of this software.
  10. *
  11. * Permission is granted to anyone to use this software for any purpose,
  12. * including commercial applications, and to alter it and redistribute it
  13. * freely, subject to the following restrictions:
  14. *
  15. * 1. The origin of this software must not be misrepresented; you must not
  16. * claim that you wrote the original software. If you use this software
  17. * in a product, an acknowledgment in the product documentation would be
  18. * appreciated but is not required.
  19. * 2. Altered source versions must be plainly marked as such, and must not be
  20. * misrepresented as being the original software.
  21. * 3. This notice may not be removed or altered from any source distribution.
  22. */
  23. #include <assert.h>
  24. #include <stdio.h>
  25. #include <math.h>
  26. #include <string.h>
  27. #include <float.h>
  28. #include <stdlib.h>
  29. #include "mikktspace.h"
  30. #define TFALSE 0
  31. #define TTRUE 1
  32. #ifndef M_PI
  33. # define M_PI 3.1415926535897932384626433832795
  34. #endif
  35. #define INTERNAL_RND_SORT_SEED 39871946
  36. #ifdef _MSC_VER
  37. # define MIKK_INLINE static __forceinline
  38. #else
  39. # define MIKK_INLINE static inline __attribute__((always_inline)) __attribute__((unused))
  40. #endif
  41. // internal structure
  42. typedef struct {
  43. float x, y, z;
  44. } SVec3;
  45. MIKK_INLINE tbool veq(const SVec3 v1, const SVec3 v2)
  46. {
  47. return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
  48. }
  49. MIKK_INLINE SVec3 vadd(const SVec3 v1, const SVec3 v2)
  50. {
  51. SVec3 vRes;
  52. vRes.x = v1.x + v2.x;
  53. vRes.y = v1.y + v2.y;
  54. vRes.z = v1.z + v2.z;
  55. return vRes;
  56. }
  57. MIKK_INLINE SVec3 vsub(const SVec3 v1, const SVec3 v2)
  58. {
  59. SVec3 vRes;
  60. vRes.x = v1.x - v2.x;
  61. vRes.y = v1.y - v2.y;
  62. vRes.z = v1.z - v2.z;
  63. return vRes;
  64. }
  65. MIKK_INLINE SVec3 vscale(const float fS, const SVec3 v)
  66. {
  67. SVec3 vRes;
  68. vRes.x = fS * v.x;
  69. vRes.y = fS * v.y;
  70. vRes.z = fS * v.z;
  71. return vRes;
  72. }
  73. MIKK_INLINE float LengthSquared(const SVec3 v)
  74. {
  75. return v.x * v.x + v.y * v.y + v.z * v.z;
  76. }
  77. MIKK_INLINE float Length(const SVec3 v)
  78. {
  79. return sqrtf(LengthSquared(v));
  80. }
  81. #if 0 // UNUSED
  82. MIKK_INLINE SVec3 Normalize(const SVec3 v)
  83. {
  84. return vscale(1.0f / Length(v), v);
  85. }
  86. #endif
  87. MIKK_INLINE SVec3 NormalizeSafe(const SVec3 v)
  88. {
  89. const float len = Length(v);
  90. if (len != 0.0f) {
  91. return vscale(1.0f / len, v);
  92. }
  93. else {
  94. return v;
  95. }
  96. }
  97. MIKK_INLINE float vdot(const SVec3 v1, const SVec3 v2)
  98. {
  99. return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
  100. }
  101. MIKK_INLINE tbool NotZero(const float fX)
  102. {
  103. // could possibly use FLT_EPSILON instead
  104. return fabsf(fX) > FLT_MIN;
  105. }
  106. #if 0 // UNUSED
  107. MIKK_INLINE tbool VNotZero(const SVec3 v)
  108. {
  109. // might change this to an epsilon based test
  110. return NotZero(v.x) || NotZero(v.y) || NotZero(v.z);
  111. }
  112. #endif
  113. typedef struct {
  114. int iNrFaces;
  115. int *pTriMembers;
  116. } SSubGroup;
  117. typedef struct {
  118. int iNrFaces;
  119. int *pFaceIndices;
  120. int iVertexRepresentitive;
  121. tbool bOrientPreservering;
  122. } SGroup;
  123. //
  124. #define MARK_DEGENERATE 1
  125. #define QUAD_ONE_DEGEN_TRI 2
  126. #define GROUP_WITH_ANY 4
  127. #define ORIENT_PRESERVING 8
  128. typedef struct {
  129. int FaceNeighbors[3];
  130. SGroup *AssignedGroup[3];
  131. // normalized first order face derivatives
  132. SVec3 vOs, vOt;
  133. float fMagS, fMagT; // original magnitudes
  134. // determines if the current and the next triangle are a quad.
  135. int iOrgFaceNumber;
  136. int iFlag, iTSpacesOffs;
  137. unsigned char vert_num[4];
  138. } STriInfo;
  139. typedef struct {
  140. SVec3 vOs;
  141. float fMagS;
  142. SVec3 vOt;
  143. float fMagT;
  144. int iCounter; // this is to average back into quads.
  145. tbool bOrient;
  146. } STSpace;
  147. static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[],
  148. int piTriList_out[],
  149. const SMikkTSpaceContext *pContext,
  150. const int iNrTrianglesIn);
  151. static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[],
  152. const SMikkTSpaceContext *pContext,
  153. const int iNrTrianglesIn);
  154. static void InitTriInfo(STriInfo pTriInfos[],
  155. const int piTriListIn[],
  156. const SMikkTSpaceContext *pContext,
  157. const int iNrTrianglesIn);
  158. static int Build4RuleGroups(STriInfo pTriInfos[],
  159. SGroup pGroups[],
  160. int piGroupTrianglesBuffer[],
  161. const int piTriListIn[],
  162. const int iNrTrianglesIn);
  163. static tbool GenerateTSpaces(STSpace psTspace[],
  164. const STriInfo pTriInfos[],
  165. const SGroup pGroups[],
  166. const int iNrActiveGroups,
  167. const int piTriListIn[],
  168. const float fThresCos,
  169. const SMikkTSpaceContext *pContext);
  170. MIKK_INLINE int MakeIndex(const int iFace, const int iVert)
  171. {
  172. assert(iVert >= 0 && iVert < 4 && iFace >= 0);
  173. return (iFace << 2) | (iVert & 0x3);
  174. }
  175. MIKK_INLINE void IndexToData(int *piFace, int *piVert, const int iIndexIn)
  176. {
  177. piVert[0] = iIndexIn & 0x3;
  178. piFace[0] = iIndexIn >> 2;
  179. }
  180. static STSpace AvgTSpace(const STSpace *pTS0, const STSpace *pTS1)
  181. {
  182. STSpace ts_res;
  183. // this if is important. Due to floating point precision
  184. // averaging when ts0==ts1 will cause a slight difference
  185. // which results in tangent space splits later on
  186. if (pTS0->fMagS == pTS1->fMagS && pTS0->fMagT == pTS1->fMagT && veq(pTS0->vOs, pTS1->vOs) &&
  187. veq(pTS0->vOt, pTS1->vOt)) {
  188. ts_res.fMagS = pTS0->fMagS;
  189. ts_res.fMagT = pTS0->fMagT;
  190. ts_res.vOs = pTS0->vOs;
  191. ts_res.vOt = pTS0->vOt;
  192. }
  193. else {
  194. ts_res.fMagS = 0.5f * (pTS0->fMagS + pTS1->fMagS);
  195. ts_res.fMagT = 0.5f * (pTS0->fMagT + pTS1->fMagT);
  196. ts_res.vOs = vadd(pTS0->vOs, pTS1->vOs);
  197. ts_res.vOt = vadd(pTS0->vOt, pTS1->vOt);
  198. ts_res.vOs = NormalizeSafe(ts_res.vOs);
  199. ts_res.vOt = NormalizeSafe(ts_res.vOt);
  200. }
  201. return ts_res;
  202. }
  203. MIKK_INLINE SVec3 GetPosition(const SMikkTSpaceContext *pContext, const int index);
  204. MIKK_INLINE SVec3 GetNormal(const SMikkTSpaceContext *pContext, const int index);
  205. MIKK_INLINE SVec3 GetTexCoord(const SMikkTSpaceContext *pContext, const int index);
  206. // degen triangles
  207. static void DegenPrologue(STriInfo pTriInfos[],
  208. int piTriList_out[],
  209. const int iNrTrianglesIn,
  210. const int iTotTris);
  211. static void DegenEpilogue(STSpace psTspace[],
  212. STriInfo pTriInfos[],
  213. int piTriListIn[],
  214. const SMikkTSpaceContext *pContext,
  215. const int iNrTrianglesIn,
  216. const int iTotTris);
  217. tbool genTangSpaceDefault(const SMikkTSpaceContext *pContext)
  218. {
  219. return genTangSpace(pContext, 180.0f);
  220. }
  221. tbool genTangSpace(const SMikkTSpaceContext *pContext, const float fAngularThreshold)
  222. {
  223. // count nr_triangles
  224. int *piTriListIn = NULL, *piGroupTrianglesBuffer = NULL;
  225. STriInfo *pTriInfos = NULL;
  226. SGroup *pGroups = NULL;
  227. STSpace *psTspace = NULL;
  228. int iNrTrianglesIn = 0, f = 0, t = 0, i = 0;
  229. int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0;
  230. int iNrActiveGroups = 0, index = 0;
  231. const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext);
  232. tbool bRes = TFALSE;
  233. const float fThresCos = cosf((fAngularThreshold * (float)M_PI) / 180.0f);
  234. // verify all call-backs have been set
  235. if (pContext->m_pInterface->m_getNumFaces == NULL ||
  236. pContext->m_pInterface->m_getNumVerticesOfFace == NULL ||
  237. pContext->m_pInterface->m_getPosition == NULL ||
  238. pContext->m_pInterface->m_getNormal == NULL || pContext->m_pInterface->m_getTexCoord == NULL)
  239. return TFALSE;
  240. // count triangles on supported faces
  241. for (f = 0; f < iNrFaces; f++) {
  242. const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
  243. if (verts == 3)
  244. ++iNrTrianglesIn;
  245. else if (verts == 4)
  246. iNrTrianglesIn += 2;
  247. }
  248. if (iNrTrianglesIn <= 0)
  249. return TFALSE;
  250. // allocate memory for an index list
  251. piTriListIn = (int *)malloc(sizeof(int[3]) * iNrTrianglesIn);
  252. pTriInfos = (STriInfo *)malloc(sizeof(STriInfo) * iNrTrianglesIn);
  253. if (piTriListIn == NULL || pTriInfos == NULL) {
  254. if (piTriListIn != NULL)
  255. free(piTriListIn);
  256. if (pTriInfos != NULL)
  257. free(pTriInfos);
  258. return TFALSE;
  259. }
  260. // make an initial triangle --> face index list
  261. iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);
  262. // make a welded index list of identical positions and attributes (pos, norm, texc)
  263. // printf("gen welded index list begin\n");
  264. GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn);
  265. // printf("gen welded index list end\n");
  266. // Mark all degenerate triangles
  267. iTotTris = iNrTrianglesIn;
  268. iDegenTriangles = 0;
  269. for (t = 0; t < iTotTris; t++) {
  270. const int i0 = piTriListIn[t * 3 + 0];
  271. const int i1 = piTriListIn[t * 3 + 1];
  272. const int i2 = piTriListIn[t * 3 + 2];
  273. const SVec3 p0 = GetPosition(pContext, i0);
  274. const SVec3 p1 = GetPosition(pContext, i1);
  275. const SVec3 p2 = GetPosition(pContext, i2);
  276. if (veq(p0, p1) || veq(p0, p2) || veq(p1, p2)) // degenerate
  277. {
  278. pTriInfos[t].iFlag |= MARK_DEGENERATE;
  279. ++iDegenTriangles;
  280. }
  281. }
  282. iNrTrianglesIn = iTotTris - iDegenTriangles;
  283. // mark all triangle pairs that belong to a quad with only one
  284. // good triangle. These need special treatment in DegenEpilogue().
  285. // Additionally, move all good triangles to the start of
  286. // pTriInfos[] and piTriListIn[] without changing order and
  287. // put the degenerate triangles last.
  288. DegenPrologue(pTriInfos, piTriListIn, iNrTrianglesIn, iTotTris);
  289. // evaluate triangle level attributes and neighbor list
  290. // printf("gen neighbors list begin\n");
  291. InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn);
  292. // printf("gen neighbors list end\n");
  293. // based on the 4 rules, identify groups based on connectivity
  294. iNrMaxGroups = iNrTrianglesIn * 3;
  295. pGroups = (SGroup *)malloc(sizeof(SGroup) * iNrMaxGroups);
  296. piGroupTrianglesBuffer = (int *)malloc(sizeof(int[3]) * iNrTrianglesIn);
  297. if (pGroups == NULL || piGroupTrianglesBuffer == NULL) {
  298. if (pGroups != NULL)
  299. free(pGroups);
  300. if (piGroupTrianglesBuffer != NULL)
  301. free(piGroupTrianglesBuffer);
  302. free(piTriListIn);
  303. free(pTriInfos);
  304. return TFALSE;
  305. }
  306. // printf("gen 4rule groups begin\n");
  307. iNrActiveGroups = Build4RuleGroups(
  308. pTriInfos, pGroups, piGroupTrianglesBuffer, piTriListIn, iNrTrianglesIn);
  309. // printf("gen 4rule groups end\n");
  310. //
  311. psTspace = (STSpace *)malloc(sizeof(STSpace) * iNrTSPaces);
  312. if (psTspace == NULL) {
  313. free(piTriListIn);
  314. free(pTriInfos);
  315. free(pGroups);
  316. free(piGroupTrianglesBuffer);
  317. return TFALSE;
  318. }
  319. memset(psTspace, 0, sizeof(STSpace) * iNrTSPaces);
  320. for (t = 0; t < iNrTSPaces; t++) {
  321. psTspace[t].vOs.x = 1.0f;
  322. psTspace[t].vOs.y = 0.0f;
  323. psTspace[t].vOs.z = 0.0f;
  324. psTspace[t].fMagS = 1.0f;
  325. psTspace[t].vOt.x = 0.0f;
  326. psTspace[t].vOt.y = 1.0f;
  327. psTspace[t].vOt.z = 0.0f;
  328. psTspace[t].fMagT = 1.0f;
  329. }
  330. // make tspaces, each group is split up into subgroups if necessary
  331. // based on fAngularThreshold. Finally a tangent space is made for
  332. // every resulting subgroup
  333. // printf("gen tspaces begin\n");
  334. bRes = GenerateTSpaces(
  335. psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriListIn, fThresCos, pContext);
  336. // printf("gen tspaces end\n");
  337. // clean up
  338. free(pGroups);
  339. free(piGroupTrianglesBuffer);
  340. if (!bRes) // if an allocation in GenerateTSpaces() failed
  341. {
  342. // clean up and return false
  343. free(pTriInfos);
  344. free(piTriListIn);
  345. free(psTspace);
  346. return TFALSE;
  347. }
  348. // degenerate quads with one good triangle will be fixed by copying a space from
  349. // the good triangle to the coinciding vertex.
  350. // all other degenerate triangles will just copy a space from any good triangle
  351. // with the same welded index in piTriListIn[].
  352. DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris);
  353. free(pTriInfos);
  354. free(piTriListIn);
  355. index = 0;
  356. for (f = 0; f < iNrFaces; f++) {
  357. const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
  358. if (verts != 3 && verts != 4)
  359. continue;
  360. // I've decided to let degenerate triangles and group-with-anythings
  361. // vary between left/right hand coordinate systems at the vertices.
  362. // All healthy triangles on the other hand are built to always be either or.
  363. /*// force the coordinate system orientation to be uniform for every face.
  364. // (this is already the case for good triangles but not for
  365. // degenerate ones and those with bGroupWithAnything==true)
  366. bool bOrient = psTspace[index].bOrient;
  367. if (psTspace[index].iCounter == 0) // tspace was not derived from a group
  368. {
  369. // look for a space created in GenerateTSpaces() by iCounter>0
  370. bool bNotFound = true;
  371. int i=1;
  372. while (i<verts && bNotFound)
  373. {
  374. if (psTspace[index+i].iCounter > 0) bNotFound=false;
  375. else ++i;
  376. }
  377. if (!bNotFound) bOrient = psTspace[index+i].bOrient;
  378. }*/
  379. // set data
  380. for (i = 0; i < verts; i++) {
  381. const STSpace *pTSpace = &psTspace[index];
  382. float tang[] = {pTSpace->vOs.x, pTSpace->vOs.y, pTSpace->vOs.z};
  383. float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z};
  384. if (pContext->m_pInterface->m_setTSpace != NULL)
  385. pContext->m_pInterface->m_setTSpace(
  386. pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i);
  387. if (pContext->m_pInterface->m_setTSpaceBasic != NULL)
  388. pContext->m_pInterface->m_setTSpaceBasic(
  389. pContext, tang, pTSpace->bOrient == TTRUE ? 1.0f : (-1.0f), f, i);
  390. ++index;
  391. }
  392. }
  393. free(psTspace);
  394. return TTRUE;
  395. }
  396. ///////////////////////////////////////////////////////////////////////////////////////////////////
  397. typedef struct {
  398. float vert[3];
  399. int index;
  400. } STmpVert;
  401. static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[],
  402. const SMikkTSpaceContext *pContext,
  403. const int iNrTrianglesIn);
  404. typedef unsigned int uint;
  405. static uint float_as_uint(const float v)
  406. {
  407. return *((uint *)(&v));
  408. }
  409. #define HASH(x, y, z) (((x)*73856093) ^ ((y)*19349663) ^ ((z)*83492791))
  410. #define HASH_F(x, y, z) HASH(float_as_uint(x), float_as_uint(y), float_as_uint(z))
  411. /* Sort comp and data based on comp.
  412. * comp2 and data2 are used as temporary storage. */
  413. static void radixsort_pair(uint *comp, int *data, uint *comp2, int *data2, int n)
  414. {
  415. int shift = 0;
  416. for (int pass = 0; pass < 4; pass++, shift += 8) {
  417. int bins[257] = {0};
  418. /* Count number of elements per bin. */
  419. for (int i = 0; i < n; i++) {
  420. bins[((comp[i] >> shift) & 0xff) + 1]++;
  421. }
  422. /* Compute prefix sum to find position of each bin in the sorted array. */
  423. for (int i = 2; i < 256; i++) {
  424. bins[i] += bins[i - 1];
  425. }
  426. /* Insert the elements in their correct location based on their bin. */
  427. for (int i = 0; i < n; i++) {
  428. int pos = bins[(comp[i] >> shift) & 0xff]++;
  429. comp2[pos] = comp[i];
  430. data2[pos] = data[i];
  431. }
  432. /* Swap arrays. */
  433. int *tmpdata = data;
  434. data = data2;
  435. data2 = tmpdata;
  436. uint *tmpcomp = comp;
  437. comp = comp2;
  438. comp2 = tmpcomp;
  439. }
  440. }
  441. /* Merge identical vertices.
  442. * To find vertices with identical position, normal and texcoord, we calculate a hash of the 9
  443. * values. Then, by sorting based on that hash, identical elements (having identical hashes) will
  444. * be moved next to each other. Since there might be hash collisions, the elements of each block
  445. * are then compared with each other and duplicates are merged.
  446. */
  447. static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[],
  448. const SMikkTSpaceContext *pContext,
  449. const int iNrTrianglesIn)
  450. {
  451. int numVertices = iNrTrianglesIn * 3;
  452. uint *hashes = (uint *)malloc(sizeof(uint) * numVertices);
  453. int *indices = (int *)malloc(sizeof(int) * numVertices);
  454. uint *temp_hashes = (uint *)malloc(sizeof(uint) * numVertices);
  455. int *temp_indices = (int *)malloc(sizeof(int) * numVertices);
  456. if (hashes == NULL || indices == NULL || temp_hashes == NULL || temp_indices == NULL) {
  457. free(hashes);
  458. free(indices);
  459. free(temp_hashes);
  460. free(temp_indices);
  461. GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn);
  462. return;
  463. }
  464. for (int i = 0; i < numVertices; i++) {
  465. const int index = piTriList_in_and_out[i];
  466. const SVec3 vP = GetPosition(pContext, index);
  467. const uint hashP = HASH_F(vP.x, vP.y, vP.z);
  468. const SVec3 vN = GetNormal(pContext, index);
  469. const uint hashN = HASH_F(vN.x, vN.y, vN.z);
  470. const SVec3 vT = GetTexCoord(pContext, index);
  471. const uint hashT = HASH_F(vT.x, vT.y, vT.z);
  472. hashes[i] = HASH(hashP, hashN, hashT);
  473. indices[i] = i;
  474. }
  475. radixsort_pair(hashes, indices, temp_hashes, temp_indices, numVertices);
  476. free(temp_hashes);
  477. free(temp_indices);
  478. /* Process blocks of vertices with the same hash.
  479. * Vertices in the block might still be separate, but we know for sure that
  480. * vertices in different blocks will never be identical. */
  481. int blockstart = 0;
  482. while (blockstart < numVertices) {
  483. /* Find end of this block (exclusive). */
  484. uint hash = hashes[blockstart];
  485. int blockend = blockstart + 1;
  486. for (; blockend < numVertices; blockend++) {
  487. if (hashes[blockend] != hash)
  488. break;
  489. }
  490. for (int i = blockstart; i < blockend; i++) {
  491. int index1 = piTriList_in_and_out[indices[i]];
  492. const SVec3 vP = GetPosition(pContext, index1);
  493. const SVec3 vN = GetNormal(pContext, index1);
  494. const SVec3 vT = GetTexCoord(pContext, index1);
  495. for (int i2 = i + 1; i2 < blockend; i2++) {
  496. int index2 = piTriList_in_and_out[indices[i2]];
  497. if (index1 == index2)
  498. continue;
  499. if (veq(vP, GetPosition(pContext, index2)) && veq(vN, GetNormal(pContext, index2)) &&
  500. veq(vT, GetTexCoord(pContext, index2))) {
  501. piTriList_in_and_out[indices[i2]] = index1;
  502. /* Once i2>i has been identified as a duplicate, we can stop since any
  503. * i3>i2>i that is a duplicate of i (and therefore also i2) will also be
  504. * compared to i2 and therefore be identified there anyways. */
  505. break;
  506. }
  507. }
  508. }
  509. /* Advance to next block. */
  510. blockstart = blockend;
  511. }
  512. free(hashes);
  513. free(indices);
  514. }
  515. static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[],
  516. const SMikkTSpaceContext *pContext,
  517. const int iNrTrianglesIn)
  518. {
  519. int iNumUniqueVerts = 0, t = 0, i = 0;
  520. for (t = 0; t < iNrTrianglesIn; t++) {
  521. for (i = 0; i < 3; i++) {
  522. const int offs = t * 3 + i;
  523. const int index = piTriList_in_and_out[offs];
  524. const SVec3 vP = GetPosition(pContext, index);
  525. const SVec3 vN = GetNormal(pContext, index);
  526. const SVec3 vT = GetTexCoord(pContext, index);
  527. tbool bFound = TFALSE;
  528. int t2 = 0, index2rec = -1;
  529. while (!bFound && t2 <= t) {
  530. int j = 0;
  531. while (!bFound && j < 3) {
  532. const int index2 = piTriList_in_and_out[t2 * 3 + j];
  533. const SVec3 vP2 = GetPosition(pContext, index2);
  534. const SVec3 vN2 = GetNormal(pContext, index2);
  535. const SVec3 vT2 = GetTexCoord(pContext, index2);
  536. if (veq(vP, vP2) && veq(vN, vN2) && veq(vT, vT2))
  537. bFound = TTRUE;
  538. else
  539. ++j;
  540. }
  541. if (!bFound)
  542. ++t2;
  543. }
  544. assert(bFound);
  545. // if we found our own
  546. if (index2rec == index) {
  547. ++iNumUniqueVerts;
  548. }
  549. piTriList_in_and_out[offs] = index2rec;
  550. }
  551. }
  552. }
  553. static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[],
  554. int piTriList_out[],
  555. const SMikkTSpaceContext *pContext,
  556. const int iNrTrianglesIn)
  557. {
  558. int iTSpacesOffs = 0, f = 0, t = 0;
  559. int iDstTriIndex = 0;
  560. for (f = 0; f < pContext->m_pInterface->m_getNumFaces(pContext); f++) {
  561. const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f);
  562. if (verts != 3 && verts != 4)
  563. continue;
  564. pTriInfos[iDstTriIndex].iOrgFaceNumber = f;
  565. pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs;
  566. if (verts == 3) {
  567. unsigned char *pVerts = pTriInfos[iDstTriIndex].vert_num;
  568. pVerts[0] = 0;
  569. pVerts[1] = 1;
  570. pVerts[2] = 2;
  571. piTriList_out[iDstTriIndex * 3 + 0] = MakeIndex(f, 0);
  572. piTriList_out[iDstTriIndex * 3 + 1] = MakeIndex(f, 1);
  573. piTriList_out[iDstTriIndex * 3 + 2] = MakeIndex(f, 2);
  574. ++iDstTriIndex; // next
  575. }
  576. else {
  577. {
  578. pTriInfos[iDstTriIndex + 1].iOrgFaceNumber = f;
  579. pTriInfos[iDstTriIndex + 1].iTSpacesOffs = iTSpacesOffs;
  580. }
  581. {
  582. // need an order independent way to evaluate
  583. // tspace on quads. This is done by splitting
  584. // along the shortest diagonal.
  585. const int i0 = MakeIndex(f, 0);
  586. const int i1 = MakeIndex(f, 1);
  587. const int i2 = MakeIndex(f, 2);
  588. const int i3 = MakeIndex(f, 3);
  589. const SVec3 T0 = GetTexCoord(pContext, i0);
  590. const SVec3 T1 = GetTexCoord(pContext, i1);
  591. const SVec3 T2 = GetTexCoord(pContext, i2);
  592. const SVec3 T3 = GetTexCoord(pContext, i3);
  593. const float distSQ_02 = LengthSquared(vsub(T2, T0));
  594. const float distSQ_13 = LengthSquared(vsub(T3, T1));
  595. tbool bQuadDiagIs_02;
  596. if (distSQ_02 < distSQ_13)
  597. bQuadDiagIs_02 = TTRUE;
  598. else if (distSQ_13 < distSQ_02)
  599. bQuadDiagIs_02 = TFALSE;
  600. else {
  601. const SVec3 P0 = GetPosition(pContext, i0);
  602. const SVec3 P1 = GetPosition(pContext, i1);
  603. const SVec3 P2 = GetPosition(pContext, i2);
  604. const SVec3 P3 = GetPosition(pContext, i3);
  605. const float distSQ_02 = LengthSquared(vsub(P2, P0));
  606. const float distSQ_13 = LengthSquared(vsub(P3, P1));
  607. bQuadDiagIs_02 = distSQ_13 < distSQ_02 ? TFALSE : TTRUE;
  608. }
  609. if (bQuadDiagIs_02) {
  610. {
  611. unsigned char *pVerts_A = pTriInfos[iDstTriIndex].vert_num;
  612. pVerts_A[0] = 0;
  613. pVerts_A[1] = 1;
  614. pVerts_A[2] = 2;
  615. }
  616. piTriList_out[iDstTriIndex * 3 + 0] = i0;
  617. piTriList_out[iDstTriIndex * 3 + 1] = i1;
  618. piTriList_out[iDstTriIndex * 3 + 2] = i2;
  619. ++iDstTriIndex; // next
  620. {
  621. unsigned char *pVerts_B = pTriInfos[iDstTriIndex].vert_num;
  622. pVerts_B[0] = 0;
  623. pVerts_B[1] = 2;
  624. pVerts_B[2] = 3;
  625. }
  626. piTriList_out[iDstTriIndex * 3 + 0] = i0;
  627. piTriList_out[iDstTriIndex * 3 + 1] = i2;
  628. piTriList_out[iDstTriIndex * 3 + 2] = i3;
  629. ++iDstTriIndex; // next
  630. }
  631. else {
  632. {
  633. unsigned char *pVerts_A = pTriInfos[iDstTriIndex].vert_num;
  634. pVerts_A[0] = 0;
  635. pVerts_A[1] = 1;
  636. pVerts_A[2] = 3;
  637. }
  638. piTriList_out[iDstTriIndex * 3 + 0] = i0;
  639. piTriList_out[iDstTriIndex * 3 + 1] = i1;
  640. piTriList_out[iDstTriIndex * 3 + 2] = i3;
  641. ++iDstTriIndex; // next
  642. {
  643. unsigned char *pVerts_B = pTriInfos[iDstTriIndex].vert_num;
  644. pVerts_B[0] = 1;
  645. pVerts_B[1] = 2;
  646. pVerts_B[2] = 3;
  647. }
  648. piTriList_out[iDstTriIndex * 3 + 0] = i1;
  649. piTriList_out[iDstTriIndex * 3 + 1] = i2;
  650. piTriList_out[iDstTriIndex * 3 + 2] = i3;
  651. ++iDstTriIndex; // next
  652. }
  653. }
  654. }
  655. iTSpacesOffs += verts;
  656. assert(iDstTriIndex <= iNrTrianglesIn);
  657. }
  658. for (t = 0; t < iNrTrianglesIn; t++)
  659. pTriInfos[t].iFlag = 0;
  660. // return total amount of tspaces
  661. return iTSpacesOffs;
  662. }
  663. MIKK_INLINE SVec3 GetPosition(const SMikkTSpaceContext *pContext, const int index)
  664. {
  665. int iF, iI;
  666. SVec3 res;
  667. float pos[3];
  668. IndexToData(&iF, &iI, index);
  669. pContext->m_pInterface->m_getPosition(pContext, pos, iF, iI);
  670. res.x = pos[0];
  671. res.y = pos[1];
  672. res.z = pos[2];
  673. return res;
  674. }
  675. MIKK_INLINE SVec3 GetNormal(const SMikkTSpaceContext *pContext, const int index)
  676. {
  677. int iF, iI;
  678. SVec3 res;
  679. float norm[3];
  680. IndexToData(&iF, &iI, index);
  681. pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI);
  682. res.x = norm[0];
  683. res.y = norm[1];
  684. res.z = norm[2];
  685. return res;
  686. }
  687. MIKK_INLINE SVec3 GetTexCoord(const SMikkTSpaceContext *pContext, const int index)
  688. {
  689. int iF, iI;
  690. SVec3 res;
  691. float texc[2];
  692. IndexToData(&iF, &iI, index);
  693. pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI);
  694. res.x = texc[0];
  695. res.y = texc[1];
  696. res.z = 1.0f;
  697. return res;
  698. }
  699. ///////////////////////////////////////////////////////////////////////////////////////////////////
  700. ///////////////////////////////////////////////////////////////////////////////////////////////////
  701. typedef union {
  702. struct {
  703. int i0, i1, f;
  704. };
  705. int array[3];
  706. } SEdge;
  707. static void BuildNeighborsFast(STriInfo pTriInfos[],
  708. SEdge *pEdges,
  709. const int piTriListIn[],
  710. const int iNrTrianglesIn);
  711. static void BuildNeighborsSlow(STriInfo pTriInfos[],
  712. const int piTriListIn[],
  713. const int iNrTrianglesIn);
  714. // returns the texture area times 2
  715. static float CalcTexArea(const SMikkTSpaceContext *pContext, const int indices[])
  716. {
  717. const SVec3 t1 = GetTexCoord(pContext, indices[0]);
  718. const SVec3 t2 = GetTexCoord(pContext, indices[1]);
  719. const SVec3 t3 = GetTexCoord(pContext, indices[2]);
  720. const float t21x = t2.x - t1.x;
  721. const float t21y = t2.y - t1.y;
  722. const float t31x = t3.x - t1.x;
  723. const float t31y = t3.y - t1.y;
  724. const float fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
  725. return fSignedAreaSTx2 < 0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2;
  726. }
  727. static void InitTriInfo(STriInfo pTriInfos[],
  728. const int piTriListIn[],
  729. const SMikkTSpaceContext *pContext,
  730. const int iNrTrianglesIn)
  731. {
  732. int f = 0, i = 0, t = 0;
  733. // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList()
  734. // which is called before this function.
  735. // generate neighbor info list
  736. for (f = 0; f < iNrTrianglesIn; f++)
  737. for (i = 0; i < 3; i++) {
  738. pTriInfos[f].FaceNeighbors[i] = -1;
  739. pTriInfos[f].AssignedGroup[i] = NULL;
  740. pTriInfos[f].vOs.x = 0.0f;
  741. pTriInfos[f].vOs.y = 0.0f;
  742. pTriInfos[f].vOs.z = 0.0f;
  743. pTriInfos[f].vOt.x = 0.0f;
  744. pTriInfos[f].vOt.y = 0.0f;
  745. pTriInfos[f].vOt.z = 0.0f;
  746. pTriInfos[f].fMagS = 0;
  747. pTriInfos[f].fMagT = 0;
  748. // assumed bad
  749. pTriInfos[f].iFlag |= GROUP_WITH_ANY;
  750. }
  751. // evaluate first order derivatives
  752. for (f = 0; f < iNrTrianglesIn; f++) {
  753. // initial values
  754. const SVec3 v1 = GetPosition(pContext, piTriListIn[f * 3 + 0]);
  755. const SVec3 v2 = GetPosition(pContext, piTriListIn[f * 3 + 1]);
  756. const SVec3 v3 = GetPosition(pContext, piTriListIn[f * 3 + 2]);
  757. const SVec3 t1 = GetTexCoord(pContext, piTriListIn[f * 3 + 0]);
  758. const SVec3 t2 = GetTexCoord(pContext, piTriListIn[f * 3 + 1]);
  759. const SVec3 t3 = GetTexCoord(pContext, piTriListIn[f * 3 + 2]);
  760. const float t21x = t2.x - t1.x;
  761. const float t21y = t2.y - t1.y;
  762. const float t31x = t3.x - t1.x;
  763. const float t31y = t3.y - t1.y;
  764. const SVec3 d1 = vsub(v2, v1);
  765. const SVec3 d2 = vsub(v3, v1);
  766. const float fSignedAreaSTx2 = t21x * t31y - t21y * t31x;
  767. // assert(fSignedAreaSTx2!=0);
  768. SVec3 vOs = vsub(vscale(t31y, d1), vscale(t21y, d2)); // eq 18
  769. SVec3 vOt = vadd(vscale(-t31x, d1), vscale(t21x, d2)); // eq 19
  770. pTriInfos[f].iFlag |= (fSignedAreaSTx2 > 0 ? ORIENT_PRESERVING : 0);
  771. if (NotZero(fSignedAreaSTx2)) {
  772. const float fAbsArea = fabsf(fSignedAreaSTx2);
  773. const float fLenOs = Length(vOs);
  774. const float fLenOt = Length(vOt);
  775. const float fS = (pTriInfos[f].iFlag & ORIENT_PRESERVING) == 0 ? (-1.0f) : 1.0f;
  776. if (NotZero(fLenOs))
  777. pTriInfos[f].vOs = vscale(fS / fLenOs, vOs);
  778. if (NotZero(fLenOt))
  779. pTriInfos[f].vOt = vscale(fS / fLenOt, vOt);
  780. // evaluate magnitudes prior to normalization of vOs and vOt
  781. pTriInfos[f].fMagS = fLenOs / fAbsArea;
  782. pTriInfos[f].fMagT = fLenOt / fAbsArea;
  783. // if this is a good triangle
  784. if (NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT))
  785. pTriInfos[f].iFlag &= (~GROUP_WITH_ANY);
  786. }
  787. }
  788. // force otherwise healthy quads to a fixed orientation
  789. while (t < (iNrTrianglesIn - 1)) {
  790. const int iFO_a = pTriInfos[t].iOrgFaceNumber;
  791. const int iFO_b = pTriInfos[t + 1].iOrgFaceNumber;
  792. if (iFO_a == iFO_b) // this is a quad
  793. {
  794. const tbool bIsDeg_a = (pTriInfos[t].iFlag & MARK_DEGENERATE) != 0 ? TTRUE : TFALSE;
  795. const tbool bIsDeg_b = (pTriInfos[t + 1].iFlag & MARK_DEGENERATE) != 0 ? TTRUE : TFALSE;
  796. // bad triangles should already have been removed by
  797. // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false
  798. if ((bIsDeg_a || bIsDeg_b) == TFALSE) {
  799. const tbool bOrientA = (pTriInfos[t].iFlag & ORIENT_PRESERVING) != 0 ? TTRUE : TFALSE;
  800. const tbool bOrientB = (pTriInfos[t + 1].iFlag & ORIENT_PRESERVING) != 0 ? TTRUE : TFALSE;
  801. // if this happens the quad has extremely bad mapping!!
  802. if (bOrientA != bOrientB) {
  803. // printf("found quad with bad mapping\n");
  804. tbool bChooseOrientFirstTri = TFALSE;
  805. if ((pTriInfos[t + 1].iFlag & GROUP_WITH_ANY) != 0)
  806. bChooseOrientFirstTri = TTRUE;
  807. else if (CalcTexArea(pContext, &piTriListIn[t * 3 + 0]) >=
  808. CalcTexArea(pContext, &piTriListIn[(t + 1) * 3 + 0]))
  809. bChooseOrientFirstTri = TTRUE;
  810. // force match
  811. {
  812. const int t0 = bChooseOrientFirstTri ? t : (t + 1);
  813. const int t1 = bChooseOrientFirstTri ? (t + 1) : t;
  814. pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first
  815. pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag & ORIENT_PRESERVING); // copy bit
  816. }
  817. }
  818. }
  819. t += 2;
  820. }
  821. else
  822. ++t;
  823. }
  824. // match up edge pairs
  825. {
  826. SEdge *pEdges = (SEdge *)malloc(sizeof(SEdge[3]) * iNrTrianglesIn);
  827. if (pEdges == NULL)
  828. BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn);
  829. else {
  830. BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn);
  831. free(pEdges);
  832. }
  833. }
  834. }
  835. ///////////////////////////////////////////////////////////////////////////////////////////////////
  836. ///////////////////////////////////////////////////////////////////////////////////////////////////
  837. static tbool AssignRecur(const int piTriListIn[],
  838. STriInfo psTriInfos[],
  839. const int iMyTriIndex,
  840. SGroup *pGroup);
  841. MIKK_INLINE void AddTriToGroup(SGroup *pGroup, const int iTriIndex);
  842. static int Build4RuleGroups(STriInfo pTriInfos[],
  843. SGroup pGroups[],
  844. int piGroupTrianglesBuffer[],
  845. const int piTriListIn[],
  846. const int iNrTrianglesIn)
  847. {
  848. const int iNrMaxGroups = iNrTrianglesIn * 3;
  849. int iNrActiveGroups = 0;
  850. int iOffset = 0, f = 0, i = 0;
  851. (void)iNrMaxGroups; /* quiet warnings in non debug mode */
  852. for (f = 0; f < iNrTrianglesIn; f++) {
  853. for (i = 0; i < 3; i++) {
  854. // if not assigned to a group
  855. if ((pTriInfos[f].iFlag & GROUP_WITH_ANY) == 0 && pTriInfos[f].AssignedGroup[i] == NULL) {
  856. tbool bOrPre;
  857. int neigh_indexL, neigh_indexR;
  858. const int vert_index = piTriListIn[f * 3 + i];
  859. assert(iNrActiveGroups < iNrMaxGroups);
  860. pTriInfos[f].AssignedGroup[i] = &pGroups[iNrActiveGroups];
  861. pTriInfos[f].AssignedGroup[i]->iVertexRepresentitive = vert_index;
  862. pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag &
  863. ORIENT_PRESERVING) != 0;
  864. pTriInfos[f].AssignedGroup[i]->iNrFaces = 0;
  865. pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset];
  866. ++iNrActiveGroups;
  867. AddTriToGroup(pTriInfos[f].AssignedGroup[i], f);
  868. bOrPre = (pTriInfos[f].iFlag & ORIENT_PRESERVING) != 0 ? TTRUE : TFALSE;
  869. neigh_indexL = pTriInfos[f].FaceNeighbors[i];
  870. neigh_indexR = pTriInfos[f].FaceNeighbors[i > 0 ? (i - 1) : 2];
  871. if (neigh_indexL >= 0) // neighbor
  872. {
  873. const tbool bAnswer = AssignRecur(
  874. piTriListIn, pTriInfos, neigh_indexL, pTriInfos[f].AssignedGroup[i]);
  875. const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag & ORIENT_PRESERVING) != 0 ? TTRUE :
  876. TFALSE;
  877. const tbool bDiff = bOrPre != bOrPre2 ? TTRUE : TFALSE;
  878. assert(bAnswer || bDiff);
  879. (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */
  880. }
  881. if (neigh_indexR >= 0) // neighbor
  882. {
  883. const tbool bAnswer = AssignRecur(
  884. piTriListIn, pTriInfos, neigh_indexR, pTriInfos[f].AssignedGroup[i]);
  885. const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag & ORIENT_PRESERVING) != 0 ? TTRUE :
  886. TFALSE;
  887. const tbool bDiff = bOrPre != bOrPre2 ? TTRUE : TFALSE;
  888. assert(bAnswer || bDiff);
  889. (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */
  890. }
  891. // update offset
  892. iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces;
  893. // since the groups are disjoint a triangle can never
  894. // belong to more than 3 groups. Subsequently something
  895. // is completely screwed if this assertion ever hits.
  896. assert(iOffset <= iNrMaxGroups);
  897. }
  898. }
  899. }
  900. return iNrActiveGroups;
  901. }
  902. MIKK_INLINE void AddTriToGroup(SGroup *pGroup, const int iTriIndex)
  903. {
  904. pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex;
  905. ++pGroup->iNrFaces;
  906. }
  907. static tbool AssignRecur(const int piTriListIn[],
  908. STriInfo psTriInfos[],
  909. const int iMyTriIndex,
  910. SGroup *pGroup)
  911. {
  912. STriInfo *pMyTriInfo = &psTriInfos[iMyTriIndex];
  913. // track down vertex
  914. const int iVertRep = pGroup->iVertexRepresentitive;
  915. const int *pVerts = &piTriListIn[3 * iMyTriIndex + 0];
  916. int i = -1;
  917. if (pVerts[0] == iVertRep)
  918. i = 0;
  919. else if (pVerts[1] == iVertRep)
  920. i = 1;
  921. else if (pVerts[2] == iVertRep)
  922. i = 2;
  923. assert(i >= 0 && i < 3);
  924. // early out
  925. if (pMyTriInfo->AssignedGroup[i] == pGroup)
  926. return TTRUE;
  927. else if (pMyTriInfo->AssignedGroup[i] != NULL)
  928. return TFALSE;
  929. if ((pMyTriInfo->iFlag & GROUP_WITH_ANY) != 0) {
  930. // first to group with a group-with-anything triangle
  931. // determines it's orientation.
  932. // This is the only existing order dependency in the code!!
  933. if (pMyTriInfo->AssignedGroup[0] == NULL && pMyTriInfo->AssignedGroup[1] == NULL &&
  934. pMyTriInfo->AssignedGroup[2] == NULL) {
  935. pMyTriInfo->iFlag &= (~ORIENT_PRESERVING);
  936. pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0);
  937. }
  938. }
  939. {
  940. const tbool bOrient = (pMyTriInfo->iFlag & ORIENT_PRESERVING) != 0 ? TTRUE : TFALSE;
  941. if (bOrient != pGroup->bOrientPreservering)
  942. return TFALSE;
  943. }
  944. AddTriToGroup(pGroup, iMyTriIndex);
  945. pMyTriInfo->AssignedGroup[i] = pGroup;
  946. {
  947. const int neigh_indexL = pMyTriInfo->FaceNeighbors[i];
  948. const int neigh_indexR = pMyTriInfo->FaceNeighbors[i > 0 ? (i - 1) : 2];
  949. if (neigh_indexL >= 0)
  950. AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup);
  951. if (neigh_indexR >= 0)
  952. AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup);
  953. }
  954. return TTRUE;
  955. }
  956. ///////////////////////////////////////////////////////////////////////////////////////////////////
  957. ///////////////////////////////////////////////////////////////////////////////////////////////////
  958. static tbool CompareSubGroups(const SSubGroup *pg1, const SSubGroup *pg2);
  959. static void QuickSort(int *pSortBuffer, int iLeft, int iRight, unsigned int uSeed);
  960. static STSpace EvalTspace(int face_indices[],
  961. const int iFaces,
  962. const int piTriListIn[],
  963. const STriInfo pTriInfos[],
  964. const SMikkTSpaceContext *pContext,
  965. const int iVertexRepresentitive);
  966. static tbool GenerateTSpaces(STSpace psTspace[],
  967. const STriInfo pTriInfos[],
  968. const SGroup pGroups[],
  969. const int iNrActiveGroups,
  970. const int piTriListIn[],
  971. const float fThresCos,
  972. const SMikkTSpaceContext *pContext)
  973. {
  974. STSpace *pSubGroupTspace = NULL;
  975. SSubGroup *pUniSubGroups = NULL;
  976. int *pTmpMembers = NULL;
  977. int iMaxNrFaces = 0, iUniqueTspaces = 0, g = 0, i = 0;
  978. for (g = 0; g < iNrActiveGroups; g++)
  979. if (iMaxNrFaces < pGroups[g].iNrFaces)
  980. iMaxNrFaces = pGroups[g].iNrFaces;
  981. if (iMaxNrFaces == 0)
  982. return TTRUE;
  983. // make initial allocations
  984. pSubGroupTspace = (STSpace *)malloc(sizeof(STSpace) * iMaxNrFaces);
  985. pUniSubGroups = (SSubGroup *)malloc(sizeof(SSubGroup) * iMaxNrFaces);
  986. pTmpMembers = (int *)malloc(sizeof(int) * iMaxNrFaces);
  987. if (pSubGroupTspace == NULL || pUniSubGroups == NULL || pTmpMembers == NULL) {
  988. if (pSubGroupTspace != NULL)
  989. free(pSubGroupTspace);
  990. if (pUniSubGroups != NULL)
  991. free(pUniSubGroups);
  992. if (pTmpMembers != NULL)
  993. free(pTmpMembers);
  994. return TFALSE;
  995. }
  996. iUniqueTspaces = 0;
  997. for (g = 0; g < iNrActiveGroups; g++) {
  998. const SGroup *pGroup = &pGroups[g];
  999. int iUniqueSubGroups = 0, s = 0;
  1000. for (i = 0; i < pGroup->iNrFaces; i++) // triangles
  1001. {
  1002. const int f = pGroup->pFaceIndices[i]; // triangle number
  1003. int index = -1, iVertIndex = -1, iOF_1 = -1, iMembers = 0, j = 0, l = 0;
  1004. SSubGroup tmp_group;
  1005. tbool bFound;
  1006. SVec3 n, vOs, vOt;
  1007. if (pTriInfos[f].AssignedGroup[0] == pGroup)
  1008. index = 0;
  1009. else if (pTriInfos[f].AssignedGroup[1] == pGroup)
  1010. index = 1;
  1011. else if (pTriInfos[f].AssignedGroup[2] == pGroup)
  1012. index = 2;
  1013. assert(index >= 0 && index < 3);
  1014. iVertIndex = piTriListIn[f * 3 + index];
  1015. assert(iVertIndex == pGroup->iVertexRepresentitive);
  1016. // is normalized already
  1017. n = GetNormal(pContext, iVertIndex);
  1018. // project
  1019. vOs = NormalizeSafe(vsub(pTriInfos[f].vOs, vscale(vdot(n, pTriInfos[f].vOs), n)));
  1020. vOt = NormalizeSafe(vsub(pTriInfos[f].vOt, vscale(vdot(n, pTriInfos[f].vOt), n)));
  1021. // original face number
  1022. iOF_1 = pTriInfos[f].iOrgFaceNumber;
  1023. iMembers = 0;
  1024. for (j = 0; j < pGroup->iNrFaces; j++) {
  1025. const int t = pGroup->pFaceIndices[j]; // triangle number
  1026. const int iOF_2 = pTriInfos[t].iOrgFaceNumber;
  1027. // project
  1028. SVec3 vOs2 = NormalizeSafe(vsub(pTriInfos[t].vOs, vscale(vdot(n, pTriInfos[t].vOs), n)));
  1029. SVec3 vOt2 = NormalizeSafe(vsub(pTriInfos[t].vOt, vscale(vdot(n, pTriInfos[t].vOt), n)));
  1030. {
  1031. const tbool bAny = ((pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY) != 0 ?
  1032. TTRUE :
  1033. TFALSE;
  1034. // make sure triangles which belong to the same quad are joined.
  1035. const tbool bSameOrgFace = iOF_1 == iOF_2 ? TTRUE : TFALSE;
  1036. const float fCosS = vdot(vOs, vOs2);
  1037. const float fCosT = vdot(vOt, vOt2);
  1038. assert(f != t || bSameOrgFace); // sanity check
  1039. if (bAny || bSameOrgFace || (fCosS > fThresCos && fCosT > fThresCos))
  1040. pTmpMembers[iMembers++] = t;
  1041. }
  1042. }
  1043. // sort pTmpMembers
  1044. tmp_group.iNrFaces = iMembers;
  1045. tmp_group.pTriMembers = pTmpMembers;
  1046. if (iMembers > 1) {
  1047. unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
  1048. QuickSort(pTmpMembers, 0, iMembers - 1, uSeed);
  1049. }
  1050. // look for an existing match
  1051. bFound = TFALSE;
  1052. l = 0;
  1053. while (l < iUniqueSubGroups && !bFound) {
  1054. bFound = CompareSubGroups(&tmp_group, &pUniSubGroups[l]);
  1055. if (!bFound)
  1056. ++l;
  1057. }
  1058. // assign tangent space index
  1059. assert(bFound || l == iUniqueSubGroups);
  1060. // piTempTangIndices[f*3+index] = iUniqueTspaces+l;
  1061. // if no match was found we allocate a new subgroup
  1062. if (!bFound) {
  1063. // insert new subgroup
  1064. int *pIndices = (int *)malloc(sizeof(int) * iMembers);
  1065. if (pIndices == NULL) {
  1066. // clean up and return false
  1067. int s = 0;
  1068. for (s = 0; s < iUniqueSubGroups; s++)
  1069. free(pUniSubGroups[s].pTriMembers);
  1070. free(pUniSubGroups);
  1071. free(pTmpMembers);
  1072. free(pSubGroupTspace);
  1073. return TFALSE;
  1074. }
  1075. pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers;
  1076. pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices;
  1077. memcpy(pIndices, tmp_group.pTriMembers, sizeof(int) * iMembers);
  1078. pSubGroupTspace[iUniqueSubGroups] = EvalTspace(tmp_group.pTriMembers,
  1079. iMembers,
  1080. piTriListIn,
  1081. pTriInfos,
  1082. pContext,
  1083. pGroup->iVertexRepresentitive);
  1084. ++iUniqueSubGroups;
  1085. }
  1086. // output tspace
  1087. {
  1088. const int iOffs = pTriInfos[f].iTSpacesOffs;
  1089. const int iVert = pTriInfos[f].vert_num[index];
  1090. STSpace *pTS_out = &psTspace[iOffs + iVert];
  1091. assert(pTS_out->iCounter < 2);
  1092. assert(((pTriInfos[f].iFlag & ORIENT_PRESERVING) != 0) == pGroup->bOrientPreservering);
  1093. if (pTS_out->iCounter == 1) {
  1094. *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]);
  1095. pTS_out->iCounter = 2; // update counter
  1096. pTS_out->bOrient = pGroup->bOrientPreservering;
  1097. }
  1098. else {
  1099. assert(pTS_out->iCounter == 0);
  1100. *pTS_out = pSubGroupTspace[l];
  1101. pTS_out->iCounter = 1; // update counter
  1102. pTS_out->bOrient = pGroup->bOrientPreservering;
  1103. }
  1104. }
  1105. }
  1106. // clean up and offset iUniqueTspaces
  1107. for (s = 0; s < iUniqueSubGroups; s++)
  1108. free(pUniSubGroups[s].pTriMembers);
  1109. iUniqueTspaces += iUniqueSubGroups;
  1110. }
  1111. // clean up
  1112. free(pUniSubGroups);
  1113. free(pTmpMembers);
  1114. free(pSubGroupTspace);
  1115. return TTRUE;
  1116. }
  1117. static STSpace EvalTspace(int face_indices[],
  1118. const int iFaces,
  1119. const int piTriListIn[],
  1120. const STriInfo pTriInfos[],
  1121. const SMikkTSpaceContext *pContext,
  1122. const int iVertexRepresentitive)
  1123. {
  1124. STSpace res;
  1125. float fAngleSum = 0;
  1126. int face = 0;
  1127. res.vOs.x = 0.0f;
  1128. res.vOs.y = 0.0f;
  1129. res.vOs.z = 0.0f;
  1130. res.vOt.x = 0.0f;
  1131. res.vOt.y = 0.0f;
  1132. res.vOt.z = 0.0f;
  1133. res.fMagS = 0;
  1134. res.fMagT = 0;
  1135. for (face = 0; face < iFaces; face++) {
  1136. const int f = face_indices[face];
  1137. // only valid triangles get to add their contribution
  1138. if ((pTriInfos[f].iFlag & GROUP_WITH_ANY) == 0) {
  1139. SVec3 n, vOs, vOt, p0, p1, p2, v1, v2;
  1140. float fCos, fAngle, fMagS, fMagT;
  1141. int i = -1, index = -1, i0 = -1, i1 = -1, i2 = -1;
  1142. if (piTriListIn[3 * f + 0] == iVertexRepresentitive)
  1143. i = 0;
  1144. else if (piTriListIn[3 * f + 1] == iVertexRepresentitive)
  1145. i = 1;
  1146. else if (piTriListIn[3 * f + 2] == iVertexRepresentitive)
  1147. i = 2;
  1148. assert(i >= 0 && i < 3);
  1149. // project
  1150. index = piTriListIn[3 * f + i];
  1151. n = GetNormal(pContext, index);
  1152. vOs = NormalizeSafe(vsub(pTriInfos[f].vOs, vscale(vdot(n, pTriInfos[f].vOs), n)));
  1153. vOt = NormalizeSafe(vsub(pTriInfos[f].vOt, vscale(vdot(n, pTriInfos[f].vOt), n)));
  1154. i2 = piTriListIn[3 * f + (i < 2 ? (i + 1) : 0)];
  1155. i1 = piTriListIn[3 * f + i];
  1156. i0 = piTriListIn[3 * f + (i > 0 ? (i - 1) : 2)];
  1157. p0 = GetPosition(pContext, i0);
  1158. p1 = GetPosition(pContext, i1);
  1159. p2 = GetPosition(pContext, i2);
  1160. v1 = vsub(p0, p1);
  1161. v2 = vsub(p2, p1);
  1162. // project
  1163. v1 = NormalizeSafe(vsub(v1, vscale(vdot(n, v1), n)));
  1164. v2 = NormalizeSafe(vsub(v2, vscale(vdot(n, v2), n)));
  1165. // weight contribution by the angle
  1166. // between the two edge vectors
  1167. fCos = vdot(v1, v2);
  1168. fCos = fCos > 1 ? 1 : (fCos < (-1) ? (-1) : fCos);
  1169. fAngle = (float)acos(fCos);
  1170. fMagS = pTriInfos[f].fMagS;
  1171. fMagT = pTriInfos[f].fMagT;
  1172. res.vOs = vadd(res.vOs, vscale(fAngle, vOs));
  1173. res.vOt = vadd(res.vOt, vscale(fAngle, vOt));
  1174. res.fMagS += (fAngle * fMagS);
  1175. res.fMagT += (fAngle * fMagT);
  1176. fAngleSum += fAngle;
  1177. }
  1178. }
  1179. // normalize
  1180. res.vOs = NormalizeSafe(res.vOs);
  1181. res.vOt = NormalizeSafe(res.vOt);
  1182. if (fAngleSum > 0) {
  1183. res.fMagS /= fAngleSum;
  1184. res.fMagT /= fAngleSum;
  1185. }
  1186. return res;
  1187. }
  1188. static tbool CompareSubGroups(const SSubGroup *pg1, const SSubGroup *pg2)
  1189. {
  1190. tbool bStillSame = TTRUE;
  1191. int i = 0;
  1192. if (pg1->iNrFaces != pg2->iNrFaces)
  1193. return TFALSE;
  1194. while (i < pg1->iNrFaces && bStillSame) {
  1195. bStillSame = pg1->pTriMembers[i] == pg2->pTriMembers[i] ? TTRUE : TFALSE;
  1196. if (bStillSame)
  1197. ++i;
  1198. }
  1199. return bStillSame;
  1200. }
  1201. static void QuickSort(int *pSortBuffer, int iLeft, int iRight, unsigned int uSeed)
  1202. {
  1203. int iL, iR, n, index, iMid, iTmp;
  1204. // Random
  1205. unsigned int t = uSeed & 31;
  1206. t = (uSeed << t) | (uSeed >> (32 - t));
  1207. uSeed = uSeed + t + 3;
  1208. // Random end
  1209. iL = iLeft;
  1210. iR = iRight;
  1211. n = (iR - iL) + 1;
  1212. assert(n >= 0);
  1213. index = (int)(uSeed % (unsigned int)n);
  1214. iMid = pSortBuffer[index + iL];
  1215. do {
  1216. while (pSortBuffer[iL] < iMid)
  1217. ++iL;
  1218. while (pSortBuffer[iR] > iMid)
  1219. --iR;
  1220. if (iL <= iR) {
  1221. iTmp = pSortBuffer[iL];
  1222. pSortBuffer[iL] = pSortBuffer[iR];
  1223. pSortBuffer[iR] = iTmp;
  1224. ++iL;
  1225. --iR;
  1226. }
  1227. } while (iL <= iR);
  1228. if (iLeft < iR)
  1229. QuickSort(pSortBuffer, iLeft, iR, uSeed);
  1230. if (iL < iRight)
  1231. QuickSort(pSortBuffer, iL, iRight, uSeed);
  1232. }
  1233. /////////////////////////////////////////////////////////////////////////////////////////////
  1234. /////////////////////////////////////////////////////////////////////////////////////////////
  1235. static void QuickSortEdges(
  1236. SEdge *pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed);
  1237. static void GetEdge(int *i0_out,
  1238. int *i1_out,
  1239. int *edgenum_out,
  1240. const int indices[],
  1241. const int i0_in,
  1242. const int i1_in);
  1243. static void BuildNeighborsFast(STriInfo pTriInfos[],
  1244. SEdge *pEdges,
  1245. const int piTriListIn[],
  1246. const int iNrTrianglesIn)
  1247. {
  1248. // build array of edges
  1249. unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed?
  1250. int iEntries = 0, iCurStartIndex = -1, f = 0, i = 0;
  1251. for (f = 0; f < iNrTrianglesIn; f++)
  1252. for (i = 0; i < 3; i++) {
  1253. const int i0 = piTriListIn[f * 3 + i];
  1254. const int i1 = piTriListIn[f * 3 + (i < 2 ? (i + 1) : 0)];
  1255. pEdges[f * 3 + i].i0 = i0 < i1 ? i0 : i1; // put minimum index in i0
  1256. pEdges[f * 3 + i].i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1
  1257. pEdges[f * 3 + i].f = f; // record face number
  1258. }
  1259. // sort over all edges by i0, this is the pricy one.
  1260. QuickSortEdges(pEdges, 0, iNrTrianglesIn * 3 - 1, 0, uSeed); // sort channel 0 which is i0
  1261. // sub sort over i1, should be fast.
  1262. // could replace this with a 64 bit int sort over (i0,i1)
  1263. // with i0 as msb in the quicksort call above.
  1264. iEntries = iNrTrianglesIn * 3;
  1265. iCurStartIndex = 0;
  1266. for (i = 1; i < iEntries; i++) {
  1267. if (pEdges[iCurStartIndex].i0 != pEdges[i].i0) {
  1268. const int iL = iCurStartIndex;
  1269. const int iR = i - 1;
  1270. // const int iElems = i-iL;
  1271. iCurStartIndex = i;
  1272. QuickSortEdges(pEdges, iL, iR, 1, uSeed); // sort channel 1 which is i1
  1273. }
  1274. }
  1275. // sub sort over f, which should be fast.
  1276. // this step is to remain compliant with BuildNeighborsSlow() when
  1277. // more than 2 triangles use the same edge (such as a butterfly topology).
  1278. iCurStartIndex = 0;
  1279. for (i = 1; i < iEntries; i++) {
  1280. if (pEdges[iCurStartIndex].i0 != pEdges[i].i0 || pEdges[iCurStartIndex].i1 != pEdges[i].i1) {
  1281. const int iL = iCurStartIndex;
  1282. const int iR = i - 1;
  1283. // const int iElems = i-iL;
  1284. iCurStartIndex = i;
  1285. QuickSortEdges(pEdges, iL, iR, 2, uSeed); // sort channel 2 which is f
  1286. }
  1287. }
  1288. // pair up, adjacent triangles
  1289. for (i = 0; i < iEntries; i++) {
  1290. const int i0 = pEdges[i].i0;
  1291. const int i1 = pEdges[i].i1;
  1292. const int f = pEdges[i].f;
  1293. tbool bUnassigned_A;
  1294. int i0_A, i1_A;
  1295. int edgenum_A, edgenum_B = 0; // 0,1 or 2
  1296. GetEdge(&i0_A,
  1297. &i1_A,
  1298. &edgenum_A,
  1299. &piTriListIn[f * 3],
  1300. i0,
  1301. i1); // resolve index ordering and edge_num
  1302. bUnassigned_A = pTriInfos[f].FaceNeighbors[edgenum_A] == -1 ? TTRUE : TFALSE;
  1303. if (bUnassigned_A) {
  1304. // get true index ordering
  1305. int j = i + 1, t;
  1306. tbool bNotFound = TTRUE;
  1307. while (j < iEntries && i0 == pEdges[j].i0 && i1 == pEdges[j].i1 && bNotFound) {
  1308. tbool bUnassigned_B;
  1309. int i0_B, i1_B;
  1310. t = pEdges[j].f;
  1311. // flip i0_B and i1_B
  1312. GetEdge(&i1_B,
  1313. &i0_B,
  1314. &edgenum_B,
  1315. &piTriListIn[t * 3],
  1316. pEdges[j].i0,
  1317. pEdges[j].i1); // resolve index ordering and edge_num
  1318. // assert(!(i0_A==i1_B && i1_A==i0_B));
  1319. bUnassigned_B = pTriInfos[t].FaceNeighbors[edgenum_B] == -1 ? TTRUE : TFALSE;
  1320. if (i0_A == i0_B && i1_A == i1_B && bUnassigned_B)
  1321. bNotFound = TFALSE;
  1322. else
  1323. ++j;
  1324. }
  1325. if (!bNotFound) {
  1326. int t = pEdges[j].f;
  1327. pTriInfos[f].FaceNeighbors[edgenum_A] = t;
  1328. // assert(pTriInfos[t].FaceNeighbors[edgenum_B]==-1);
  1329. pTriInfos[t].FaceNeighbors[edgenum_B] = f;
  1330. }
  1331. }
  1332. }
  1333. }
  1334. static void BuildNeighborsSlow(STriInfo pTriInfos[],
  1335. const int piTriListIn[],
  1336. const int iNrTrianglesIn)
  1337. {
  1338. int f = 0, i = 0;
  1339. for (f = 0; f < iNrTrianglesIn; f++) {
  1340. for (i = 0; i < 3; i++) {
  1341. // if unassigned
  1342. if (pTriInfos[f].FaceNeighbors[i] == -1) {
  1343. const int i0_A = piTriListIn[f * 3 + i];
  1344. const int i1_A = piTriListIn[f * 3 + (i < 2 ? (i + 1) : 0)];
  1345. // search for a neighbor
  1346. tbool bFound = TFALSE;
  1347. int t = 0, j = 0;
  1348. while (!bFound && t < iNrTrianglesIn) {
  1349. if (t != f) {
  1350. j = 0;
  1351. while (!bFound && j < 3) {
  1352. // in rev order
  1353. const int i1_B = piTriListIn[t * 3 + j];
  1354. const int i0_B = piTriListIn[t * 3 + (j < 2 ? (j + 1) : 0)];
  1355. // assert(!(i0_A==i1_B && i1_A==i0_B));
  1356. if (i0_A == i0_B && i1_A == i1_B)
  1357. bFound = TTRUE;
  1358. else
  1359. ++j;
  1360. }
  1361. }
  1362. if (!bFound)
  1363. ++t;
  1364. }
  1365. // assign neighbors
  1366. if (bFound) {
  1367. pTriInfos[f].FaceNeighbors[i] = t;
  1368. // assert(pTriInfos[t].FaceNeighbors[j]==-1);
  1369. pTriInfos[t].FaceNeighbors[j] = f;
  1370. }
  1371. }
  1372. }
  1373. }
  1374. }
  1375. static void QuickSortEdges(
  1376. SEdge *pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed)
  1377. {
  1378. unsigned int t;
  1379. int iL, iR, n, index, iMid;
  1380. // early out
  1381. SEdge sTmp;
  1382. const int iElems = iRight - iLeft + 1;
  1383. if (iElems < 2)
  1384. return;
  1385. else if (iElems == 2) {
  1386. if (pSortBuffer[iLeft].array[channel] > pSortBuffer[iRight].array[channel]) {
  1387. sTmp = pSortBuffer[iLeft];
  1388. pSortBuffer[iLeft] = pSortBuffer[iRight];
  1389. pSortBuffer[iRight] = sTmp;
  1390. }
  1391. return;
  1392. }
  1393. else if (iElems < 16) {
  1394. int i, j;
  1395. for (i = 0; i < iElems - 1; i++) {
  1396. for (j = 0; j < iElems - i - 1; j++) {
  1397. int index = iLeft + j;
  1398. if (pSortBuffer[index].array[channel] > pSortBuffer[index + 1].array[channel]) {
  1399. sTmp = pSortBuffer[index];
  1400. pSortBuffer[index] = pSortBuffer[index + 1];
  1401. pSortBuffer[index + 1] = sTmp;
  1402. }
  1403. }
  1404. }
  1405. return;
  1406. }
  1407. // Random
  1408. t = uSeed & 31;
  1409. t = (uSeed << t) | (uSeed >> (32 - t));
  1410. uSeed = uSeed + t + 3;
  1411. // Random end
  1412. iL = iLeft;
  1413. iR = iRight;
  1414. n = (iR - iL) + 1;
  1415. assert(n >= 0);
  1416. index = (int)(uSeed % (unsigned int)n);
  1417. iMid = pSortBuffer[index + iL].array[channel];
  1418. do {
  1419. while (pSortBuffer[iL].array[channel] < iMid)
  1420. ++iL;
  1421. while (pSortBuffer[iR].array[channel] > iMid)
  1422. --iR;
  1423. if (iL <= iR) {
  1424. sTmp = pSortBuffer[iL];
  1425. pSortBuffer[iL] = pSortBuffer[iR];
  1426. pSortBuffer[iR] = sTmp;
  1427. ++iL;
  1428. --iR;
  1429. }
  1430. } while (iL <= iR);
  1431. if (iLeft < iR)
  1432. QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed);
  1433. if (iL < iRight)
  1434. QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed);
  1435. }
  1436. // resolve ordering and edge number
  1437. static void GetEdge(int *i0_out,
  1438. int *i1_out,
  1439. int *edgenum_out,
  1440. const int indices[],
  1441. const int i0_in,
  1442. const int i1_in)
  1443. {
  1444. *edgenum_out = -1;
  1445. // test if first index is on the edge
  1446. if (indices[0] == i0_in || indices[0] == i1_in) {
  1447. // test if second index is on the edge
  1448. if (indices[1] == i0_in || indices[1] == i1_in) {
  1449. edgenum_out[0] = 0; // first edge
  1450. i0_out[0] = indices[0];
  1451. i1_out[0] = indices[1];
  1452. }
  1453. else {
  1454. edgenum_out[0] = 2; // third edge
  1455. i0_out[0] = indices[2];
  1456. i1_out[0] = indices[0];
  1457. }
  1458. }
  1459. else {
  1460. // only second and third index is on the edge
  1461. edgenum_out[0] = 1; // second edge
  1462. i0_out[0] = indices[1];
  1463. i1_out[0] = indices[2];
  1464. }
  1465. }
  1466. /////////////////////////////////////////////////////////////////////////////////////////////
  1467. /////////////////////////////////// Degenerate triangles ////////////////////////////////////
  1468. static void DegenPrologue(STriInfo pTriInfos[],
  1469. int piTriList_out[],
  1470. const int iNrTrianglesIn,
  1471. const int iTotTris)
  1472. {
  1473. int iNextGoodTriangleSearchIndex = -1;
  1474. tbool bStillFindingGoodOnes;
  1475. // locate quads with only one good triangle
  1476. int t = 0;
  1477. while (t < (iTotTris - 1)) {
  1478. const int iFO_a = pTriInfos[t].iOrgFaceNumber;
  1479. const int iFO_b = pTriInfos[t + 1].iOrgFaceNumber;
  1480. if (iFO_a == iFO_b) // this is a quad
  1481. {
  1482. const tbool bIsDeg_a = (pTriInfos[t].iFlag & MARK_DEGENERATE) != 0 ? TTRUE : TFALSE;
  1483. const tbool bIsDeg_b = (pTriInfos[t + 1].iFlag & MARK_DEGENERATE) != 0 ? TTRUE : TFALSE;
  1484. if ((bIsDeg_a ^ bIsDeg_b) != 0) {
  1485. pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI;
  1486. pTriInfos[t + 1].iFlag |= QUAD_ONE_DEGEN_TRI;
  1487. }
  1488. t += 2;
  1489. }
  1490. else
  1491. ++t;
  1492. }
  1493. // reorder list so all degen triangles are moved to the back
  1494. // without reordering the good triangles
  1495. iNextGoodTriangleSearchIndex = 1;
  1496. t = 0;
  1497. bStillFindingGoodOnes = TTRUE;
  1498. while (t < iNrTrianglesIn && bStillFindingGoodOnes) {
  1499. const tbool bIsGood = (pTriInfos[t].iFlag & MARK_DEGENERATE) == 0 ? TTRUE : TFALSE;
  1500. if (bIsGood) {
  1501. if (iNextGoodTriangleSearchIndex < (t + 2))
  1502. iNextGoodTriangleSearchIndex = t + 2;
  1503. }
  1504. else {
  1505. int t0, t1;
  1506. // search for the first good triangle.
  1507. tbool bJustADegenerate = TTRUE;
  1508. while (bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris) {
  1509. const tbool bIsGood = (pTriInfos[iNextGoodTriangleSearchIndex].iFlag & MARK_DEGENERATE) ==
  1510. 0 ?
  1511. TTRUE :
  1512. TFALSE;
  1513. if (bIsGood)
  1514. bJustADegenerate = TFALSE;
  1515. else
  1516. ++iNextGoodTriangleSearchIndex;
  1517. }
  1518. t0 = t;
  1519. t1 = iNextGoodTriangleSearchIndex;
  1520. ++iNextGoodTriangleSearchIndex;
  1521. assert(iNextGoodTriangleSearchIndex > (t + 1));
  1522. // swap triangle t0 and t1
  1523. if (!bJustADegenerate) {
  1524. int i = 0;
  1525. for (i = 0; i < 3; i++) {
  1526. const int index = piTriList_out[t0 * 3 + i];
  1527. piTriList_out[t0 * 3 + i] = piTriList_out[t1 * 3 + i];
  1528. piTriList_out[t1 * 3 + i] = index;
  1529. }
  1530. {
  1531. const STriInfo tri_info = pTriInfos[t0];
  1532. pTriInfos[t0] = pTriInfos[t1];
  1533. pTriInfos[t1] = tri_info;
  1534. }
  1535. }
  1536. else
  1537. bStillFindingGoodOnes = TFALSE; // this is not supposed to happen
  1538. }
  1539. if (bStillFindingGoodOnes)
  1540. ++t;
  1541. }
  1542. assert(bStillFindingGoodOnes); // code will still work.
  1543. assert(iNrTrianglesIn == t);
  1544. }
  1545. typedef struct VertReverseLookupContext {
  1546. tbool bIsInitialized;
  1547. int *pLookup;
  1548. int iMaxVertIndex;
  1549. } VertReverseLookupContext;
  1550. static void GenerateReverseLookup(const int piTriListIn[],
  1551. const int iNrTrianglesIn,
  1552. VertReverseLookupContext *pLookupCtx)
  1553. {
  1554. int t;
  1555. // Figure out what size of lookup array we need.
  1556. pLookupCtx->iMaxVertIndex = -1;
  1557. for (t = 0; t < 3 * iNrTrianglesIn; t++) {
  1558. int iVertIndex = piTriListIn[t];
  1559. if (iVertIndex > pLookupCtx->iMaxVertIndex) {
  1560. pLookupCtx->iMaxVertIndex = iVertIndex;
  1561. }
  1562. }
  1563. // Allocate memory.
  1564. if (pLookupCtx->iMaxVertIndex < 1) {
  1565. // Nothing to allocate, all triangles are degenerate.
  1566. return;
  1567. }
  1568. pLookupCtx->pLookup = malloc(sizeof(int) * (pLookupCtx->iMaxVertIndex + 1));
  1569. if (pLookupCtx->pLookup == NULL) {
  1570. // Most likely run out of memory.
  1571. return;
  1572. }
  1573. // Fill in lookup.
  1574. for (t = 0; t <= pLookupCtx->iMaxVertIndex; t++) {
  1575. pLookupCtx->pLookup[t] = -1;
  1576. }
  1577. for (t = 0; t < 3 * iNrTrianglesIn; t++) {
  1578. int iVertIndex = piTriListIn[t];
  1579. if (pLookupCtx->pLookup[iVertIndex] != -1) {
  1580. continue;
  1581. }
  1582. pLookupCtx->pLookup[iVertIndex] = t;
  1583. }
  1584. }
  1585. static int LookupVertexIndexFromGoodTriangle(VertReverseLookupContext *pLookupCtx,
  1586. int piTriListIn[],
  1587. const int iNrTrianglesIn,
  1588. const int iVertexIndex)
  1589. {
  1590. // Allocate lookup on demand.
  1591. if (!pLookupCtx->bIsInitialized) {
  1592. GenerateReverseLookup(piTriListIn, iNrTrianglesIn, pLookupCtx);
  1593. pLookupCtx->bIsInitialized = TTRUE;
  1594. }
  1595. // Make sure vertex index is in the mapping.
  1596. if (iVertexIndex > pLookupCtx->iMaxVertIndex) {
  1597. return -1;
  1598. }
  1599. if (pLookupCtx->pLookup == NULL) {
  1600. return -1;
  1601. }
  1602. // Perform actual lookup.
  1603. return pLookupCtx->pLookup[iVertexIndex];
  1604. }
  1605. static void FreeReverseLookup(VertReverseLookupContext *pLookupCtx)
  1606. {
  1607. if (!pLookupCtx->bIsInitialized) {
  1608. return;
  1609. }
  1610. if (pLookupCtx->pLookup != NULL) {
  1611. free(pLookupCtx->pLookup);
  1612. }
  1613. }
  1614. static void DegenEpilogue(STSpace psTspace[],
  1615. STriInfo pTriInfos[],
  1616. int piTriListIn[],
  1617. const SMikkTSpaceContext *pContext,
  1618. const int iNrTrianglesIn,
  1619. const int iTotTris)
  1620. {
  1621. int t = 0, i = 0;
  1622. VertReverseLookupContext lookupCtx = {TFALSE};
  1623. // deal with degenerate triangles
  1624. // punishment for degenerate triangles is O(iNrTrianglesIn) extra memory.
  1625. for (t = iNrTrianglesIn; t < iTotTris; t++) {
  1626. // degenerate triangles on a quad with one good triangle are skipped
  1627. // here but processed in the next loop
  1628. const tbool bSkip = (pTriInfos[t].iFlag & QUAD_ONE_DEGEN_TRI) != 0 ? TTRUE : TFALSE;
  1629. if (bSkip) {
  1630. continue;
  1631. }
  1632. for (i = 0; i < 3; i++) {
  1633. const int index1 = piTriListIn[t * 3 + i];
  1634. int j = LookupVertexIndexFromGoodTriangle(&lookupCtx, piTriListIn, iNrTrianglesIn, index1);
  1635. if (j < 0) {
  1636. // Matching vertex from good triangle is not found.
  1637. continue;
  1638. }
  1639. const int iTri = j / 3;
  1640. const int iVert = j % 3;
  1641. const int iSrcVert = pTriInfos[iTri].vert_num[iVert];
  1642. const int iSrcOffs = pTriInfos[iTri].iTSpacesOffs;
  1643. const int iDstVert = pTriInfos[t].vert_num[i];
  1644. const int iDstOffs = pTriInfos[t].iTSpacesOffs;
  1645. // copy tspace
  1646. psTspace[iDstOffs + iDstVert] = psTspace[iSrcOffs + iSrcVert];
  1647. }
  1648. }
  1649. FreeReverseLookup(&lookupCtx);
  1650. // deal with degenerate quads with one good triangle
  1651. for (t = 0; t < iNrTrianglesIn; t++) {
  1652. // this triangle belongs to a quad where the
  1653. // other triangle is degenerate
  1654. if ((pTriInfos[t].iFlag & QUAD_ONE_DEGEN_TRI) != 0) {
  1655. SVec3 vDstP;
  1656. int iOrgF = -1, i = 0;
  1657. tbool bNotFound;
  1658. unsigned char *pV = pTriInfos[t].vert_num;
  1659. int iFlag = (1 << pV[0]) | (1 << pV[1]) | (1 << pV[2]);
  1660. int iMissingIndex = 0;
  1661. if ((iFlag & 2) == 0)
  1662. iMissingIndex = 1;
  1663. else if ((iFlag & 4) == 0)
  1664. iMissingIndex = 2;
  1665. else if ((iFlag & 8) == 0)
  1666. iMissingIndex = 3;
  1667. iOrgF = pTriInfos[t].iOrgFaceNumber;
  1668. vDstP = GetPosition(pContext, MakeIndex(iOrgF, iMissingIndex));
  1669. bNotFound = TTRUE;
  1670. i = 0;
  1671. while (bNotFound && i < 3) {
  1672. const int iVert = pV[i];
  1673. const SVec3 vSrcP = GetPosition(pContext, MakeIndex(iOrgF, iVert));
  1674. if (veq(vSrcP, vDstP) == TTRUE) {
  1675. const int iOffs = pTriInfos[t].iTSpacesOffs;
  1676. psTspace[iOffs + iMissingIndex] = psTspace[iOffs + iVert];
  1677. bNotFound = TFALSE;
  1678. }
  1679. else
  1680. ++i;
  1681. }
  1682. assert(!bNotFound);
  1683. }
  1684. }
  1685. }