par_msquares.h 77 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117
  1. // MSQUARES :: https://github.com/prideout/par
  2. // Converts fp32 grayscale images, or 8-bit color images, into triangles.
  3. //
  4. // For grayscale images, a threshold is specified to determine insideness.
  5. // For color images, an exact color is specified to determine insideness.
  6. // Color images can be r8, rg16, rgb24, or rgba32. For a visual overview of
  7. // the API and all the flags, see:
  8. //
  9. // http://github.prideout.net/marching-squares/
  10. //
  11. // The MIT License
  12. // Copyright (c) 2015 Philip Rideout
  13. #ifndef PAR_MSQUARES_H
  14. #define PAR_MSQUARES_H
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #endif
  18. #include <stdint.h>
  19. // -----------------------------------------------------------------------------
  20. // BEGIN PUBLIC API
  21. // -----------------------------------------------------------------------------
  22. typedef uint8_t par_byte;
  23. typedef struct par_msquares_meshlist_s par_msquares_meshlist;
  24. // Results of a marching squares operation. Triangles are counter-clockwise.
  25. typedef struct {
  26. float* points; // pointer to XY (or XYZ) vertex coordinates
  27. int npoints; // number of vertex coordinates
  28. uint16_t* triangles; // pointer to 3-tuples of vertex indices
  29. int ntriangles; // number of 3-tuples
  30. int dim; // number of floats per point (either 2 or 3)
  31. uint32_t color; // used only with par_msquares_color_multi
  32. } par_msquares_mesh;
  33. // Polyline boundary extracted from a mesh, composed of one or more chains.
  34. // Counterclockwise chains are solid, clockwise chains are holes. So, when
  35. // serializing to SVG, all chains can be aggregated in a single <path>,
  36. // provided they each terminate with a "Z" and use the default fill rule.
  37. typedef struct {
  38. float* points; // list of XY vertex coordinates
  39. int npoints; // number of vertex coordinates
  40. float** chains; // list of pointers to the start of each chain
  41. uint16_t* lengths; // list of chain lengths
  42. int nchains; // number of chains
  43. } par_msquares_boundary;
  44. // Reverses the "insideness" test.
  45. #define PAR_MSQUARES_INVERT (1 << 0)
  46. // Returns a meshlist with two meshes: one for the inside, one for the outside.
  47. #define PAR_MSQUARES_DUAL (1 << 1)
  48. // Requests that returned meshes have 3-tuple coordinates instead of 2-tuples.
  49. // When using a color-based function, the Z coordinate represents the alpha
  50. // value of the nearest pixel.
  51. #define PAR_MSQUARES_HEIGHTS (1 << 2)
  52. // Applies a step function to the Z coordinates. Requires HEIGHTS and DUAL.
  53. #define PAR_MSQUARES_SNAP (1 << 3)
  54. // Adds extrusion triangles to each mesh other than the lowest mesh. Requires
  55. // the PAR_MSQUARES_HEIGHTS flag to be present.
  56. #define PAR_MSQUARES_CONNECT (1 << 4)
  57. // Enables quick & dirty (not best) simpification of the returned mesh.
  58. #define PAR_MSQUARES_SIMPLIFY (1 << 5)
  59. // Indicates that the "color" argument is ABGR instead of ARGB.
  60. #define PAR_MSQUARES_SWIZZLE (1 << 6)
  61. // Ensures there are no T-junction vertices. (par_msquares_color_multi only)
  62. // Requires the PAR_MSQUARES_SIMPLIFY flag to be disabled.
  63. #define PAR_MSQUARES_CLEAN (1 << 7)
  64. par_msquares_meshlist* par_msquares_grayscale(float const* data, int width,
  65. int height, int cellsize, float threshold, int flags);
  66. par_msquares_meshlist* par_msquares_color(par_byte const* data, int width,
  67. int height, int cellsize, uint32_t color, int bpp, int flags);
  68. par_msquares_mesh const* par_msquares_get_mesh(par_msquares_meshlist*, int n);
  69. int par_msquares_get_count(par_msquares_meshlist*);
  70. void par_msquares_free(par_msquares_meshlist*);
  71. void par_msquares_free_boundary(par_msquares_boundary*);
  72. typedef int (*par_msquares_inside_fn)(int, void*);
  73. typedef float (*par_msquares_height_fn)(float, float, void*);
  74. par_msquares_meshlist* par_msquares_function(int width, int height,
  75. int cellsize, int flags, void* context, par_msquares_inside_fn insidefn,
  76. par_msquares_height_fn heightfn);
  77. par_msquares_meshlist* par_msquares_grayscale_multi(float const* data,
  78. int width, int height, int cellsize, float const* thresholds,
  79. int nthresholds, int flags);
  80. par_msquares_meshlist* par_msquares_color_multi(par_byte const* data, int width,
  81. int height, int cellsize, int bpp, int flags);
  82. par_msquares_boundary* par_msquares_extract_boundary(par_msquares_mesh const* );
  83. #ifndef PAR_PI
  84. #define PAR_PI (3.14159265359)
  85. #define PAR_MIN(a, b) (a > b ? b : a)
  86. #define PAR_MAX(a, b) (a > b ? a : b)
  87. #define PAR_CLAMP(v, lo, hi) PAR_MAX(lo, PAR_MIN(hi, v))
  88. #define PAR_SWAP(T, A, B) { T tmp = B; B = A; A = tmp; }
  89. #define PAR_SQR(a) ((a) * (a))
  90. #endif
  91. #ifndef PAR_MALLOC
  92. #define PAR_MALLOC(T, N) ((T*) malloc(N * sizeof(T)))
  93. #define PAR_CALLOC(T, N) ((T*) calloc(N * sizeof(T), 1))
  94. #define PAR_REALLOC(T, BUF, N) ((T*) realloc(BUF, sizeof(T) * (N)))
  95. #define PAR_FREE(BUF) free(BUF)
  96. #endif
  97. #ifdef __cplusplus
  98. }
  99. #endif
  100. // -----------------------------------------------------------------------------
  101. // END PUBLIC API
  102. // -----------------------------------------------------------------------------
  103. #ifdef PAR_MSQUARES_IMPLEMENTATION
  104. #include <stdlib.h>
  105. #include <assert.h>
  106. #include <float.h>
  107. #include <string.h>
  108. typedef struct {
  109. uint16_t* values;
  110. size_t count;
  111. size_t capacity;
  112. } par__uint16list;
  113. typedef struct {
  114. float* points;
  115. int npoints;
  116. uint16_t* triangles;
  117. int ntriangles;
  118. int dim;
  119. uint32_t color;
  120. int nconntriangles;
  121. uint16_t* conntri;
  122. par__uint16list* tjunctions;
  123. } par_msquares__mesh;
  124. struct par_msquares_meshlist_s {
  125. int nmeshes;
  126. par_msquares__mesh** meshes;
  127. };
  128. static int** par_msquares_binary_point_table = 0;
  129. static int** par_msquares_binary_triangle_table = 0;
  130. static int* par_msquares_quaternary_triangle_table[64][4];
  131. static int* par_msquares_quaternary_boundary_table[64][4];
  132. static par_msquares_meshlist* par_msquares__merge(par_msquares_meshlist** lists,
  133. int count, int snap);
  134. static void par_init_tables()
  135. {
  136. char const* BINARY_TABLE =
  137. "0"
  138. "1017"
  139. "1123"
  140. "2023370"
  141. "1756"
  142. "2015560"
  143. "2123756"
  144. "3023035056"
  145. "1345"
  146. "4013034045057"
  147. "2124451"
  148. "3024045057"
  149. "2734467"
  150. "3013034046"
  151. "3124146167"
  152. "2024460";
  153. char const* binary_token = BINARY_TABLE;
  154. par_msquares_binary_point_table = PAR_CALLOC(int*, 16);
  155. par_msquares_binary_triangle_table = PAR_CALLOC(int*, 16);
  156. for (int i = 0; i < 16; i++) {
  157. int ntris = *binary_token - '0';
  158. binary_token++;
  159. par_msquares_binary_triangle_table[i] =
  160. PAR_CALLOC(int, (ntris + 1) * 3);
  161. int* sqrtris = par_msquares_binary_triangle_table[i];
  162. sqrtris[0] = ntris;
  163. int mask = 0;
  164. int* sqrpts = par_msquares_binary_point_table[i] = PAR_CALLOC(int, 7);
  165. sqrpts[0] = 0;
  166. for (int j = 0; j < ntris * 3; j++, binary_token++) {
  167. int midp = *binary_token - '0';
  168. int bit = 1 << midp;
  169. if (!(mask & bit)) {
  170. mask |= bit;
  171. sqrpts[++sqrpts[0]] = midp;
  172. }
  173. sqrtris[j + 1] = midp;
  174. }
  175. }
  176. char const* QUATERNARY_TABLE =
  177. "2024046000"
  178. "3346360301112300"
  179. "3346360301112300"
  180. "3346360301112300"
  181. "3560502523013450"
  182. "2015056212414500"
  183. "4018087785756212313828348450"
  184. "4018087785756212313828348450"
  185. "3560502523013450"
  186. "4018087785756212313828348450"
  187. "2015056212414500"
  188. "4018087785756212313828348450"
  189. "3560502523013450"
  190. "4018087785756212313828348450"
  191. "4018087785756212313828348450"
  192. "2015056212414500"
  193. "3702724745001756"
  194. "2018087212313828348452785756"
  195. "4013034045057112301756"
  196. "4013034045057112301756"
  197. "2023037027347460"
  198. "1701312414616700"
  199. "2018087212313847857568348450"
  200. "2018087212313847857568348450"
  201. "4018087123138028348452785756"
  202. "1701467161262363513450"
  203. "2018087412313883484502785756"
  204. "2018087212313828348452785756"
  205. "4018087123138028348452785756"
  206. "1701467161262363513450"
  207. "2018087212313828348452785756"
  208. "2018087412313883484502785756"
  209. "3702724745001756"
  210. "4013034045057112301756"
  211. "2018087212313828348452785756"
  212. "4013034045057112301756"
  213. "4018087123138028348452785756"
  214. "2018087412313883484502785756"
  215. "1701467161262363513450"
  216. "2018087212313828348452785756"
  217. "2023037027347460"
  218. "2018087212313847857568348450"
  219. "1701312414616700"
  220. "2018087212313847857568348450"
  221. "4018087123138028348452785756"
  222. "2018087212313828348452785756"
  223. "1701467161262363513450"
  224. "2018087412313883484502785756"
  225. "3702724745001756"
  226. "4013034045057112301756"
  227. "4013034045057112301756"
  228. "2018087212313828348452785756"
  229. "4018087123138028348452785756"
  230. "2018087412313883484502785756"
  231. "2018087212313828348452785756"
  232. "1701467161262363513450"
  233. "4018087123138028348452785756"
  234. "2018087212313828348452785756"
  235. "2018087412313883484502785756"
  236. "1701467161262363513450"
  237. "2023037027347460"
  238. "2018087212313847857568348450"
  239. "2018087212313847857568348450"
  240. "1701312414616700";
  241. char const* quaternary_token = QUATERNARY_TABLE;
  242. int* quaternary_values = PAR_CALLOC(int, strlen(QUATERNARY_TABLE));
  243. int* vals = quaternary_values;
  244. for (int i = 0; i < 64; i++) {
  245. int ntris = *quaternary_token++ - '0';
  246. *vals = ntris;
  247. par_msquares_quaternary_triangle_table[i][0] = vals++;
  248. for (int j = 0; j < ntris * 3; j++) {
  249. int pt = *quaternary_token++ - '0';
  250. assert(pt >= 0 && pt < 9);
  251. *vals++ = pt;
  252. }
  253. ntris = *quaternary_token++ - '0';
  254. *vals = ntris;
  255. par_msquares_quaternary_triangle_table[i][1] = vals++;
  256. for (int j = 0; j < ntris * 3; j++) {
  257. int pt = *quaternary_token++ - '0';
  258. assert(pt >= 0 && pt < 9);
  259. *vals++ = pt;
  260. }
  261. ntris = *quaternary_token++ - '0';
  262. *vals = ntris;
  263. par_msquares_quaternary_triangle_table[i][2] = vals++;
  264. for (int j = 0; j < ntris * 3; j++) {
  265. int pt = *quaternary_token++ - '0';
  266. assert(pt >= 0 && pt < 9);
  267. *vals++ = pt;
  268. }
  269. ntris = *quaternary_token++ - '0';
  270. *vals = ntris;
  271. par_msquares_quaternary_triangle_table[i][3] = vals++;
  272. for (int j = 0; j < ntris * 3; j++) {
  273. int pt = *quaternary_token++ - '0';
  274. assert(pt >= 0 && pt < 9);
  275. *vals++ = pt;
  276. }
  277. }
  278. assert(vals == quaternary_values + strlen(QUATERNARY_TABLE));
  279. char const* QUATERNARY_EDGES =
  280. "0000"
  281. "11313100113131001131310013501530"
  282. "115151002188523881258830218852388125883013501530"
  283. "218852388125883011515100218852388125883013501530"
  284. "218852388125883021885238812588301151510015700175"
  285. "2188723881258832788521357131017521357131017513701730"
  286. "11717100218872388127883021887238812788302388702588327885"
  287. "1172713515302188725881027885218872388125883278852388702588327885"
  288. "11727135153021887238812588327885218872588102788515700175"
  289. "213571310175218872388125883278852135713101752388702588327885"
  290. "21887258810278851172713515302188723881258832788513701730"
  291. "21887238812788301171710021887238812788302388702588327885"
  292. "21887238812588327885117271351530218872588102788515700175"
  293. "213571310175213571310175218872388125883278852388702588327885"
  294. "2188725881027885218872388125883278851172713515302388702588327885"
  295. "21887238812588327885218872588102788511727135153013701730"
  296. "2188723881278830218872388127883011717100";
  297. quaternary_token = QUATERNARY_EDGES;
  298. quaternary_values = PAR_CALLOC(int, strlen(QUATERNARY_EDGES));
  299. vals = quaternary_values;
  300. for (int i = 0; i < 64; i++) {
  301. int nedges = *quaternary_token++ - '0';
  302. *vals = nedges;
  303. par_msquares_quaternary_boundary_table[i][0] = vals++;
  304. for (int j = 0; j < nedges * 2; j++) {
  305. int pt = *quaternary_token++ - '0';
  306. assert(pt >= 0 && pt < 9);
  307. *vals++ = pt;
  308. }
  309. nedges = *quaternary_token++ - '0';
  310. *vals = nedges;
  311. par_msquares_quaternary_boundary_table[i][1] = vals++;
  312. for (int j = 0; j < nedges * 2; j++) {
  313. int pt = *quaternary_token++ - '0';
  314. assert(pt >= 0 && pt < 9);
  315. *vals++ = pt;
  316. }
  317. nedges = *quaternary_token++ - '0';
  318. *vals = nedges;
  319. par_msquares_quaternary_boundary_table[i][2] = vals++;
  320. for (int j = 0; j < nedges * 2; j++) {
  321. int pt = *quaternary_token++ - '0';
  322. assert(pt >= 0 && pt < 9);
  323. *vals++ = pt;
  324. }
  325. nedges = *quaternary_token++ - '0';
  326. *vals = nedges;
  327. par_msquares_quaternary_boundary_table[i][3] = vals++;
  328. for (int j = 0; j < nedges * 2; j++) {
  329. int pt = *quaternary_token++ - '0';
  330. assert(pt >= 0 && pt < 9);
  331. *vals++ = pt;
  332. }
  333. }
  334. assert(vals == quaternary_values + strlen(QUATERNARY_EDGES));
  335. }
  336. typedef struct {
  337. float const* data;
  338. float threshold;
  339. float lower_bound;
  340. float upper_bound;
  341. int width;
  342. int height;
  343. } par_gray_context;
  344. static int gray_inside(int location, void* contextptr)
  345. {
  346. par_gray_context* context = (par_gray_context*) contextptr;
  347. return context->data[location] > context->threshold;
  348. }
  349. static int gray_multi_inside(int location, void* contextptr)
  350. {
  351. par_gray_context* context = (par_gray_context*) contextptr;
  352. float val = context->data[location];
  353. float upper = context->upper_bound;
  354. float lower = context->lower_bound;
  355. return val >= lower && val < upper;
  356. }
  357. static float gray_height(float x, float y, void* contextptr)
  358. {
  359. par_gray_context* context = (par_gray_context*) contextptr;
  360. int i = PAR_CLAMP(context->width * x, 0, context->width - 1);
  361. int j = PAR_CLAMP(context->height * y, 0, context->height - 1);
  362. return context->data[i + j * context->width];
  363. }
  364. typedef struct {
  365. par_byte const* data;
  366. par_byte color[4];
  367. int bpp;
  368. int width;
  369. int height;
  370. } par_color_context;
  371. static int color_inside(int location, void* contextptr)
  372. {
  373. par_color_context* context = (par_color_context*) contextptr;
  374. par_byte const* data = context->data + location * context->bpp;
  375. for (int i = 0; i < context->bpp; i++) {
  376. if (data[i] != context->color[i]) {
  377. return 0;
  378. }
  379. }
  380. return 1;
  381. }
  382. static float color_height(float x, float y, void* contextptr)
  383. {
  384. par_color_context* context = (par_color_context*) contextptr;
  385. assert(context->bpp == 4);
  386. int i = PAR_CLAMP(context->width * x, 0, context->width - 1);
  387. int j = PAR_CLAMP(context->height * y, 0, context->height - 1);
  388. int k = i + j * context->width;
  389. return context->data[k * 4 + 3] / 255.0;
  390. }
  391. par_msquares_meshlist* par_msquares_color(par_byte const* data, int width,
  392. int height, int cellsize, uint32_t color, int bpp, int flags)
  393. {
  394. par_color_context context;
  395. context.bpp = bpp;
  396. if (flags & PAR_MSQUARES_SWIZZLE) {
  397. context.color[0] = (color >> 0) & 0xff;
  398. context.color[1] = (color >> 8) & 0xff;
  399. context.color[2] = (color >> 16) & 0xff;
  400. context.color[3] = (color >> 24) & 0xff;
  401. } else {
  402. context.color[0] = (color >> 16) & 0xff;
  403. context.color[1] = (color >> 8) & 0xff;
  404. context.color[2] = (color >> 0) & 0xff;
  405. context.color[3] = (color >> 24) & 0xff;
  406. }
  407. context.data = data;
  408. context.width = width;
  409. context.height = height;
  410. return par_msquares_function(
  411. width, height, cellsize, flags, &context, color_inside, color_height);
  412. }
  413. par_msquares_meshlist* par_msquares_grayscale(float const* data, int width,
  414. int height, int cellsize, float threshold, int flags)
  415. {
  416. par_gray_context context;
  417. context.width = width;
  418. context.height = height;
  419. context.data = data;
  420. context.threshold = threshold;
  421. return par_msquares_function(
  422. width, height, cellsize, flags, &context, gray_inside, gray_height);
  423. }
  424. par_msquares_meshlist* par_msquares_grayscale_multi(float const* data,
  425. int width, int height, int cellsize, float const* thresholds,
  426. int nthresholds, int flags)
  427. {
  428. par_msquares_meshlist* mlists[2];
  429. mlists[0] = PAR_CALLOC(par_msquares_meshlist, 1);
  430. int connect = flags & PAR_MSQUARES_CONNECT;
  431. int snap = flags & PAR_MSQUARES_SNAP;
  432. int heights = flags & PAR_MSQUARES_HEIGHTS;
  433. if (!heights) {
  434. snap = connect = 0;
  435. }
  436. flags &= ~PAR_MSQUARES_INVERT;
  437. flags &= ~PAR_MSQUARES_DUAL;
  438. flags &= ~PAR_MSQUARES_CONNECT;
  439. flags &= ~PAR_MSQUARES_SNAP;
  440. par_gray_context context;
  441. context.width = width;
  442. context.height = height;
  443. context.data = data;
  444. context.lower_bound = -FLT_MAX;
  445. for (int i = 0; i <= nthresholds; i++) {
  446. int mergeconf = i > 0 ? connect : 0;
  447. if (i == nthresholds) {
  448. context.upper_bound = FLT_MAX;
  449. mergeconf |= snap;
  450. } else {
  451. context.upper_bound = thresholds[i];
  452. }
  453. mlists[1] = par_msquares_function(width, height, cellsize, flags,
  454. &context, gray_multi_inside, gray_height);
  455. mlists[0] = par_msquares__merge(mlists, 2, mergeconf);
  456. context.lower_bound = context.upper_bound;
  457. flags |= connect;
  458. }
  459. return mlists[0];
  460. }
  461. par_msquares_mesh const* par_msquares_get_mesh(
  462. par_msquares_meshlist* mlist, int mindex)
  463. {
  464. assert(mlist && mindex < mlist->nmeshes);
  465. return (par_msquares_mesh const*) mlist->meshes[mindex];
  466. }
  467. int par_msquares_get_count(par_msquares_meshlist* mlist)
  468. {
  469. assert(mlist);
  470. return mlist->nmeshes;
  471. }
  472. void par_msquares_free(par_msquares_meshlist* mlist)
  473. {
  474. if (!mlist) {
  475. return;
  476. }
  477. par_msquares__mesh** meshes = mlist->meshes;
  478. for (int i = 0; i < mlist->nmeshes; i++) {
  479. free(meshes[i]->points);
  480. free(meshes[i]->triangles);
  481. free(meshes[i]);
  482. }
  483. free(meshes);
  484. free(mlist);
  485. }
  486. // Combine multiple meshlists by moving mesh pointers, and optionally apply
  487. // a "snap" operation that assigns a single Z value across all verts in each
  488. // mesh. The Z value determined by the mesh's position in the final mesh list.
  489. static par_msquares_meshlist* par_msquares__merge(par_msquares_meshlist** lists,
  490. int count, int snap)
  491. {
  492. par_msquares_meshlist* merged = PAR_CALLOC(par_msquares_meshlist, 1);
  493. merged->nmeshes = 0;
  494. for (int i = 0; i < count; i++) {
  495. merged->nmeshes += lists[i]->nmeshes;
  496. }
  497. merged->meshes = PAR_CALLOC(par_msquares__mesh*, merged->nmeshes);
  498. par_msquares__mesh** pmesh = merged->meshes;
  499. for (int i = 0; i < count; i++) {
  500. par_msquares_meshlist* meshlist = lists[i];
  501. for (int j = 0; j < meshlist->nmeshes; j++) {
  502. *pmesh++ = meshlist->meshes[j];
  503. }
  504. free(meshlist);
  505. }
  506. if (!snap) {
  507. return merged;
  508. }
  509. pmesh = merged->meshes;
  510. float zmin = FLT_MAX;
  511. float zmax = -zmin;
  512. for (int i = 0; i < merged->nmeshes; i++, pmesh++) {
  513. float* pzed = (*pmesh)->points + 2;
  514. for (int j = 0; j < (*pmesh)->npoints; j++, pzed += 3) {
  515. zmin = PAR_MIN(*pzed, zmin);
  516. zmax = PAR_MAX(*pzed, zmax);
  517. }
  518. }
  519. float zextent = zmax - zmin;
  520. pmesh = merged->meshes;
  521. for (int i = 0; i < merged->nmeshes; i++, pmesh++) {
  522. float* pzed = (*pmesh)->points + 2;
  523. float zed = zmin + zextent * i / (merged->nmeshes - 1);
  524. for (int j = 0; j < (*pmesh)->npoints; j++, pzed += 3) {
  525. *pzed = zed;
  526. }
  527. }
  528. if (!(snap & PAR_MSQUARES_CONNECT)) {
  529. return merged;
  530. }
  531. for (int i = 1; i < merged->nmeshes; i++) {
  532. par_msquares__mesh* mesh = merged->meshes[i];
  533. // Find all extrusion points. This is tightly coupled to the
  534. // tessellation code, which generates two "connector" triangles for each
  535. // extruded edge. The first two verts of the second triangle are the
  536. // verts that need to be displaced.
  537. char* markers = PAR_CALLOC(char, mesh->npoints);
  538. int tri = mesh->ntriangles - mesh->nconntriangles;
  539. while (tri < mesh->ntriangles) {
  540. markers[mesh->triangles[tri * 3 + 3]] = 1;
  541. markers[mesh->triangles[tri * 3 + 4]] = 1;
  542. tri += 2;
  543. }
  544. // Displace all extrusion points down to the previous level.
  545. float zed = zmin + zextent * (i - 1) / (merged->nmeshes - 1);
  546. float* pzed = mesh->points + 2;
  547. for (int j = 0; j < mesh->npoints; j++, pzed += 3) {
  548. if (markers[j]) {
  549. *pzed = zed;
  550. }
  551. }
  552. free(markers);
  553. }
  554. return merged;
  555. }
  556. static void par_remove_unreferenced_verts(par_msquares__mesh* mesh)
  557. {
  558. if (mesh->npoints == 0) {
  559. return;
  560. }
  561. char* markers = PAR_CALLOC(char, mesh->npoints);
  562. uint16_t const* ptris = mesh->triangles;
  563. int newnpts = 0;
  564. for (int i = 0; i < mesh->ntriangles * 3; i++, ptris++) {
  565. if (!markers[*ptris]) {
  566. newnpts++;
  567. markers[*ptris] = 1;
  568. }
  569. }
  570. float* newpts = PAR_CALLOC(float, newnpts * mesh->dim);
  571. uint16_t* mapping = PAR_CALLOC(uint16_t, mesh->npoints);
  572. float const* ppts = mesh->points;
  573. float* pnewpts = newpts;
  574. int j = 0;
  575. if (mesh->dim == 3) {
  576. for (int i = 0; i < mesh->npoints; i++, ppts += 3) {
  577. if (markers[i]) {
  578. *pnewpts++ = ppts[0];
  579. *pnewpts++ = ppts[1];
  580. *pnewpts++ = ppts[2];
  581. mapping[i] = j++;
  582. }
  583. }
  584. } else {
  585. for (int i = 0; i < mesh->npoints; i++, ppts += 2) {
  586. if (markers[i]) {
  587. *pnewpts++ = ppts[0];
  588. *pnewpts++ = ppts[1];
  589. mapping[i] = j++;
  590. }
  591. }
  592. }
  593. free(mesh->points);
  594. free(markers);
  595. mesh->points = newpts;
  596. mesh->npoints = newnpts;
  597. for (int i = 0; i < mesh->ntriangles * 3; i++) {
  598. mesh->triangles[i] = mapping[mesh->triangles[i]];
  599. }
  600. free(mapping);
  601. }
  602. par_msquares_meshlist* par_msquares_function(int width, int height,
  603. int cellsize, int flags, void* context, par_msquares_inside_fn insidefn,
  604. par_msquares_height_fn heightfn)
  605. {
  606. assert(width > 0 && width % cellsize == 0);
  607. assert(height > 0 && height % cellsize == 0);
  608. if (flags & PAR_MSQUARES_DUAL) {
  609. int connect = flags & PAR_MSQUARES_CONNECT;
  610. int snap = flags & PAR_MSQUARES_SNAP;
  611. int heights = flags & PAR_MSQUARES_HEIGHTS;
  612. if (!heights) {
  613. snap = connect = 0;
  614. }
  615. flags ^= PAR_MSQUARES_INVERT;
  616. flags &= ~PAR_MSQUARES_DUAL;
  617. flags &= ~PAR_MSQUARES_CONNECT;
  618. par_msquares_meshlist* m[2];
  619. m[0] = par_msquares_function(width, height, cellsize, flags,
  620. context, insidefn, heightfn);
  621. flags ^= PAR_MSQUARES_INVERT;
  622. if (connect) {
  623. flags |= PAR_MSQUARES_CONNECT;
  624. }
  625. m[1] = par_msquares_function(width, height, cellsize, flags,
  626. context, insidefn, heightfn);
  627. return par_msquares__merge(m, 2, snap | connect);
  628. }
  629. int invert = flags & PAR_MSQUARES_INVERT;
  630. // Create the two code tables if we haven't already. These are tables of
  631. // fixed constants, so it's embarassing that we use dynamic memory
  632. // allocation for them. However it's easy and it's one-time-only.
  633. if (!par_msquares_binary_point_table) {
  634. par_init_tables();
  635. }
  636. // Allocate the meshlist and the first mesh.
  637. par_msquares_meshlist* mlist = PAR_CALLOC(par_msquares_meshlist, 1);
  638. mlist->nmeshes = 1;
  639. mlist->meshes = PAR_CALLOC(par_msquares__mesh*, 1);
  640. mlist->meshes[0] = PAR_CALLOC(par_msquares__mesh, 1);
  641. par_msquares__mesh* mesh = mlist->meshes[0];
  642. mesh->dim = (flags & PAR_MSQUARES_HEIGHTS) ? 3 : 2;
  643. int ncols = width / cellsize;
  644. int nrows = height / cellsize;
  645. // Worst case is four triangles and six verts per cell, so allocate that
  646. // much.
  647. int maxtris = ncols * nrows * 4;
  648. int maxpts = ncols * nrows * 6;
  649. int maxedges = ncols * nrows * 2;
  650. // However, if we include extrusion triangles for boundary edges,
  651. // we need space for another 4 triangles and 4 points per cell.
  652. uint16_t* conntris = 0;
  653. int nconntris = 0;
  654. uint16_t* edgemap = 0;
  655. if (flags & PAR_MSQUARES_CONNECT) {
  656. conntris = PAR_CALLOC(uint16_t, maxedges * 6);
  657. maxtris += maxedges * 2;
  658. maxpts += maxedges * 2;
  659. edgemap = PAR_CALLOC(uint16_t, maxpts);
  660. for (int i = 0; i < maxpts; i++) {
  661. edgemap[i] = 0xffff;
  662. }
  663. }
  664. uint16_t* tris = PAR_CALLOC(uint16_t, maxtris * 3);
  665. int ntris = 0;
  666. float* pts = PAR_CALLOC(float, maxpts * mesh->dim);
  667. int npts = 0;
  668. // The "verts" x/y/z arrays are the 4 corners and 4 midpoints around the
  669. // square, in counter-clockwise order. The origin of "triangle space" is at
  670. // the lower-left, although we expect the image data to be in raster order
  671. // (starts at top-left).
  672. float vertsx[8], vertsy[8];
  673. float normalization = 1.0f / PAR_MAX(width, height);
  674. float normalized_cellsize = cellsize * normalization;
  675. int maxrow = (height - 1) * width;
  676. uint16_t* ptris = tris;
  677. uint16_t* pconntris = conntris;
  678. float* ppts = pts;
  679. uint8_t* prevrowmasks = PAR_CALLOC(uint8_t, ncols);
  680. int* prevrowinds = PAR_CALLOC(int, ncols * 3);
  681. // If simplification is enabled, we need to track all 'F' cells and their
  682. // repsective triangle indices.
  683. uint8_t* simplification_codes = 0;
  684. uint16_t* simplification_tris = 0;
  685. uint8_t* simplification_ntris = 0;
  686. if (flags & PAR_MSQUARES_SIMPLIFY) {
  687. simplification_codes = PAR_CALLOC(uint8_t, nrows * ncols);
  688. simplification_tris = PAR_CALLOC(uint16_t, nrows * ncols);
  689. simplification_ntris = PAR_CALLOC(uint8_t, nrows * ncols);
  690. }
  691. // Do the march!
  692. for (int row = 0; row < nrows; row++) {
  693. vertsx[0] = vertsx[6] = vertsx[7] = 0;
  694. vertsx[1] = vertsx[5] = 0.5 * normalized_cellsize;
  695. vertsx[2] = vertsx[3] = vertsx[4] = normalized_cellsize;
  696. vertsy[0] = vertsy[1] = vertsy[2] = normalized_cellsize * (row + 1);
  697. vertsy[4] = vertsy[5] = vertsy[6] = normalized_cellsize * row;
  698. vertsy[3] = vertsy[7] = normalized_cellsize * (row + 0.5);
  699. int northi = row * cellsize * width;
  700. int southi = PAR_MIN(northi + cellsize * width, maxrow);
  701. int northwest = invert ^ insidefn(northi, context);
  702. int southwest = invert ^ insidefn(southi, context);
  703. int previnds[8] = {0};
  704. uint8_t prevmask = 0;
  705. for (int col = 0; col < ncols; col++) {
  706. northi += cellsize;
  707. southi += cellsize;
  708. if (col == ncols - 1) {
  709. northi--;
  710. southi--;
  711. }
  712. int northeast = invert ^ insidefn(northi, context);
  713. int southeast = invert ^ insidefn(southi, context);
  714. int code = southwest | (southeast << 1) | (northwest << 2) |
  715. (northeast << 3);
  716. int const* pointspec = par_msquares_binary_point_table[code];
  717. int ptspeclength = *pointspec++;
  718. int currinds[8] = {0};
  719. uint8_t mask = 0;
  720. uint8_t prevrowmask = prevrowmasks[col];
  721. while (ptspeclength--) {
  722. int midp = *pointspec++;
  723. int bit = 1 << midp;
  724. mask |= bit;
  725. // The following six conditionals perform welding to reduce the
  726. // number of vertices. The first three perform welding with the
  727. // cell to the west; the latter three perform welding with the
  728. // cell to the north.
  729. if (bit == 1 && (prevmask & 4)) {
  730. currinds[midp] = previnds[2];
  731. continue;
  732. }
  733. if (bit == 128 && (prevmask & 8)) {
  734. currinds[midp] = previnds[3];
  735. continue;
  736. }
  737. if (bit == 64 && (prevmask & 16)) {
  738. currinds[midp] = previnds[4];
  739. continue;
  740. }
  741. if (bit == 16 && (prevrowmask & 4)) {
  742. currinds[midp] = prevrowinds[col * 3 + 2];
  743. continue;
  744. }
  745. if (bit == 32 && (prevrowmask & 2)) {
  746. currinds[midp] = prevrowinds[col * 3 + 1];
  747. continue;
  748. }
  749. if (bit == 64 && (prevrowmask & 1)) {
  750. currinds[midp] = prevrowinds[col * 3 + 0];
  751. continue;
  752. }
  753. ppts[0] = vertsx[midp];
  754. ppts[1] = vertsy[midp];
  755. // Adjust the midpoints to a more exact crossing point.
  756. if (midp == 1) {
  757. int begin = southi - cellsize / 2;
  758. int previous = 0;
  759. for (int i = 0; i < cellsize; i++) {
  760. int offset = begin + i / 2 * ((i % 2) ? -1 : 1);
  761. int inside = insidefn(offset, context);
  762. if (i > 0 && inside != previous) {
  763. ppts[0] = normalization *
  764. (col * cellsize + offset - southi + cellsize);
  765. break;
  766. }
  767. previous = inside;
  768. }
  769. } else if (midp == 5) {
  770. int begin = northi - cellsize / 2;
  771. int previous = 0;
  772. for (int i = 0; i < cellsize; i++) {
  773. int offset = begin + i / 2 * ((i % 2) ? -1 : 1);
  774. int inside = insidefn(offset, context);
  775. if (i > 0 && inside != previous) {
  776. ppts[0] = normalization *
  777. (col * cellsize + offset - northi + cellsize);
  778. break;
  779. }
  780. previous = inside;
  781. }
  782. } else if (midp == 3) {
  783. int begin = northi + width * cellsize / 2;
  784. int previous = 0;
  785. for (int i = 0; i < cellsize; i++) {
  786. int offset = begin +
  787. width * (i / 2 * ((i % 2) ? -1 : 1));
  788. int inside = insidefn(offset, context);
  789. if (i > 0 && inside != previous) {
  790. ppts[1] = normalization *
  791. (row * cellsize +
  792. (offset - northi) / (float) width);
  793. break;
  794. }
  795. previous = inside;
  796. }
  797. } else if (midp == 7) {
  798. int begin = northi + width * cellsize / 2 - cellsize;
  799. int previous = 0;
  800. for (int i = 0; i < cellsize; i++) {
  801. int offset = begin +
  802. width * (i / 2 * ((i % 2) ? -1 : 1));
  803. int inside = insidefn(offset, context);
  804. if (i > 0 && inside != previous) {
  805. ppts[1] = normalization *
  806. (row * cellsize +
  807. (offset - northi - cellsize) / (float) width);
  808. break;
  809. }
  810. previous = inside;
  811. }
  812. }
  813. if (mesh->dim == 3) {
  814. ppts[2] = heightfn(ppts[0], ppts[1], context);
  815. }
  816. ppts += mesh->dim;
  817. currinds[midp] = npts++;
  818. }
  819. int const* trianglespec = par_msquares_binary_triangle_table[code];
  820. int trispeclength = *trianglespec++;
  821. if (flags & PAR_MSQUARES_SIMPLIFY) {
  822. simplification_codes[ncols * row + col] = code;
  823. simplification_tris[ncols * row + col] = ntris;
  824. simplification_ntris[ncols * row + col] = trispeclength;
  825. }
  826. // Add triangles.
  827. while (trispeclength--) {
  828. int a = *trianglespec++;
  829. int b = *trianglespec++;
  830. int c = *trianglespec++;
  831. *ptris++ = currinds[c];
  832. *ptris++ = currinds[b];
  833. *ptris++ = currinds[a];
  834. ntris++;
  835. }
  836. // Create two extrusion triangles for each boundary edge.
  837. if (flags & PAR_MSQUARES_CONNECT) {
  838. trianglespec = par_msquares_binary_triangle_table[code];
  839. trispeclength = *trianglespec++;
  840. while (trispeclength--) {
  841. int a = *trianglespec++;
  842. int b = *trianglespec++;
  843. int c = *trianglespec++;
  844. int i = currinds[a];
  845. int j = currinds[b];
  846. int k = currinds[c];
  847. int u = 0, v = 0, w = 0;
  848. if ((a % 2) && (b % 2)) {
  849. u = v = 1;
  850. } else if ((a % 2) && (c % 2)) {
  851. u = w = 1;
  852. } else if ((b % 2) && (c % 2)) {
  853. v = w = 1;
  854. } else {
  855. continue;
  856. }
  857. if (u && edgemap[i] == 0xffff) {
  858. for (int d = 0; d < mesh->dim; d++) {
  859. *ppts++ = pts[i * mesh->dim + d];
  860. }
  861. edgemap[i] = npts++;
  862. }
  863. if (v && edgemap[j] == 0xffff) {
  864. for (int d = 0; d < mesh->dim; d++) {
  865. *ppts++ = pts[j * mesh->dim + d];
  866. }
  867. edgemap[j] = npts++;
  868. }
  869. if (w && edgemap[k] == 0xffff) {
  870. for (int d = 0; d < mesh->dim; d++) {
  871. *ppts++ = pts[k * mesh->dim + d];
  872. }
  873. edgemap[k] = npts++;
  874. }
  875. if ((a % 2) && (b % 2)) {
  876. *pconntris++ = i;
  877. *pconntris++ = j;
  878. *pconntris++ = edgemap[j];
  879. *pconntris++ = edgemap[j];
  880. *pconntris++ = edgemap[i];
  881. *pconntris++ = i;
  882. } else if ((a % 2) && (c % 2)) {
  883. *pconntris++ = edgemap[k];
  884. *pconntris++ = k;
  885. *pconntris++ = i;
  886. *pconntris++ = edgemap[i];
  887. *pconntris++ = edgemap[k];
  888. *pconntris++ = i;
  889. } else if ((b % 2) && (c % 2)) {
  890. *pconntris++ = j;
  891. *pconntris++ = k;
  892. *pconntris++ = edgemap[k];
  893. *pconntris++ = edgemap[k];
  894. *pconntris++ = edgemap[j];
  895. *pconntris++ = j;
  896. }
  897. nconntris += 2;
  898. }
  899. }
  900. // Prepare for the next cell.
  901. prevrowmasks[col] = mask;
  902. prevrowinds[col * 3 + 0] = currinds[0];
  903. prevrowinds[col * 3 + 1] = currinds[1];
  904. prevrowinds[col * 3 + 2] = currinds[2];
  905. prevmask = mask;
  906. northwest = northeast;
  907. southwest = southeast;
  908. for (int i = 0; i < 8; i++) {
  909. previnds[i] = currinds[i];
  910. vertsx[i] += normalized_cellsize;
  911. }
  912. }
  913. }
  914. free(edgemap);
  915. free(prevrowmasks);
  916. free(prevrowinds);
  917. // Perform quick-n-dirty simplification by iterating two rows at a time.
  918. // In no way does this create the simplest possible mesh, but at least it's
  919. // fast and easy.
  920. if (flags & PAR_MSQUARES_SIMPLIFY) {
  921. int in_run = 0, start_run;
  922. // First figure out how many triangles we can eliminate.
  923. int neliminated_triangles = 0;
  924. for (int row = 0; row < nrows - 1; row += 2) {
  925. for (int col = 0; col < ncols; col++) {
  926. int a = simplification_codes[ncols * row + col] == 0xf;
  927. int b = simplification_codes[ncols * row + col + ncols] == 0xf;
  928. if (a && b) {
  929. if (!in_run) {
  930. in_run = 1;
  931. start_run = col;
  932. }
  933. continue;
  934. }
  935. if (in_run) {
  936. in_run = 0;
  937. int run_width = col - start_run;
  938. neliminated_triangles += run_width * 4 - 2;
  939. }
  940. }
  941. if (in_run) {
  942. in_run = 0;
  943. int run_width = ncols - start_run;
  944. neliminated_triangles += run_width * 4 - 2;
  945. }
  946. }
  947. // Build a new index array cell-by-cell. If any given cell is 'F' and
  948. // its neighbor to the south is also 'F', then it's part of a run.
  949. int nnewtris = ntris + nconntris - neliminated_triangles;
  950. uint16_t* newtris = PAR_CALLOC(uint16_t, nnewtris * 3);
  951. uint16_t* pnewtris = newtris;
  952. in_run = 0;
  953. for (int row = 0; row < nrows - 1; row += 2) {
  954. for (int col = 0; col < ncols; col++) {
  955. int cell = ncols * row + col;
  956. int south = cell + ncols;
  957. int a = simplification_codes[cell] == 0xf;
  958. int b = simplification_codes[south] == 0xf;
  959. if (a && b) {
  960. if (!in_run) {
  961. in_run = 1;
  962. start_run = col;
  963. }
  964. continue;
  965. }
  966. if (in_run) {
  967. in_run = 0;
  968. int nw_cell = ncols * row + start_run;
  969. int ne_cell = ncols * row + col - 1;
  970. int sw_cell = nw_cell + ncols;
  971. int se_cell = ne_cell + ncols;
  972. int nw_tri = simplification_tris[nw_cell];
  973. int ne_tri = simplification_tris[ne_cell];
  974. int sw_tri = simplification_tris[sw_cell];
  975. int se_tri = simplification_tris[se_cell];
  976. int nw_corner = nw_tri * 3 + 4;
  977. int ne_corner = ne_tri * 3 + 0;
  978. int sw_corner = sw_tri * 3 + 2;
  979. int se_corner = se_tri * 3 + 1;
  980. *pnewtris++ = tris[se_corner];
  981. *pnewtris++ = tris[sw_corner];
  982. *pnewtris++ = tris[nw_corner];
  983. *pnewtris++ = tris[nw_corner];
  984. *pnewtris++ = tris[ne_corner];
  985. *pnewtris++ = tris[se_corner];
  986. }
  987. int ncelltris = simplification_ntris[cell];
  988. int celltri = simplification_tris[cell];
  989. for (int t = 0; t < ncelltris; t++, celltri++) {
  990. *pnewtris++ = tris[celltri * 3];
  991. *pnewtris++ = tris[celltri * 3 + 1];
  992. *pnewtris++ = tris[celltri * 3 + 2];
  993. }
  994. ncelltris = simplification_ntris[south];
  995. celltri = simplification_tris[south];
  996. for (int t = 0; t < ncelltris; t++, celltri++) {
  997. *pnewtris++ = tris[celltri * 3];
  998. *pnewtris++ = tris[celltri * 3 + 1];
  999. *pnewtris++ = tris[celltri * 3 + 2];
  1000. }
  1001. }
  1002. if (in_run) {
  1003. in_run = 0;
  1004. int nw_cell = ncols * row + start_run;
  1005. int ne_cell = ncols * row + ncols - 1;
  1006. int sw_cell = nw_cell + ncols;
  1007. int se_cell = ne_cell + ncols;
  1008. int nw_tri = simplification_tris[nw_cell];
  1009. int ne_tri = simplification_tris[ne_cell];
  1010. int sw_tri = simplification_tris[sw_cell];
  1011. int se_tri = simplification_tris[se_cell];
  1012. int nw_corner = nw_tri * 3 + 4;
  1013. int ne_corner = ne_tri * 3 + 0;
  1014. int sw_corner = sw_tri * 3 + 2;
  1015. int se_corner = se_tri * 3 + 1;
  1016. *pnewtris++ = tris[se_corner];
  1017. *pnewtris++ = tris[sw_corner];
  1018. *pnewtris++ = tris[nw_corner];
  1019. *pnewtris++ = tris[nw_corner];
  1020. *pnewtris++ = tris[ne_corner];
  1021. *pnewtris++ = tris[se_corner];
  1022. }
  1023. }
  1024. ptris = pnewtris;
  1025. ntris -= neliminated_triangles;
  1026. free(tris);
  1027. tris = newtris;
  1028. free(simplification_codes);
  1029. free(simplification_tris);
  1030. free(simplification_ntris);
  1031. // Remove unreferenced points.
  1032. char* markers = PAR_CALLOC(char, npts);
  1033. ptris = tris;
  1034. int newnpts = 0;
  1035. for (int i = 0; i < ntris * 3; i++, ptris++) {
  1036. if (!markers[*ptris]) {
  1037. newnpts++;
  1038. markers[*ptris] = 1;
  1039. }
  1040. }
  1041. for (int i = 0; i < nconntris * 3; i++) {
  1042. if (!markers[conntris[i]]) {
  1043. newnpts++;
  1044. markers[conntris[i]] = 1;
  1045. }
  1046. }
  1047. float* newpts = PAR_CALLOC(float, newnpts * mesh->dim);
  1048. uint16_t* mapping = PAR_CALLOC(uint16_t, npts);
  1049. ppts = pts;
  1050. float* pnewpts = newpts;
  1051. int j = 0;
  1052. if (mesh->dim == 3) {
  1053. for (int i = 0; i < npts; i++, ppts += 3) {
  1054. if (markers[i]) {
  1055. *pnewpts++ = ppts[0];
  1056. *pnewpts++ = ppts[1];
  1057. *pnewpts++ = ppts[2];
  1058. mapping[i] = j++;
  1059. }
  1060. }
  1061. } else {
  1062. for (int i = 0; i < npts; i++, ppts += 2) {
  1063. if (markers[i]) {
  1064. *pnewpts++ = ppts[0];
  1065. *pnewpts++ = ppts[1];
  1066. mapping[i] = j++;
  1067. }
  1068. }
  1069. }
  1070. free(pts);
  1071. free(markers);
  1072. pts = newpts;
  1073. npts = newnpts;
  1074. for (int i = 0; i < ntris * 3; i++) {
  1075. tris[i] = mapping[tris[i]];
  1076. }
  1077. for (int i = 0; i < nconntris * 3; i++) {
  1078. conntris[i] = mapping[conntris[i]];
  1079. }
  1080. free(mapping);
  1081. }
  1082. // Append all extrusion triangles to the main triangle array.
  1083. // We need them to be last so that they form a contiguous sequence.
  1084. pconntris = conntris;
  1085. for (int i = 0; i < nconntris; i++) {
  1086. *ptris++ = *pconntris++;
  1087. *ptris++ = *pconntris++;
  1088. *ptris++ = *pconntris++;
  1089. ntris++;
  1090. }
  1091. free(conntris);
  1092. // Final cleanup and return.
  1093. assert(npts <= maxpts);
  1094. assert(ntris <= maxtris);
  1095. mesh->npoints = npts;
  1096. mesh->points = pts;
  1097. mesh->ntriangles = ntris;
  1098. mesh->triangles = tris;
  1099. mesh->nconntriangles = nconntris;
  1100. return mlist;
  1101. }
  1102. typedef struct {
  1103. uint16_t outera;
  1104. uint16_t outerb;
  1105. uint16_t innera;
  1106. uint16_t innerb;
  1107. char i;
  1108. char j;
  1109. par_msquares__mesh* mesh;
  1110. int mesh_index;
  1111. } par_connector;
  1112. static par_connector* par_conn_find(par_connector* conns, int nconns,
  1113. char i, char j)
  1114. {
  1115. for (int c = 0; c < nconns; c++) {
  1116. if (conns[c].i == i && conns[c].j == j) {
  1117. return conns + c;
  1118. }
  1119. }
  1120. return 0;
  1121. }
  1122. static int par_msquares_cmp(const void *a, const void *b)
  1123. {
  1124. uint32_t arg1 = *((uint32_t const*) a);
  1125. uint32_t arg2 = *((uint32_t const*) b);
  1126. if (arg1 < arg2) return -1;
  1127. if (arg1 > arg2) return 1;
  1128. return 0;
  1129. }
  1130. typedef int (*par_msquares_code_fn)(int, int, int, int, void*);
  1131. static int par_msquares_multi_code(int sw, int se, int ne, int nw)
  1132. {
  1133. int code[4];
  1134. int ncols = 0;
  1135. code[0] = ncols++;
  1136. if (se == sw) {
  1137. code[1] = code[0];
  1138. } else {
  1139. code[1] = ncols++;
  1140. }
  1141. if (ne == se) {
  1142. code[2] = code[1];
  1143. } else if (ne == sw) {
  1144. code[2] = code[0];
  1145. } else {
  1146. code[2] = ncols++;
  1147. }
  1148. if (nw == ne) {
  1149. code[3] = code[2];
  1150. } else if (nw == se) {
  1151. code[3] = code[1];
  1152. } else if (nw == sw) {
  1153. code[3] = code[0];
  1154. } else {
  1155. code[3] = ncols++;
  1156. }
  1157. return code[0] | (code[1] << 2) | (code[2] << 4) | (code[3] << 6);
  1158. }
  1159. static uint32_t par_msquares_argb(par_byte const* pdata, int bpp)
  1160. {
  1161. uint32_t color = 0;
  1162. if (bpp == 4) {
  1163. color |= pdata[2];
  1164. color |= pdata[1] << 8;
  1165. color |= pdata[0] << 16;
  1166. color |= pdata[3] << 24;
  1167. return color;
  1168. }
  1169. for (int j = 0; j < bpp; j++) {
  1170. color <<= 8;
  1171. color |= pdata[j];
  1172. }
  1173. return color;
  1174. }
  1175. // Merge connective triangles into the primary triangle list.
  1176. static void par_msquares__finalize(par_msquares_meshlist* mlist)
  1177. {
  1178. if (mlist->nmeshes < 2 || mlist->meshes[1]->nconntriangles == 0) {
  1179. return;
  1180. }
  1181. for (int m = 1; m < mlist->nmeshes; m++) {
  1182. par_msquares__mesh* mesh = mlist->meshes[m];
  1183. int ntris = mesh->ntriangles + mesh->nconntriangles;
  1184. uint16_t* triangles = PAR_CALLOC(uint16_t, ntris * 3);
  1185. uint16_t* dst = triangles;
  1186. uint16_t const* src = mesh->triangles;
  1187. for (int t = 0; t < mesh->ntriangles; t++) {
  1188. *dst++ = *src++;
  1189. *dst++ = *src++;
  1190. *dst++ = *src++;
  1191. }
  1192. src = mesh->conntri;
  1193. for (int t = 0; t < mesh->nconntriangles; t++) {
  1194. *dst++ = *src++;
  1195. *dst++ = *src++;
  1196. *dst++ = *src++;
  1197. }
  1198. free(mesh->triangles);
  1199. free(mesh->conntri);
  1200. mesh->triangles = triangles;
  1201. mesh->ntriangles = ntris;
  1202. mesh->conntri = 0;
  1203. mesh->nconntriangles = 0;
  1204. }
  1205. }
  1206. static par__uint16list* par__uint16list_create()
  1207. {
  1208. par__uint16list* list = PAR_CALLOC(par__uint16list, 1);
  1209. list->count = 0;
  1210. list->capacity = 32;
  1211. list->values = PAR_CALLOC(uint16_t, list->capacity);
  1212. return list;
  1213. }
  1214. static void par__uint16list_add3(par__uint16list* list,
  1215. uint16_t a, uint16_t b, uint16_t c)
  1216. {
  1217. if (list->count + 3 > list->capacity) {
  1218. list->capacity *= 2;
  1219. list->values = PAR_REALLOC(uint16_t, list->values, list->capacity);
  1220. }
  1221. list->values[list->count++] = a;
  1222. list->values[list->count++] = b;
  1223. list->values[list->count++] = c;
  1224. }
  1225. static void par__uint16list_free(par__uint16list* list)
  1226. {
  1227. if (list) {
  1228. PAR_FREE(list->values);
  1229. PAR_FREE(list);
  1230. }
  1231. }
  1232. static void par_msquares__repair_tjunctions(par_msquares_meshlist* mlist)
  1233. {
  1234. for (int m = 0; m < mlist->nmeshes; m++) {
  1235. par_msquares__mesh* mesh = mlist->meshes[m];
  1236. par__uint16list* tjunctions = mesh->tjunctions;
  1237. int njunctions = (int) tjunctions->count / 3;
  1238. if (njunctions == 0) {
  1239. continue;
  1240. }
  1241. int ntriangles = mesh->ntriangles + njunctions;
  1242. mesh->triangles = PAR_REALLOC(uint16_t, mesh->triangles,
  1243. ntriangles * 3);
  1244. uint16_t const* jun = tjunctions->values;
  1245. uint16_t* new_triangles = mesh->triangles + mesh->ntriangles * 3;
  1246. int ncreated = 0;
  1247. for (int j = 0; j < njunctions; j++, jun += 3) {
  1248. uint16_t* tri = mesh->triangles;
  1249. int t;
  1250. for (t = 0; t < mesh->ntriangles; t++, tri += 3) {
  1251. int i = -1;
  1252. if (tri[0] == jun[0] && tri[1] == jun[1]) {
  1253. i = 0;
  1254. } else if (tri[1] == jun[0] && tri[2] == jun[1]) {
  1255. i = 1;
  1256. } else if (tri[2] == jun[0] && tri[0] == jun[1]) {
  1257. i = 2;
  1258. } else {
  1259. continue;
  1260. }
  1261. new_triangles[0] = tri[(i + 0) % 3];
  1262. new_triangles[1] = jun[2];
  1263. new_triangles[2] = tri[(i + 2) % 3];
  1264. tri[(i + 0) % 3] = jun[2];
  1265. new_triangles += 3;
  1266. ncreated++;
  1267. break;
  1268. }
  1269. // TODO: Need to investigate the "msquares_multi_diagram.obj" test.
  1270. assert(t != mesh->ntriangles &&
  1271. "Error with T-Junction repair; please disable the CLEAN flag.");
  1272. }
  1273. mesh->ntriangles += ncreated;
  1274. }
  1275. }
  1276. par_msquares_meshlist* par_msquares_color_multi(par_byte const* data, int width,
  1277. int height, int cellsize, int bpp, int flags)
  1278. {
  1279. if (!par_msquares_binary_point_table) {
  1280. par_init_tables();
  1281. }
  1282. const int ncols = width / cellsize;
  1283. const int nrows = height / cellsize;
  1284. const int maxrow = (height - 1) * width;
  1285. const int ncells = ncols * nrows;
  1286. const int dim = (flags & PAR_MSQUARES_HEIGHTS) ? 3 : 2;
  1287. const int west_to_east[9] = { 2, -1, -1, -1, -1, -1, 4, 3, -1 };
  1288. const int north_to_south[9] = { -1, -1, -1, -1, 2, 1, 0, -1, -1 };
  1289. assert(!(flags & PAR_MSQUARES_HEIGHTS) || bpp == 4);
  1290. assert(bpp > 0 && bpp <= 4 && "Bytes per pixel must be 1, 2, 3, or 4.");
  1291. assert(!(flags & PAR_MSQUARES_CLEAN) || !(flags & PAR_MSQUARES_SIMPLIFY));
  1292. assert(!(flags & PAR_MSQUARES_SNAP) &&
  1293. "SNAP is not supported with color_multi");
  1294. assert(!(flags & PAR_MSQUARES_INVERT) &&
  1295. "INVERT is not supported with color_multi");
  1296. assert(!(flags & PAR_MSQUARES_DUAL) &&
  1297. "DUAL is not supported with color_multi");
  1298. // Find all unique colors and ensure there are no more than 256 colors.
  1299. uint32_t colors[256];
  1300. int ncolors = 0;
  1301. par_byte const* pdata = data;
  1302. for (int i = 0; i < width * height; i++, pdata += bpp) {
  1303. uint32_t color = par_msquares_argb(pdata, bpp);
  1304. if (0 == bsearch(&color, colors, ncolors, 4, par_msquares_cmp)) {
  1305. assert(ncolors < 256);
  1306. colors[ncolors++] = color;
  1307. qsort(colors, ncolors, sizeof(uint32_t), par_msquares_cmp);
  1308. }
  1309. }
  1310. // Convert the color image to grayscale using the mapping table.
  1311. par_byte* pixels = PAR_CALLOC(par_byte, width * height);
  1312. pdata = data;
  1313. for (int i = 0; i < width * height; i++, pdata += bpp) {
  1314. uint32_t color = par_msquares_argb(pdata, bpp);
  1315. void* result = bsearch(&color, colors, ncolors, 4, par_msquares_cmp);
  1316. pixels[i] = (uint32_t*) result - &colors[0];
  1317. }
  1318. // Allocate 1 mesh for each color.
  1319. par_msquares_meshlist* mlist = PAR_CALLOC(par_msquares_meshlist, 1);
  1320. mlist->nmeshes = ncolors;
  1321. mlist->meshes = PAR_CALLOC(par_msquares__mesh*, ncolors);
  1322. par_msquares__mesh* mesh;
  1323. int maxtris_per_cell = 6;
  1324. int maxpts_per_cell = 9;
  1325. if (flags & PAR_MSQUARES_CONNECT) {
  1326. maxpts_per_cell += 6;
  1327. }
  1328. for (int i = 0; i < ncolors; i++) {
  1329. mesh = mlist->meshes[i] = PAR_CALLOC(par_msquares__mesh, 1);
  1330. mesh->color = colors[i];
  1331. mesh->points = PAR_CALLOC(float, ncells * maxpts_per_cell * dim);
  1332. mesh->triangles = PAR_CALLOC(uint16_t, ncells * maxtris_per_cell * 3);
  1333. mesh->dim = dim;
  1334. mesh->tjunctions = par__uint16list_create();
  1335. if (flags & PAR_MSQUARES_CONNECT) {
  1336. mesh->conntri = PAR_CALLOC(uint16_t, ncells * 8 * 3);
  1337. }
  1338. }
  1339. // The "verts" x/y/z arrays are the 4 corners and 4 midpoints around the
  1340. // square, in counter-clockwise order, starting at the lower-left. The
  1341. // ninth vert is the center point.
  1342. float vertsx[9], vertsy[9];
  1343. float normalization = 1.0f / PAR_MAX(width, height);
  1344. float normalized_cellsize = cellsize * normalization;
  1345. uint8_t cella[256];
  1346. uint8_t cellb[256];
  1347. uint8_t* currcell = cella;
  1348. uint8_t* prevcell = cellb;
  1349. uint16_t inds0[256 * 9];
  1350. uint16_t inds1[256 * 9];
  1351. uint16_t* currinds = inds0;
  1352. uint16_t* previnds = inds1;
  1353. uint16_t* rowindsa = PAR_CALLOC(uint16_t, ncols * 3 * 256);
  1354. uint8_t* rowcellsa = PAR_CALLOC(uint8_t, ncols * 256);
  1355. uint16_t* rowindsb = PAR_CALLOC(uint16_t, ncols * 3 * 256);
  1356. uint8_t* rowcellsb = PAR_CALLOC(uint8_t, ncols * 256);
  1357. uint16_t* prevrowinds = rowindsa;
  1358. uint16_t* currrowinds = rowindsb;
  1359. uint8_t* prevrowcells = rowcellsa;
  1360. uint8_t* currrowcells = rowcellsb;
  1361. uint32_t* simplification_words = 0;
  1362. if (flags & PAR_MSQUARES_SIMPLIFY) {
  1363. simplification_words = PAR_CALLOC(uint32_t, 2 * nrows * ncols);
  1364. }
  1365. // Do the march!
  1366. for (int row = 0; row < nrows; row++) {
  1367. vertsx[0] = vertsx[6] = vertsx[7] = 0;
  1368. vertsx[1] = vertsx[5] = vertsx[8] = 0.5 * normalized_cellsize;
  1369. vertsx[2] = vertsx[3] = vertsx[4] = normalized_cellsize;
  1370. vertsy[0] = vertsy[1] = vertsy[2] = normalized_cellsize * (row + 1);
  1371. vertsy[4] = vertsy[5] = vertsy[6] = normalized_cellsize * row;
  1372. vertsy[3] = vertsy[7] = vertsy[8] = normalized_cellsize * (row + 0.5);
  1373. int northi = row * cellsize * width;
  1374. int southi = PAR_MIN(northi + cellsize * width, maxrow);
  1375. int nwval = pixels[northi];
  1376. int swval = pixels[southi];
  1377. memset(currrowcells, 0, ncols * 256);
  1378. for (int col = 0; col < ncols; col++) {
  1379. northi += cellsize;
  1380. southi += cellsize;
  1381. if (col == ncols - 1) {
  1382. northi--;
  1383. southi--;
  1384. }
  1385. // Obtain 8-bit code and grab the four corresponding triangle lists.
  1386. int neval = pixels[northi];
  1387. int seval = pixels[southi];
  1388. int code = par_msquares_multi_code(swval, seval, neval, nwval) >> 2;
  1389. int const* trispecs[4] = {
  1390. par_msquares_quaternary_triangle_table[code][0],
  1391. par_msquares_quaternary_triangle_table[code][1],
  1392. par_msquares_quaternary_triangle_table[code][2],
  1393. par_msquares_quaternary_triangle_table[code][3]
  1394. };
  1395. int ntris[4] = {
  1396. *trispecs[0]++,
  1397. *trispecs[1]++,
  1398. *trispecs[2]++,
  1399. *trispecs[3]++
  1400. };
  1401. int const* edgespecs[4] = {
  1402. par_msquares_quaternary_boundary_table[code][0],
  1403. par_msquares_quaternary_boundary_table[code][1],
  1404. par_msquares_quaternary_boundary_table[code][2],
  1405. par_msquares_quaternary_boundary_table[code][3]
  1406. };
  1407. int nedges[4] = {
  1408. *edgespecs[0]++,
  1409. *edgespecs[1]++,
  1410. *edgespecs[2]++,
  1411. *edgespecs[3]++
  1412. };
  1413. int vals[4] = { swval, seval, neval, nwval };
  1414. // Gather topology information.
  1415. par_connector edges[16];
  1416. int ncedges = 0;
  1417. for (int c = 0; c < 4; c++) {
  1418. int color = vals[c];
  1419. par_msquares__mesh* mesh = mlist->meshes[color];
  1420. par_connector edge;
  1421. for (int e = 0; e < nedges[c]; e++) {
  1422. char previndex = edgespecs[c][e * 2];
  1423. char currindex = edgespecs[c][e * 2 + 1];
  1424. edge.i = previndex;
  1425. edge.j = currindex;
  1426. edge.mesh_index = color;
  1427. edge.mesh = mesh;
  1428. edges[ncedges++] = edge;
  1429. }
  1430. }
  1431. assert(ncedges < 16);
  1432. // Push triangles and points into the four affected meshes.
  1433. for (int m = 0; m < ncolors; m++) {
  1434. currcell[m] = 0;
  1435. }
  1436. uint32_t colors = 0;
  1437. uint32_t counts = 0;
  1438. uint16_t* conntris_start[4];
  1439. for (int c = 0; c < 4; c++) {
  1440. int color = vals[c];
  1441. colors |= color << (8 * c);
  1442. counts |= ntris[c] << (8 * c);
  1443. par_msquares__mesh* mesh = mlist->meshes[color];
  1444. float height = (mesh->color >> 24) / 255.0;
  1445. conntris_start[c] = mesh->conntri + mesh->nconntriangles * 3;
  1446. int usedpts[9] = {0};
  1447. uint16_t* pcurrinds = currinds + 9 * color;
  1448. uint16_t const* pprevinds = previnds + 9 * color;
  1449. uint16_t const* pprevrowinds =
  1450. prevrowinds + ncols * 3 * color + col * 3;
  1451. uint8_t prevrowcell = prevrowcells[color * ncols + col];
  1452. float* pdst = mesh->points + mesh->npoints * mesh->dim;
  1453. int previndex, prevflag;
  1454. for (int t = 0; t < ntris[c] * 3; t++) {
  1455. uint16_t index = trispecs[c][t];
  1456. if (usedpts[index]) {
  1457. continue;
  1458. }
  1459. usedpts[index] = 1;
  1460. if (index < 8) {
  1461. currcell[color] |= 1 << index;
  1462. }
  1463. // Vertical welding.
  1464. previndex = north_to_south[index];
  1465. prevflag = (previndex > -1) ? (1 << previndex) : 0;
  1466. if (row > 0 && (prevrowcell & prevflag)) {
  1467. pcurrinds[index] = pprevrowinds[previndex];
  1468. continue;
  1469. }
  1470. // Horizontal welding.
  1471. previndex = west_to_east[index];
  1472. prevflag = (previndex > -1) ? (1 << previndex) : 0;
  1473. if (col > 0 && (prevcell[color] & prevflag)) {
  1474. pcurrinds[index] = pprevinds[previndex];
  1475. continue;
  1476. }
  1477. // Insert brand new point.
  1478. float* vertex = pdst;
  1479. *pdst++ = vertsx[index];
  1480. *pdst++ = 1 - vertsy[index];
  1481. if (mesh->dim == 3) {
  1482. *pdst++ = height;
  1483. }
  1484. pcurrinds[index] = mesh->npoints++;
  1485. // If this is a midpoint, nudge it to the intersection.
  1486. if (index == 1) {
  1487. int begin = southi - cellsize;
  1488. for (int i = 1; i < cellsize + 1; i++) {
  1489. int val = pixels[begin + i];
  1490. if (val != pixels[begin]) {
  1491. vertex[0] = vertsx[0] + normalized_cellsize *
  1492. (float) i / cellsize;
  1493. break;
  1494. }
  1495. }
  1496. } else if (index == 3) {
  1497. int begin = northi;
  1498. for (int i = 1; i < cellsize + 1; i++) {
  1499. int val = pixels[begin + i * width];
  1500. if (val != pixels[begin]) {
  1501. vertex[1] = (1 - vertsy[4]) -
  1502. normalized_cellsize * (float) i / cellsize;
  1503. break;
  1504. }
  1505. }
  1506. }
  1507. }
  1508. // Look for T junctions and note them for later repairs.
  1509. uint8_t prc = prevrowcell;
  1510. if (usedpts[4] && !usedpts[5] && usedpts[6] && (prc & 2)) {
  1511. // Above cell had a middle vert, current cell straddles it.
  1512. par__uint16list_add3(mesh->tjunctions,
  1513. pcurrinds[4], pcurrinds[6], pprevrowinds[1]);
  1514. } else if ((prc & 1) && !(prc & 2) && (prc & 4) && usedpts[5]) {
  1515. // Current cell has a middle vert, above cell straddles it.
  1516. par__uint16list_add3(mesh->tjunctions,
  1517. pprevrowinds[0], pprevrowinds[2], pcurrinds[5]);
  1518. }
  1519. uint8_t pcc = col > 0 ? prevcell[color] : 0;
  1520. if (usedpts[0] && !usedpts[7] && usedpts[6] && (pcc & 8)) {
  1521. // Left cell had a middle vert, current cell straddles it.
  1522. par__uint16list_add3(mesh->tjunctions,
  1523. pcurrinds[6], pcurrinds[0], pprevinds[3]);
  1524. }
  1525. if ((pcc & 4) && !(pcc & 8) && (pcc & 16) && usedpts[7]) {
  1526. // Current cell has a middle vert, left cell straddles it.
  1527. par__uint16list_add3(mesh->tjunctions,
  1528. pprevinds[2], pprevinds[4], pcurrinds[7]);
  1529. }
  1530. // Stamp out the cell's triangle indices for this color.
  1531. uint16_t* tdst = mesh->triangles + mesh->ntriangles * 3;
  1532. mesh->ntriangles += ntris[c];
  1533. for (int t = 0; t < ntris[c] * 3; t++) {
  1534. uint16_t index = trispecs[c][t];
  1535. *tdst++ = pcurrinds[index];
  1536. }
  1537. // Add extrusion points and connective triangles if requested.
  1538. if (!(flags & PAR_MSQUARES_CONNECT)) {
  1539. continue;
  1540. }
  1541. for (int e = 0; e < nedges[c]; e++) {
  1542. int previndex = edgespecs[c][e * 2];
  1543. int currindex = edgespecs[c][e * 2 + 1];
  1544. par_connector* thisedge = par_conn_find(edges,
  1545. ncedges, previndex, currindex);
  1546. thisedge->innera = pcurrinds[previndex];
  1547. thisedge->innerb = pcurrinds[currindex];
  1548. thisedge->outera = mesh->npoints;
  1549. thisedge->outerb = mesh->npoints + 1;
  1550. par_connector* oppedge = par_conn_find(edges,
  1551. ncedges, currindex, previndex);
  1552. if (oppedge->mesh_index > color) continue;
  1553. *pdst++ = vertsx[previndex];
  1554. *pdst++ = 1 - vertsy[previndex];
  1555. if (mesh->dim == 3) {
  1556. *pdst++ = height;
  1557. }
  1558. mesh->npoints++;
  1559. *pdst++ = vertsx[currindex];
  1560. *pdst++ = 1 - vertsy[currindex];
  1561. if (mesh->dim == 3) {
  1562. *pdst++ = height;
  1563. }
  1564. mesh->npoints++;
  1565. uint16_t i0 = mesh->npoints - 1;
  1566. uint16_t i1 = mesh->npoints - 2;
  1567. uint16_t i2 = pcurrinds[previndex];
  1568. uint16_t i3 = pcurrinds[currindex];
  1569. uint16_t* ptr = mesh->conntri +
  1570. mesh->nconntriangles * 3;
  1571. *ptr++ = i2; *ptr++ = i1; *ptr++ = i0;
  1572. *ptr++ = i0; *ptr++ = i3; *ptr++ = i2;
  1573. mesh->nconntriangles += 2;
  1574. }
  1575. }
  1576. // Adjust the positions of the extrusion verts.
  1577. if (flags & PAR_MSQUARES_CONNECT) {
  1578. for (int c = 0; c < 4; c++) {
  1579. int color = vals[c];
  1580. uint16_t* pconninds = conntris_start[c];
  1581. par_msquares__mesh* mesh = mlist->meshes[color];
  1582. for (int e = 0; e < nedges[c]; e++) {
  1583. int previndex = edgespecs[c][e * 2];
  1584. int currindex = edgespecs[c][e * 2 + 1];
  1585. uint16_t i1 = pconninds[1];
  1586. uint16_t i0 = pconninds[2];
  1587. par_connector const* oppedge = par_conn_find(edges,
  1588. ncedges, currindex, previndex);
  1589. if (oppedge->mesh_index > color) continue;
  1590. int d = mesh->dim;
  1591. float* dst = mesh->points;
  1592. float const* src = oppedge->mesh->points;
  1593. dst[i0 * d + 0] = src[oppedge->innera * d + 0];
  1594. dst[i0 * d + 1] = src[oppedge->innera * d + 1];
  1595. dst[i1 * d + 0] = src[oppedge->innerb * d + 0];
  1596. dst[i1 * d + 1] = src[oppedge->innerb * d + 1];
  1597. if (d == 3) {
  1598. dst[i0 * d + 2] = src[oppedge->innera * d + 2];
  1599. dst[i1 * d + 2] = src[oppedge->innerb * d + 2];
  1600. }
  1601. pconninds += 6;
  1602. }
  1603. }
  1604. }
  1605. // Stash the bottom indices for each mesh in this cell to enable
  1606. // vertical as-you-go welding.
  1607. uint8_t* pcurrrowcells = currrowcells;
  1608. uint16_t* pcurrrowinds = currrowinds;
  1609. uint16_t const* pcurrinds = currinds;
  1610. for (int color = 0; color < ncolors; color++) {
  1611. pcurrrowcells[col] = currcell[color];
  1612. pcurrrowcells += ncols;
  1613. pcurrrowinds[col * 3 + 0] = pcurrinds[0];
  1614. pcurrrowinds[col * 3 + 1] = pcurrinds[1];
  1615. pcurrrowinds[col * 3 + 2] = pcurrinds[2];
  1616. pcurrrowinds += ncols * 3;
  1617. pcurrinds += 9;
  1618. }
  1619. // Stash some information later used by simplification.
  1620. if (flags & PAR_MSQUARES_SIMPLIFY) {
  1621. int cell = col + row * ncols;
  1622. simplification_words[cell * 2] = colors;
  1623. simplification_words[cell * 2 + 1] = counts;
  1624. }
  1625. // Advance the cursor.
  1626. nwval = neval;
  1627. swval = seval;
  1628. for (int i = 0; i < 9; i++) {
  1629. vertsx[i] += normalized_cellsize;
  1630. }
  1631. PAR_SWAP(uint8_t*, prevcell, currcell);
  1632. PAR_SWAP(uint16_t*, previnds, currinds);
  1633. }
  1634. PAR_SWAP(uint8_t*, prevrowcells, currrowcells);
  1635. PAR_SWAP(uint16_t*, prevrowinds, currrowinds);
  1636. }
  1637. free(prevrowinds);
  1638. free(prevrowcells);
  1639. free(pixels);
  1640. if (flags & PAR_MSQUARES_CLEAN) {
  1641. par_msquares__repair_tjunctions(mlist);
  1642. }
  1643. for (int m = 0; m < mlist->nmeshes; m++) {
  1644. par_msquares__mesh* mesh = mlist->meshes[m];
  1645. par__uint16list_free(mesh->tjunctions);
  1646. }
  1647. if (!(flags & PAR_MSQUARES_SIMPLIFY)) {
  1648. par_msquares__finalize(mlist);
  1649. return mlist;
  1650. }
  1651. uint8_t* simplification_blocks = PAR_CALLOC(uint8_t, nrows * ncols);
  1652. uint32_t* simplification_tris = PAR_CALLOC(uint32_t, nrows * ncols);
  1653. uint8_t* simplification_ntris = PAR_CALLOC(uint8_t, nrows * ncols);
  1654. // Perform quick-n-dirty simplification by iterating two rows at a time.
  1655. // In no way does this create the simplest possible mesh, but at least it's
  1656. // fast and easy.
  1657. for (uint32_t color = 0; color < (uint32_t) ncolors; color++) {
  1658. par_msquares__mesh* mesh = mlist->meshes[color];
  1659. // Populate the per-mesh info grids.
  1660. int ntris = 0;
  1661. for (int row = 0; row < nrows; row++) {
  1662. for (int col = 0; col < ncols; col++) {
  1663. int cell = ncols * row + col;
  1664. uint32_t colors = simplification_words[cell * 2];
  1665. uint32_t counts = simplification_words[cell * 2 + 1];
  1666. int ncelltris = 0;
  1667. int ncorners = 0;
  1668. if ((colors & 0xff) == color) {
  1669. ncelltris = counts & 0xff;
  1670. ncorners++;
  1671. }
  1672. if (((colors >> 8) & 0xff) == color) {
  1673. ncelltris += (counts >> 8) & 0xff;
  1674. ncorners++;
  1675. }
  1676. if (((colors >> 16) & 0xff) == color) {
  1677. ncelltris += (counts >> 16) & 0xff;
  1678. ncorners++;
  1679. }
  1680. if (((colors >> 24) & 0xff) == color) {
  1681. ncelltris += (counts >> 24) & 0xff;
  1682. ncorners++;
  1683. }
  1684. simplification_ntris[cell] = ncelltris;
  1685. simplification_tris[cell] = ntris;
  1686. simplification_blocks[cell] = ncorners == 4;
  1687. ntris += ncelltris;
  1688. }
  1689. }
  1690. // First figure out how many triangles we can eliminate.
  1691. int in_run = 0, start_run;
  1692. int neliminated_triangles = 0;
  1693. for (int row = 0; row < nrows - 1; row += 2) {
  1694. for (int col = 0; col < ncols; col++) {
  1695. int cell = ncols * row + col;
  1696. int a = simplification_blocks[cell];
  1697. int b = simplification_blocks[cell + ncols];
  1698. if (a && b) {
  1699. if (!in_run) {
  1700. in_run = 1;
  1701. start_run = col;
  1702. }
  1703. continue;
  1704. }
  1705. if (in_run) {
  1706. in_run = 0;
  1707. int run_width = col - start_run;
  1708. neliminated_triangles += run_width * 4 - 2;
  1709. }
  1710. }
  1711. if (in_run) {
  1712. in_run = 0;
  1713. int run_width = ncols - start_run;
  1714. neliminated_triangles += run_width * 4 - 2;
  1715. }
  1716. }
  1717. if (neliminated_triangles == 0) {
  1718. continue;
  1719. }
  1720. // Build a new index array cell-by-cell. If any given cell is 'F' and
  1721. // its neighbor to the south is also 'F', then it's part of a run.
  1722. int nnewtris = mesh->ntriangles - neliminated_triangles;
  1723. uint16_t* newtris = PAR_CALLOC(uint16_t, nnewtris * 3);
  1724. uint16_t* pnewtris = newtris;
  1725. in_run = 0;
  1726. uint16_t* tris = mesh->triangles;
  1727. for (int row = 0; row < nrows - 1; row += 2) {
  1728. for (int col = 0; col < ncols; col++) {
  1729. int cell = ncols * row + col;
  1730. int south = cell + ncols;
  1731. int a = simplification_blocks[cell];
  1732. int b = simplification_blocks[south];
  1733. if (a && b) {
  1734. if (!in_run) {
  1735. in_run = 1;
  1736. start_run = col;
  1737. }
  1738. continue;
  1739. }
  1740. if (in_run) {
  1741. in_run = 0;
  1742. int nw_cell = ncols * row + start_run;
  1743. int ne_cell = ncols * row + col - 1;
  1744. int sw_cell = nw_cell + ncols;
  1745. int se_cell = ne_cell + ncols;
  1746. int nw_tri = simplification_tris[nw_cell];
  1747. int ne_tri = simplification_tris[ne_cell];
  1748. int sw_tri = simplification_tris[sw_cell];
  1749. int se_tri = simplification_tris[se_cell];
  1750. int nw_corner = nw_tri * 3 + 5;
  1751. int ne_corner = ne_tri * 3 + 2;
  1752. int sw_corner = sw_tri * 3 + 0;
  1753. int se_corner = se_tri * 3 + 1;
  1754. *pnewtris++ = tris[nw_corner];
  1755. *pnewtris++ = tris[sw_corner];
  1756. *pnewtris++ = tris[se_corner];
  1757. *pnewtris++ = tris[se_corner];
  1758. *pnewtris++ = tris[ne_corner];
  1759. *pnewtris++ = tris[nw_corner];
  1760. }
  1761. int ncelltris = simplification_ntris[cell];
  1762. int celltri = simplification_tris[cell];
  1763. for (int t = 0; t < ncelltris; t++, celltri++) {
  1764. *pnewtris++ = tris[celltri * 3];
  1765. *pnewtris++ = tris[celltri * 3 + 1];
  1766. *pnewtris++ = tris[celltri * 3 + 2];
  1767. }
  1768. ncelltris = simplification_ntris[south];
  1769. celltri = simplification_tris[south];
  1770. for (int t = 0; t < ncelltris; t++, celltri++) {
  1771. *pnewtris++ = tris[celltri * 3];
  1772. *pnewtris++ = tris[celltri * 3 + 1];
  1773. *pnewtris++ = tris[celltri * 3 + 2];
  1774. }
  1775. }
  1776. if (in_run) {
  1777. in_run = 0;
  1778. int nw_cell = ncols * row + start_run;
  1779. int ne_cell = ncols * row + ncols - 1;
  1780. int sw_cell = nw_cell + ncols;
  1781. int se_cell = ne_cell + ncols;
  1782. int nw_tri = simplification_tris[nw_cell];
  1783. int ne_tri = simplification_tris[ne_cell];
  1784. int sw_tri = simplification_tris[sw_cell];
  1785. int se_tri = simplification_tris[se_cell];
  1786. int nw_corner = nw_tri * 3 + 5;
  1787. int ne_corner = ne_tri * 3 + 2;
  1788. int sw_corner = sw_tri * 3 + 0;
  1789. int se_corner = se_tri * 3 + 1;
  1790. *pnewtris++ = tris[nw_corner];
  1791. *pnewtris++ = tris[sw_corner];
  1792. *pnewtris++ = tris[se_corner];
  1793. *pnewtris++ = tris[se_corner];
  1794. *pnewtris++ = tris[ne_corner];
  1795. *pnewtris++ = tris[nw_corner];
  1796. }
  1797. }
  1798. mesh->ntriangles -= neliminated_triangles;
  1799. free(mesh->triangles);
  1800. mesh->triangles = newtris;
  1801. }
  1802. free(simplification_blocks);
  1803. free(simplification_ntris);
  1804. free(simplification_tris);
  1805. free(simplification_words);
  1806. par_msquares__finalize(mlist);
  1807. for (int i = 0; i < mlist->nmeshes; i++) {
  1808. par_remove_unreferenced_verts(mlist->meshes[i]);
  1809. }
  1810. return mlist;
  1811. }
  1812. void par_msquares_free_boundary(par_msquares_boundary* polygon)
  1813. {
  1814. free(polygon->points);
  1815. free(polygon->chains);
  1816. free(polygon->lengths);
  1817. free(polygon);
  1818. }
  1819. typedef struct par__hedge_s {
  1820. uint32_t key;
  1821. struct par__hvert_s* endvert;
  1822. struct par__hedge_s* opposite;
  1823. struct par__hedge_s* next;
  1824. struct par__hedge_s* prev;
  1825. } par__hedge;
  1826. typedef struct par__hvert_s {
  1827. par__hedge* incoming;
  1828. } par__hvert;
  1829. typedef struct {
  1830. par_msquares_mesh const* mesh;
  1831. par__hvert* verts;
  1832. par__hedge* edges;
  1833. par__hedge** sorted_edges;
  1834. } par__hemesh;
  1835. static int par__hedge_cmp(const void *arg0, const void *arg1)
  1836. {
  1837. par__hedge* he0 = *((par__hedge**) arg0);
  1838. par__hedge* he1 = *((par__hedge**) arg1);
  1839. if (he0->key < he1->key) return -1;
  1840. if (he0->key > he1->key) return 1;
  1841. return 0;
  1842. }
  1843. static par__hedge* par__hedge_find(par__hemesh* hemesh, uint32_t key)
  1844. {
  1845. par__hedge target = {0};
  1846. target.key = key;
  1847. par__hedge* ptarget = &target;
  1848. int nedges = hemesh->mesh->ntriangles * 3;
  1849. par__hedge** result = (par__hedge**) bsearch(&ptarget, hemesh->sorted_edges,
  1850. nedges, sizeof(par__hedge*), par__hedge_cmp);
  1851. return result ? *result : 0;
  1852. }
  1853. static uint32_t par__hedge_key(par__hvert* a, par__hvert* b, par__hvert* s)
  1854. {
  1855. uint32_t ai = a - s;
  1856. uint32_t bi = b - s;
  1857. return (ai << 16) | bi;
  1858. }
  1859. par_msquares_boundary* par_msquares_extract_boundary(
  1860. par_msquares_mesh const* mesh)
  1861. {
  1862. par_msquares_boundary* result = PAR_CALLOC(par_msquares_boundary, 1);
  1863. par__hemesh hemesh = {0};
  1864. hemesh.mesh = mesh;
  1865. int nedges = mesh->ntriangles * 3;
  1866. // Populate all fields of verts and edges, except opposite.
  1867. hemesh.edges = PAR_CALLOC(par__hedge, nedges);
  1868. par__hvert* hverts = hemesh.verts = PAR_CALLOC(par__hvert, mesh->npoints);
  1869. par__hedge* edge = hemesh.edges;
  1870. uint16_t const* tri = mesh->triangles;
  1871. for (int n = 0; n < mesh->ntriangles; n++, edge += 3, tri += 3) {
  1872. edge[0].endvert = hverts + tri[1];
  1873. edge[1].endvert = hverts + tri[2];
  1874. edge[2].endvert = hverts + tri[0];
  1875. hverts[tri[1]].incoming = edge + 0;
  1876. hverts[tri[2]].incoming = edge + 1;
  1877. hverts[tri[0]].incoming = edge + 2;
  1878. edge[0].next = edge + 1;
  1879. edge[1].next = edge + 2;
  1880. edge[2].next = edge + 0;
  1881. edge[0].prev = edge + 2;
  1882. edge[1].prev = edge + 0;
  1883. edge[2].prev = edge + 1;
  1884. edge[0].key = par__hedge_key(edge[2].endvert, edge[0].endvert, hverts);
  1885. edge[1].key = par__hedge_key(edge[0].endvert, edge[1].endvert, hverts);
  1886. edge[2].key = par__hedge_key(edge[1].endvert, edge[2].endvert, hverts);
  1887. }
  1888. // Sort the edges according to their key.
  1889. hemesh.sorted_edges = PAR_CALLOC(par__hedge*, mesh->ntriangles * 3);
  1890. for (int n = 0; n < nedges; n++) {
  1891. hemesh.sorted_edges[n] = hemesh.edges + n;
  1892. }
  1893. qsort(hemesh.sorted_edges, nedges, sizeof(par__hedge*), par__hedge_cmp);
  1894. // Populate the "opposite" field in each edge.
  1895. for (int n = 0; n < nedges; n++) {
  1896. par__hedge* edge = hemesh.edges + n;
  1897. par__hedge* prev = edge->prev;
  1898. par__hvert* start = edge->endvert;
  1899. par__hvert* end = prev->endvert;
  1900. uint32_t key = par__hedge_key(start, end, hverts);
  1901. edge->opposite = par__hedge_find(&hemesh, key);
  1902. }
  1903. // Re-use the sorted_edges array, filling it with boundary edges only.
  1904. // Also create a mapping table to consolidate all boundary verts.
  1905. int nborders = 0;
  1906. for (int n = 0; n < nedges; n++) {
  1907. par__hedge* edge = hemesh.edges + n;
  1908. if (!edge->opposite) {
  1909. hemesh.sorted_edges[nborders++] = edge;
  1910. }
  1911. }
  1912. // Allocate for the worst case (all separate triangles).
  1913. // We'll adjust the lengths later.
  1914. result->nchains = nborders / 3;
  1915. result->npoints = nborders + result->nchains;
  1916. result->points = PAR_CALLOC(float, 2 * result->npoints);
  1917. result->chains = PAR_CALLOC(float*, result->nchains);
  1918. result->lengths = PAR_CALLOC(uint16_t, result->nchains);
  1919. // Iterate over each polyline.
  1920. edge = hemesh.sorted_edges[0];
  1921. int pt = 0;
  1922. int nwritten = 0;
  1923. int nchains = 0;
  1924. while (1) {
  1925. float* points = result->points;
  1926. par__hedge* orig = edge;
  1927. uint16_t index = edge->prev->endvert - hverts;
  1928. result->chains[nchains] = points + pt;
  1929. result->lengths[nchains]++;
  1930. points[pt++] = mesh->points[index * mesh->dim];
  1931. points[pt++] = mesh->points[index * mesh->dim + 1];
  1932. while (1) {
  1933. index = edge->endvert - hverts;
  1934. edge->key = 0;
  1935. nwritten++;
  1936. result->lengths[nchains]++;
  1937. points[pt++] = mesh->points[index * mesh->dim];
  1938. points[pt++] = mesh->points[index * mesh->dim + 1];
  1939. par__hedge* next = edge->next;
  1940. while (next != edge) {
  1941. if (!next->opposite) {
  1942. break;
  1943. }
  1944. next = next->opposite->next;
  1945. }
  1946. edge = next;
  1947. if (edge == orig) {
  1948. break;
  1949. }
  1950. }
  1951. nchains++;
  1952. if (nwritten >= nborders) {
  1953. break;
  1954. }
  1955. for (int i = 0; i < nborders; i++) {
  1956. edge = hemesh.sorted_edges[i];
  1957. if (edge->key) {
  1958. break;
  1959. }
  1960. }
  1961. }
  1962. result->npoints = pt / 2;
  1963. result->nchains = nchains;
  1964. free(hemesh.verts);
  1965. free(hemesh.edges);
  1966. free(hemesh.sorted_edges);
  1967. return result;
  1968. }
  1969. #endif // PAR_MSQUARES_IMPLEMENTATION
  1970. #endif // PAR_MSQUARES_H