mikktspace.c 56 KB

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