iron_obj.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. #include "iron_obj.h"
  2. #include "iron_array.h"
  3. #include "iron_gc.h"
  4. #include "iron_string.h"
  5. #include "iron_vec4.h"
  6. #include <math.h>
  7. #include <stdlib.h>
  8. #include <string.h>
  9. static raw_mesh_t *part = NULL;
  10. static f32_array_t pos_temp;
  11. static f32_array_t uv_temp;
  12. static f32_array_t nor_temp;
  13. static uint32_t va[512];
  14. static uint32_t ua[512];
  15. static uint32_t na[512];
  16. static int vi = 0;
  17. static int ui = 0;
  18. static int ni = 0;
  19. static uint8_t buf[128];
  20. static char str[256];
  21. static int vind_off = 0;
  22. static int tind_off = 0;
  23. static int nind_off = 0;
  24. static uint8_t *bytes = NULL;
  25. static size_t bytes_length = 0;
  26. static f32_array_t *pos_first;
  27. static f32_array_t *uv_first;
  28. static f32_array_t *nor_first;
  29. void console_info(char *s);
  30. static bool check_uvmap = true;
  31. static int read_int() {
  32. int bi = 0;
  33. while (part->pos < bytes_length) { // Read into buffer
  34. char c = bytes[part->pos];
  35. if (c == '/' || c == '\n' || c == '\r' || c == ' ' || c == '\t') {
  36. break;
  37. }
  38. buf[bi++] = c;
  39. part->pos++;
  40. }
  41. int res = 0; // Parse buffer into int
  42. int dec = 1;
  43. int off = buf[0] == '-' ? 1 : 0;
  44. int len = bi - 1;
  45. for (int i = 0; i < bi - off; ++i) {
  46. res += (buf[len - i] - 48) * dec;
  47. dec *= 10;
  48. }
  49. if (off > 0) {
  50. res *= -1;
  51. }
  52. return res;
  53. }
  54. static inline void skip_whitespace() {
  55. while (bytes[part->pos] == ' ' || bytes[part->pos] == '\t') {
  56. part->pos++;
  57. }
  58. }
  59. static void read_face_fast() {
  60. while (true) {
  61. va[vi++] = read_int() - 1;
  62. part->pos++; // '/'
  63. ua[ui++] = read_int() - 1;
  64. part->pos++; // '/'
  65. na[ni++] = read_int() - 1;
  66. skip_whitespace();
  67. if (bytes[part->pos] == '\n' || bytes[part->pos] == '\r' || part->pos >= bytes_length) {
  68. break;
  69. }
  70. }
  71. }
  72. static void read_face() {
  73. while (true) {
  74. va[vi++] = read_int() - 1;
  75. if (uv_temp.length > 0 || nor_temp.length > 0) {
  76. part->pos++; // "/"
  77. if (uv_temp.length > 0) {
  78. ua[ui++] = read_int() - 1;
  79. }
  80. if (nor_temp.length > 0) {
  81. // Some exporters put fake uv index even when uv data is not present... (f 1/1/1 instead of f 1//1)
  82. bool has_bogus_uv = uv_temp.length == 0 && bytes[part->pos] != '/';
  83. if (has_bogus_uv) {
  84. read_int();
  85. }
  86. part->pos++; // "/"
  87. na[ni++] = read_int() - 1;
  88. }
  89. }
  90. // Some exporters put "//" even when normal and uv data are not present (f 1//)
  91. else if (uv_temp.length == 0 && nor_temp.length == 0 && bytes[part->pos] == '/') {
  92. part->pos += 2;
  93. }
  94. skip_whitespace();
  95. if (bytes[part->pos] == '\n' || bytes[part->pos] == '\r' || part->pos >= bytes_length) {
  96. break;
  97. }
  98. }
  99. }
  100. static float read_float() {
  101. int bi = 0;
  102. while (true) { // Read into buffer
  103. char c = bytes[part->pos];
  104. if (c == ' ' || c == '\n' || c == '\r' || c == '\t') {
  105. break;
  106. }
  107. if (c == 'E' || c == 'e') {
  108. part->pos++;
  109. int first = buf[0] == '-' ? -(buf[1] - 48) : buf[0] - 48;
  110. int exp = read_int();
  111. int dec = 1;
  112. int loop = exp > 0 ? exp : -exp;
  113. for (int i = 0; i < loop; ++i) {
  114. dec *= 10;
  115. }
  116. return exp > 0 ? (float)first * dec : (float)first / dec;
  117. }
  118. buf[bi++] = c;
  119. part->pos++;
  120. }
  121. float res = 0.0; // Parse buffer into float
  122. int64_t dot = 1;
  123. int64_t dec = 1;
  124. int off = buf[0] == '-' ? 1 : 0;
  125. int len = bi - 1;
  126. for (int i = 0; i < bi - off; ++i) {
  127. char c = buf[len - i];
  128. if (c == '.') {
  129. dot = dec;
  130. continue;
  131. }
  132. res += (c - 48) * dec;
  133. dec *= 10;
  134. }
  135. if (off > 0) {
  136. res /= -dot;
  137. }
  138. else {
  139. res /= dot;
  140. }
  141. return res;
  142. }
  143. static char *read_string() {
  144. size_t begin = part->pos;
  145. while (true) {
  146. char c = bytes[part->pos];
  147. if (c == '\n' || c == '\r' || c == ' ' || c == '\t') {
  148. break;
  149. }
  150. part->pos++;
  151. }
  152. for (int i = 0; i < part->pos - begin; ++i) {
  153. str[i] = bytes[begin + i];
  154. }
  155. str[part->pos - begin] = '\0';
  156. return str;
  157. }
  158. static void next_line() {
  159. while (part->pos < bytes_length) {
  160. char c = bytes[part->pos++];
  161. if (c == '\n') {
  162. break; // \n, \r\n
  163. }
  164. }
  165. }
  166. static int get_tile(int i1, int i2, int i3, i32_array_t *uv_indices, int tiles_u) {
  167. float u1 = uv_temp.buffer[uv_indices->buffer[i1] * 2];
  168. float v1 = uv_temp.buffer[uv_indices->buffer[i1] * 2 + 1];
  169. float u2 = uv_temp.buffer[uv_indices->buffer[i2] * 2];
  170. float v2 = uv_temp.buffer[uv_indices->buffer[i2] * 2 + 1];
  171. float u3 = uv_temp.buffer[uv_indices->buffer[i3] * 2];
  172. float v3 = uv_temp.buffer[uv_indices->buffer[i3] * 2 + 1];
  173. int tile_u = (int)((u1 + u2 + u3) / 3);
  174. int tile_v = (int)((v1 + v2 + v3) / 3);
  175. return tile_u + tile_v * tiles_u;
  176. }
  177. static bool pnpoly(float v0x, float v0y, float v1x, float v1y, float v2x, float v2y, float px, float py) {
  178. // https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
  179. bool c = false;
  180. if (((v0y > py) != (v2y > py)) && (px < (v2x - v0x) * (py - v0y) / (v2y - v0y) + v0x)) {
  181. c = !c;
  182. }
  183. if (((v1y > py) != (v0y > py)) && (px < (v0x - v1x) * (py - v1y) / (v0y - v1y) + v1x)) {
  184. c = !c;
  185. }
  186. if (((v2y > py) != (v1y > py)) && (px < (v1x - v2x) * (py - v2y) / (v1y - v2y) + v2x)) {
  187. c = !c;
  188. }
  189. return c;
  190. }
  191. static iron_vector4_t calc_normal(iron_vector4_t a, iron_vector4_t b, iron_vector4_t c) {
  192. iron_vector4_t cb = vec4_sub(c, b);
  193. iron_vector4_t ab = vec4_sub(a, b);
  194. cb = vec4_cross(cb, ab);
  195. cb = vec4_norm(cb);
  196. return cb;
  197. }
  198. // 'o' for object split, 'g' for groups, 'u'semtl for materials
  199. raw_mesh_t *obj_parse(buffer_t *file_bytes, char split_code, uint64_t start_pos, bool udim) {
  200. bytes = file_bytes->buffer;
  201. bytes_length = file_bytes->length;
  202. part = gc_alloc(sizeof(raw_mesh_t));
  203. part->scale_pos = 1.0;
  204. part->scale_tex = 1.0;
  205. part->pos = start_pos;
  206. part->udims_u = 1;
  207. part->udims_v = 1;
  208. part->name = string_copy(str);
  209. i32_array_t pos_indices = {0};
  210. i32_array_t uv_indices = {0};
  211. i32_array_t nor_indices = {0};
  212. bool reading_faces = false;
  213. bool reading_object = false;
  214. bool full_attrib = false;
  215. check_uvmap = true;
  216. if (start_pos == 0) {
  217. vind_off = tind_off = nind_off = 0;
  218. }
  219. if (split_code == 'u' && start_pos > 0) {
  220. pos_temp = *pos_first;
  221. nor_temp = *nor_first;
  222. uv_temp = *uv_first;
  223. }
  224. else {
  225. memset(&pos_temp, 0, sizeof(pos_temp));
  226. memset(&uv_temp, 0, sizeof(uv_temp));
  227. memset(&nor_temp, 0, sizeof(nor_temp));
  228. }
  229. while (part->pos < bytes_length) {
  230. char c0 = bytes[part->pos++];
  231. if (reading_object && reading_faces && (c0 == 'v' || c0 == split_code)) {
  232. part->pos--;
  233. part->has_next = true;
  234. break;
  235. }
  236. if (c0 == 'v') {
  237. char c1 = bytes[part->pos++];
  238. if (c1 == ' ') {
  239. skip_whitespace(); // Some exporters put additional space directly after "v"
  240. f32_array_push(&pos_temp, read_float());
  241. skip_whitespace();
  242. f32_array_push(&pos_temp, read_float());
  243. skip_whitespace();
  244. f32_array_push(&pos_temp, read_float());
  245. }
  246. else if (c1 == 't') {
  247. skip_whitespace();
  248. f32_array_push(&uv_temp, read_float());
  249. skip_whitespace();
  250. f32_array_push(&uv_temp, read_float());
  251. if (nor_temp.length > 0) {
  252. full_attrib = true;
  253. }
  254. }
  255. else if (c1 == 'n') {
  256. skip_whitespace();
  257. f32_array_push(&nor_temp, read_float());
  258. skip_whitespace();
  259. f32_array_push(&nor_temp, read_float());
  260. skip_whitespace();
  261. f32_array_push(&nor_temp, read_float());
  262. if (uv_temp.length > 0) {
  263. full_attrib = true;
  264. }
  265. }
  266. }
  267. else if (c0 == 'f') {
  268. skip_whitespace();
  269. reading_faces = true;
  270. vi = ui = ni = 0;
  271. full_attrib ? read_face_fast() : read_face();
  272. if (vi <= 4) { // Convex, fan triangulation
  273. i32_array_push(&pos_indices, va[0]);
  274. i32_array_push(&pos_indices, va[1]);
  275. i32_array_push(&pos_indices, va[2]);
  276. for (int i = 3; i < vi; ++i) {
  277. i32_array_push(&pos_indices, va[0]);
  278. i32_array_push(&pos_indices, va[i - 1]);
  279. i32_array_push(&pos_indices, va[i]);
  280. }
  281. if (uv_temp.length > 0) {
  282. i32_array_push(&uv_indices, ua[0]);
  283. i32_array_push(&uv_indices, ua[1]);
  284. i32_array_push(&uv_indices, ua[2]);
  285. for (int i = 3; i < ui; ++i) {
  286. i32_array_push(&uv_indices, ua[0]);
  287. i32_array_push(&uv_indices, ua[i - 1]);
  288. i32_array_push(&uv_indices, ua[i]);
  289. }
  290. if (check_uvmap && ua[0] == 0 && ua[1] == 0 && ua[2] == 0) { // Blender points faces with no UV to 0.0 (vt index 0)
  291. check_uvmap = false;
  292. console_info("Warning: Mesh is not fully UV unwrapped");
  293. }
  294. }
  295. if (nor_temp.length > 0) {
  296. i32_array_push(&nor_indices, na[0]);
  297. i32_array_push(&nor_indices, na[1]);
  298. i32_array_push(&nor_indices, na[2]);
  299. for (int i = 3; i < ni; ++i) {
  300. i32_array_push(&nor_indices, na[0]);
  301. i32_array_push(&nor_indices, na[i - 1]);
  302. i32_array_push(&nor_indices, na[i]);
  303. }
  304. }
  305. }
  306. else { // Convex or concave, ear clipping
  307. int _vind_off = split_code == 'u' ? 0 : vind_off;
  308. int _nind_off = split_code == 'u' ? 0 : nind_off;
  309. float nx = 0.0;
  310. float ny = 0.0;
  311. float nz = 0.0;
  312. if (nor_temp.length > 0) {
  313. nx = nor_temp.buffer[(na[0] - _nind_off) * 3];
  314. ny = nor_temp.buffer[(na[0] - _nind_off) * 3 + 1];
  315. nz = nor_temp.buffer[(na[0] - _nind_off) * 3 + 2];
  316. }
  317. else {
  318. iron_vector4_t n = calc_normal(vec4_create(pos_temp.buffer[(va[0] - _vind_off) * 3], pos_temp.buffer[(va[0] - _vind_off) * 3 + 1],
  319. pos_temp.buffer[(va[0] - _vind_off) * 3 + 2], 1.0f),
  320. vec4_create(pos_temp.buffer[(va[1] - _vind_off) * 3], pos_temp.buffer[(va[1] - _vind_off) * 3 + 1],
  321. pos_temp.buffer[(va[1] - _vind_off) * 3 + 2], 1.0f),
  322. vec4_create(pos_temp.buffer[(va[2] - _vind_off) * 3], pos_temp.buffer[(va[2] - _vind_off) * 3 + 1],
  323. pos_temp.buffer[(va[2] - _vind_off) * 3 + 2], 1.0f));
  324. nx = n.x;
  325. ny = n.y;
  326. nz = n.z;
  327. }
  328. float nxabs = (float)fabs(nx);
  329. float nyabs = (float)fabs(ny);
  330. float nzabs = (float)fabs(nz);
  331. bool flip = nx + ny + nz > 0;
  332. int axis = nxabs > nyabs && nxabs > nzabs ? 0 : nyabs > nxabs && nyabs > nzabs ? 1 : 2;
  333. int axis0 = axis == 0 ? (flip ? 2 : 1) : axis == 1 ? (flip ? 0 : 2) : (flip ? 1 : 0);
  334. int axis1 = axis == 0 ? (flip ? 1 : 2) : axis == 1 ? (flip ? 2 : 0) : (flip ? 0 : 1);
  335. int loops = 0;
  336. int i = -1;
  337. while (vi > 3 && loops++ < vi) {
  338. i = (i + 1) % vi;
  339. int i1 = (i + 1) % vi;
  340. int i2 = (i + 2) % vi;
  341. int vi0 = (va[i] - _vind_off) * 3;
  342. int vi1 = (va[i1] - _vind_off) * 3;
  343. int vi2 = (va[i2] - _vind_off) * 3;
  344. float v0x = pos_temp.buffer[vi0 + axis0];
  345. float v0y = pos_temp.buffer[vi0 + axis1];
  346. float v1x = pos_temp.buffer[vi1 + axis0];
  347. float v1y = pos_temp.buffer[vi1 + axis1];
  348. float v2x = pos_temp.buffer[vi2 + axis0];
  349. float v2y = pos_temp.buffer[vi2 + axis1];
  350. float e0x = v0x - v1x; // Not an interior vertex
  351. float e0y = v0y - v1y;
  352. float e1x = v2x - v1x;
  353. float e1y = v2y - v1y;
  354. float cross = e0x * e1y - e0y * e1x;
  355. if (cross <= 0) {
  356. continue;
  357. }
  358. bool overlap = false; // Other vertex found inside this triangle
  359. for (int j = 0; j < vi - 3; ++j) {
  360. int j0 = (va[(i + 3 + j) % vi] - _vind_off) * 3;
  361. float px = pos_temp.buffer[j0 + axis0];
  362. float py = pos_temp.buffer[j0 + axis1];
  363. if (pnpoly(v0x, v0y, v1x, v1y, v2x, v2y, px, py)) {
  364. overlap = true;
  365. break;
  366. }
  367. }
  368. if (overlap) {
  369. continue;
  370. }
  371. i32_array_push(&pos_indices, va[i]); // Found ear
  372. i32_array_push(&pos_indices, va[i1]);
  373. i32_array_push(&pos_indices, va[i2]);
  374. if (uv_temp.length > 0) {
  375. i32_array_push(&uv_indices, ua[i]);
  376. i32_array_push(&uv_indices, ua[i1]);
  377. i32_array_push(&uv_indices, ua[i2]);
  378. }
  379. if (nor_temp.length > 0) {
  380. i32_array_push(&nor_indices, na[i]);
  381. i32_array_push(&nor_indices, na[i1]);
  382. i32_array_push(&nor_indices, na[i2]);
  383. }
  384. for (int j = ((i + 1) % vi); j < vi - 1; ++j) { // Consume vertex
  385. va[j] = va[j + 1];
  386. ua[j] = ua[j + 1];
  387. na[j] = na[j + 1];
  388. }
  389. vi--;
  390. i--;
  391. loops = 0;
  392. }
  393. i32_array_push(&pos_indices, va[0]); // Last one
  394. i32_array_push(&pos_indices, va[1]);
  395. i32_array_push(&pos_indices, va[2]);
  396. if (uv_temp.length > 0) {
  397. i32_array_push(&uv_indices, ua[0]);
  398. i32_array_push(&uv_indices, ua[1]);
  399. i32_array_push(&uv_indices, ua[2]);
  400. }
  401. if (nor_temp.length > 0) {
  402. i32_array_push(&nor_indices, na[0]);
  403. i32_array_push(&nor_indices, na[1]);
  404. i32_array_push(&nor_indices, na[2]);
  405. }
  406. }
  407. }
  408. else if (c0 == split_code) {
  409. if (split_code == 'u') {
  410. part->pos += 5; // "u"semtl
  411. }
  412. skip_whitespace();
  413. if (!udim) {
  414. reading_object = true;
  415. }
  416. part->name = string_copy(read_string());
  417. }
  418. else if (c0 == '\n') { // Empty line
  419. continue;
  420. }
  421. next_line();
  422. }
  423. if (start_pos > 0) {
  424. if (split_code != 'u') {
  425. for (int i = 0; i < pos_indices.length; ++i) {
  426. pos_indices.buffer[i] -= vind_off;
  427. }
  428. for (int i = 0; i < uv_indices.length; ++i) {
  429. uv_indices.buffer[i] -= tind_off;
  430. }
  431. for (int i = 0; i < nor_indices.length; ++i) {
  432. nor_indices.buffer[i] -= nind_off;
  433. }
  434. }
  435. }
  436. else {
  437. if (split_code == 'u') {
  438. pos_first = &pos_temp;
  439. nor_first = &nor_temp;
  440. uv_first = &uv_temp;
  441. }
  442. }
  443. vind_off += (int)(pos_temp.length / 3); // Assumes separate vertex data per object
  444. tind_off += (int)(uv_temp.length / 2);
  445. nind_off += (int)(nor_temp.length / 3);
  446. // Pack positions to (-1, 1) range
  447. part->scale_pos = 0.0;
  448. for (int i = 0; i < pos_temp.length; ++i) {
  449. float f = (float)fabs(pos_temp.buffer[i]);
  450. if (part->scale_pos < f) {
  451. part->scale_pos = f;
  452. }
  453. }
  454. float inv = 32767 * (1 / part->scale_pos);
  455. part->posa = calloc(sizeof(i16_array_t), 1);
  456. part->posa->length = part->posa->capacity = pos_indices.length * 4;
  457. part->posa->buffer = malloc(part->posa->capacity * sizeof(int16_t));
  458. part->inda = calloc(sizeof(u32_array_t), 1);
  459. part->inda->length = part->inda->capacity = pos_indices.length;
  460. part->inda->buffer = malloc(part->inda->capacity * sizeof(uint32_t));
  461. part->vertex_count = pos_indices.length;
  462. part->index_count = pos_indices.length;
  463. int inda_length = pos_indices.length;
  464. for (int i = 0; i < pos_indices.length; ++i) {
  465. part->posa->buffer[i * 4] = (int)(pos_temp.buffer[pos_indices.buffer[i] * 3] * inv);
  466. part->posa->buffer[i * 4 + 1] = (int)(-pos_temp.buffer[pos_indices.buffer[i] * 3 + 2] * inv);
  467. part->posa->buffer[i * 4 + 2] = (int)(pos_temp.buffer[pos_indices.buffer[i] * 3 + 1] * inv);
  468. part->inda->buffer[i] = i;
  469. }
  470. if (nor_indices.length > 0) {
  471. part->nora = calloc(sizeof(i16_array_t), 1);
  472. part->nora->length = part->nora->capacity = nor_indices.length * 2;
  473. part->nora->buffer = malloc(part->nora->capacity * sizeof(int16_t));
  474. for (int i = 0; i < pos_indices.length; ++i) {
  475. part->nora->buffer[i * 2] = (int)(nor_temp.buffer[nor_indices.buffer[i] * 3] * 32767);
  476. part->nora->buffer[i * 2 + 1] = (int)(-nor_temp.buffer[nor_indices.buffer[i] * 3 + 2] * 32767);
  477. part->posa->buffer[i * 4 + 3] = (int)(nor_temp.buffer[nor_indices.buffer[i] * 3 + 1] * 32767);
  478. }
  479. }
  480. else {
  481. // Calc normals
  482. part->nora = calloc(sizeof(i16_array_t), 1);
  483. part->nora->length = part->nora->capacity = inda_length * 2;
  484. part->nora->buffer = malloc(part->nora->capacity * sizeof(int16_t));
  485. for (int i = 0; i < (int)(inda_length / 3); ++i) {
  486. int i1 = part->inda->buffer[i * 3];
  487. int i2 = part->inda->buffer[i * 3 + 1];
  488. int i3 = part->inda->buffer[i * 3 + 2];
  489. iron_vector4_t n = calc_normal(vec4_create(part->posa->buffer[i1 * 4], part->posa->buffer[i1 * 4 + 1], part->posa->buffer[i1 * 4 + 2], 1.0),
  490. vec4_create(part->posa->buffer[i2 * 4], part->posa->buffer[i2 * 4 + 1], part->posa->buffer[i2 * 4 + 2], 1.0),
  491. vec4_create(part->posa->buffer[i3 * 4], part->posa->buffer[i3 * 4 + 1], part->posa->buffer[i3 * 4 + 2], 1.0));
  492. part->nora->buffer[i1 * 2] = (int)(n.x * 32767);
  493. part->nora->buffer[i1 * 2 + 1] = (int)(n.y * 32767);
  494. part->posa->buffer[i1 * 4 + 3] = (int)(n.z * 32767);
  495. part->nora->buffer[i2 * 2] = (int)(n.x * 32767);
  496. part->nora->buffer[i2 * 2 + 1] = (int)(n.y * 32767);
  497. part->posa->buffer[i2 * 4 + 3] = (int)(n.z * 32767);
  498. part->nora->buffer[i3 * 2] = (int)(n.x * 32767);
  499. part->nora->buffer[i3 * 2 + 1] = (int)(n.y * 32767);
  500. part->posa->buffer[i3 * 4 + 3] = (int)(n.z * 32767);
  501. }
  502. }
  503. if (uv_indices.length > 0) {
  504. if (udim) {
  505. // Find number of tiles
  506. int tiles_u = 1;
  507. int tiles_v = 1;
  508. for (int i = 0; i < (int)(uv_temp.length / 2); ++i) {
  509. while (uv_temp.buffer[i * 2] > tiles_u)
  510. tiles_u++;
  511. while (uv_temp.buffer[i * 2 + 1] > tiles_v)
  512. tiles_v++;
  513. }
  514. // Amount of indices pre tile
  515. uint32_t *num = (uint32_t *)malloc(tiles_u * tiles_v * sizeof(uint32_t));
  516. memset(num, 0, tiles_u * tiles_v * sizeof(uint32_t));
  517. for (int i = 0; i < (int)(inda_length / 3); ++i) {
  518. int tile = get_tile(part->inda->buffer[i * 3], part->inda->buffer[i * 3 + 1], part->inda->buffer[i * 3 + 2], &uv_indices, tiles_u);
  519. num[tile] += 3;
  520. }
  521. // Split indices per tile
  522. part->udims = any_array_create(tiles_u * tiles_v);
  523. part->udims_u = tiles_u;
  524. part->udims_v = tiles_v;
  525. for (int i = 0; i < tiles_u * tiles_v; ++i) {
  526. part->udims->buffer[i] = u32_array_create(num[i]);
  527. num[i] = 0;
  528. }
  529. for (int i = 0; i < (int)(inda_length / 3); ++i) {
  530. int i1 = part->inda->buffer[i * 3];
  531. int i2 = part->inda->buffer[i * 3 + 1];
  532. int i3 = part->inda->buffer[i * 3 + 2];
  533. int tile = get_tile(i1, i2, i3, &uv_indices, tiles_u);
  534. u32_array_t *a = part->udims->buffer[tile];
  535. a->buffer[num[tile]++] = i1;
  536. a->buffer[num[tile]++] = i2;
  537. a->buffer[num[tile]++] = i3;
  538. }
  539. // Normalize uvs to 0-1 range
  540. int16_t *uvtiles = (int16_t *)malloc(uv_temp.length * sizeof(int16_t));
  541. for (int i = 0; i < (int)(inda_length / 3); ++i) { // TODO: merge loops
  542. int i1 = part->inda->buffer[i * 3];
  543. int i2 = part->inda->buffer[i * 3 + 1];
  544. int i3 = part->inda->buffer[i * 3 + 2];
  545. int tile = get_tile(i1, i2, i3, &uv_indices, tiles_u);
  546. int tile_u = tile % tiles_u;
  547. int tile_v = (int)(tile / tiles_u);
  548. uvtiles[uv_indices.buffer[i1] * 2] = tile_u;
  549. uvtiles[uv_indices.buffer[i1] * 2 + 1] = tile_v;
  550. uvtiles[uv_indices.buffer[i2] * 2] = tile_u;
  551. uvtiles[uv_indices.buffer[i2] * 2 + 1] = tile_v;
  552. uvtiles[uv_indices.buffer[i3] * 2] = tile_u;
  553. uvtiles[uv_indices.buffer[i3] * 2 + 1] = tile_v;
  554. }
  555. for (int i = 0; i < uv_temp.length; ++i) {
  556. uv_temp.buffer[i] -= uvtiles[i];
  557. }
  558. free(uvtiles);
  559. free(num);
  560. }
  561. part->texa = calloc(sizeof(i16_array_t), 1);
  562. part->texa->length = part->texa->capacity = uv_indices.length * 2;
  563. part->texa->buffer = malloc(part->texa->capacity * sizeof(int16_t));
  564. for (int i = 0; i < uv_indices.length; ++i) {
  565. float uvx = uv_temp.buffer[uv_indices.buffer[i] * 2];
  566. if (uvx > 1.0) {
  567. uvx = uvx - (int)(uvx);
  568. }
  569. float uvy = uv_temp.buffer[uv_indices.buffer[i] * 2 + 1];
  570. if (uvy > 1.0) {
  571. uvy = uvy - (int)(uvy);
  572. }
  573. part->texa->buffer[i * 2] = (int)(uvx * 32767);
  574. part->texa->buffer[i * 2 + 1] = (int)((1.0 - uvy) * 32767);
  575. }
  576. }
  577. bytes = NULL;
  578. if (!part->has_next) {
  579. pos_first = nor_first = uv_first = NULL;
  580. array_free(&pos_temp);
  581. array_free(&uv_temp);
  582. array_free(&nor_temp);
  583. }
  584. array_free(&pos_indices);
  585. array_free(&uv_indices);
  586. array_free(&nor_indices);
  587. return part;
  588. }
  589. void obj_destroy(raw_mesh_t *part) {
  590. // if (part->udims != NULL) {
  591. // for (int i = 0; i < part->udims_u * part->udims_v; ++i) {
  592. // free(part->udims[i]);
  593. // }
  594. // free(part->udims);
  595. // }
  596. free(part->posa);
  597. free(part->nora);
  598. free(part->texa);
  599. free(part->inda);
  600. gc_free(part);
  601. }