obj2c.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. #include <assert.h>
  2. #include <stdio.h>
  3. #include <errno.h>
  4. #include <float.h>
  5. #include <limits.h>
  6. #include <string.h>
  7. #define NOB_IMPLEMENTATION
  8. #define NOB_STRIP_PREFIX
  9. #include "nob.h"
  10. typedef struct {
  11. float x, y;
  12. } Vector2;
  13. Vector2 make_vector2(float x, float y)
  14. {
  15. Vector2 v2;
  16. v2.x = x;
  17. v2.y = y;
  18. return v2;
  19. }
  20. typedef struct {
  21. float x, y, z;
  22. } Vector3;
  23. Vector3 make_vector3(float x, float y, float z)
  24. {
  25. Vector3 v3;
  26. v3.x = x;
  27. v3.y = y;
  28. v3.z = z;
  29. return v3;
  30. }
  31. typedef struct {
  32. int *items;
  33. size_t capacity;
  34. size_t count;
  35. } Face_Indices;
  36. typedef struct {
  37. int *items;
  38. size_t capacity;
  39. size_t count;
  40. } Vertex_Indices;
  41. typedef struct {
  42. Vector3 position;
  43. Face_Indices faces;
  44. int component; // 0 means never visited, >0 is the index of the component vertex belongs to
  45. } Vertex;
  46. Vertex make_vertex(float x, float y, float z)
  47. {
  48. return (Vertex) {
  49. .position = make_vector3(x, y, z),
  50. };
  51. }
  52. typedef struct {
  53. Vertex *items;
  54. size_t capacity;
  55. size_t count;
  56. } Vertices;
  57. #define VERTICES_PER_FACE 3
  58. typedef struct {
  59. int v[VERTICES_PER_FACE];
  60. int vt[VERTICES_PER_FACE];
  61. int vn[VERTICES_PER_FACE];
  62. } Face;
  63. Face make_face(int v1, int v2, int v3, int vt1, int vt2, int vt3, int vn1, int vn2, int vn3)
  64. {
  65. static_assert(VERTICES_PER_FACE == 3, "");
  66. Face f = {
  67. .v = {v1, v2, v3},
  68. .vt = {vt1, vt2, vt3},
  69. .vn = {vn1, vn2, vn3},
  70. };
  71. return f;
  72. }
  73. typedef struct {
  74. Face *items;
  75. size_t capacity;
  76. size_t count;
  77. } Faces;
  78. typedef struct {
  79. Vector3 *items;
  80. size_t capacity;
  81. size_t count;
  82. } Normals;
  83. typedef struct {
  84. Vector2 *items;
  85. size_t capacity;
  86. size_t count;
  87. } TexCoords;
  88. typedef struct {
  89. int *items;
  90. size_t count;
  91. size_t capacity;
  92. } Component_Indices;
  93. bool is_deleted_face(Vertices vertices, Face face, Component_Indices delete_components)
  94. {
  95. for (size_t i = 0; i < VERTICES_PER_FACE; ++i) {
  96. // TODO: @perf if this is too slow due to too many deleted components you can always just pre-sort the indices and do a binary search
  97. for (size_t j = 0; j < delete_components.count; ++j) {
  98. if (vertices.items[face.v[i]].component == delete_components.items[j]) {
  99. return true;
  100. }
  101. }
  102. }
  103. return false;
  104. }
  105. void generate_code(FILE *out, Vertices vertices, TexCoords texcoords, Normals normals, Faces faces, Component_Indices delete_components)
  106. {
  107. fprintf(out, "#ifndef OBJ_H_\n");
  108. fprintf(out, "#define OBJ_H_\n");
  109. fprintf(out, "#define vertices_count %zu\n", vertices.count);
  110. if (vertices.count == 0) {
  111. fprintf(out, "static const float vertices[1][3] = {0};\n");
  112. } else {
  113. fprintf(out, "static const float vertices[][3] = {\n");
  114. for (size_t i = 0; i < vertices.count; ++i) {
  115. Vector3 v = vertices.items[i].position;
  116. fprintf(out, " {%f, %f, %f},\n", v.x, v.y, v.z);
  117. }
  118. fprintf(out, "};\n");
  119. }
  120. fprintf(out, "#define texcoords_count %zu\n", texcoords.count);
  121. if (texcoords.count == 0) {
  122. fprintf(out, "static const float texcoords[1][3] = {0};\n");
  123. } else {
  124. fprintf(out, "static const float texcoords[][3] = {\n");
  125. for (size_t i = 0; i < texcoords.count; ++i) {
  126. Vector2 vt = texcoords.items[i];
  127. fprintf(out, " {%f, %f},\n", vt.x, vt.y);
  128. }
  129. fprintf(out, "};\n");
  130. }
  131. fprintf(out, "#define normals_count %zu\n", normals.count);
  132. if (normals.count == 0) {
  133. fprintf(out, "static const float normals[1][3] = {0};\n");
  134. } else {
  135. fprintf(out, "static const float normals[][3] = {\n");
  136. for (size_t i = 0; i < normals.count; ++i) {
  137. Vector3 vn = normals.items[i];
  138. fprintf(out, " {%f, %f, %f},\n", vn.x, vn.y, vn.z);
  139. }
  140. fprintf(out, "};\n");
  141. }
  142. size_t visible_faces_count = 0;
  143. for (size_t i = 0; i < faces.count; ++i) {
  144. if (!is_deleted_face(vertices, faces.items[i], delete_components)) {
  145. visible_faces_count += 1;
  146. }
  147. }
  148. fprintf(out, "#define faces_count %zu\n", visible_faces_count);
  149. if (visible_faces_count == 0) {
  150. fprintf(out, "static const int faces[1][9] = {0};\n");
  151. } else {
  152. fprintf(out, "static const int faces[%zu][9] = {\n", visible_faces_count);
  153. for (size_t i = 0; i < faces.count; ++i) {
  154. if (!is_deleted_face(vertices, faces.items[i], delete_components)) {
  155. Face f = faces.items[i];
  156. fprintf(out, " {%d, %d, %d, %d, %d, %d, %d, %d, %d},\n", f.v[0], f.v[1], f.v[2], f.vt[0], f.vt[1], f.vt[2], f.vn[0], f.vn[1], f.vn[2]);
  157. }
  158. }
  159. fprintf(out, "};\n");
  160. }
  161. fprintf(out, "#endif // OBJ_H_\n");
  162. }
  163. Vector3 remap_object(Vector3 v, float scale, float lx, float hx, float ly, float hy, float lz, float hz)
  164. {
  165. float cx = lx + (hx - lx)/2;
  166. float cy = ly + (hy - ly)/2;
  167. float cz = lz + (hz - lz)/2;
  168. v.z = (v.z - cz)*scale;
  169. v.x = (v.x - cx)*scale;
  170. v.y = (v.y - cy)*scale;
  171. return v;
  172. }
  173. void usage(const char *program_name)
  174. {
  175. fprintf(stderr, "Usage: %s [OPTIONS] <INPUT.obj>\n", program_name);
  176. fprintf(stderr, "Options:\n");
  177. fprintf(stderr, " -o output file path\n");
  178. fprintf(stderr, " -s scale the model\n");
  179. }
  180. void parse_face_triple(String_View *line, int *lf, int *hf, int *v, int *vt, int *vn)
  181. {
  182. char *endptr;
  183. *line = sv_trim_left(*line);
  184. *v = strtol(line->data, &endptr, 10) - 1; // NOTE: -1 is to account for 1-based indexing.
  185. if (*lf > *v) *lf = *v;
  186. if (*hf < *v) *hf = *v;
  187. sv_chop_left(line, endptr - line->data);
  188. *vt = 0;
  189. if (line->count > 0 && line->data[0] == '/') {
  190. sv_chop_left(line, 1);
  191. *vt = strtol(line->data, &endptr, 10) - 1; // NOTE: -1 is to account for 1-based indexing.
  192. sv_chop_left(line, endptr - line->data);
  193. }
  194. *vn = 0;
  195. if (line->count > 0 && line->data[0] == '/') {
  196. sv_chop_left(line, 1);
  197. *vn = strtol(line->data, &endptr, 10) - 1; // NOTE: -1 is to account for 1-based indexing.
  198. sv_chop_left(line, endptr - line->data);
  199. }
  200. while (line->count > 0 && !isspace(*line->data)) sv_chop_left(line, 1);
  201. }
  202. int unvisited_vertex(Vertices vertices)
  203. {
  204. for (size_t i = 0; i < vertices.count; ++i) {
  205. if (!vertices.items[i].component) {
  206. return (int)i;
  207. }
  208. }
  209. return -1;
  210. }
  211. int main(int argc, char **argv)
  212. {
  213. int result = 0;
  214. assert(argc > 0);
  215. const char *program_name = shift(argv, argc);
  216. const char *output_file_path = NULL;
  217. const char *input_file_path = NULL;
  218. float scale = 0.75;
  219. Component_Indices delete_components = {0};
  220. // TODO: consider using https://github.com/tsoding/flag.h in here
  221. while (argc > 0) {
  222. const char *flag = shift(argv, argc);
  223. if (strcmp(flag, "-o") == 0) {
  224. if (argc <= 0) {
  225. usage(program_name);
  226. fprintf(stderr, "ERROR: no value is provided for flag %s\n", flag);
  227. return_defer(1);
  228. }
  229. if (output_file_path != NULL) {
  230. usage(program_name);
  231. fprintf(stderr, "ERROR: %s was already provided\n", flag);
  232. return_defer(1);
  233. }
  234. output_file_path = shift(argv, argc);
  235. } else if (strcmp(flag, "-s") == 0) {
  236. if (argc <= 0) {
  237. usage(program_name);
  238. fprintf(stderr, "ERROR: no value is provided for flag %s\n", flag);
  239. return_defer(1);
  240. }
  241. const char *value = shift(argv, argc);
  242. scale = strtof(value, NULL);
  243. } else if (strcmp(flag, "-d") == 0) {
  244. if (argc <= 0) {
  245. usage(program_name);
  246. fprintf(stderr, "ERROR: no value is provided for flag %s\n", flag);
  247. return_defer(1);
  248. }
  249. const char *value = shift(argv, argc);
  250. da_append(&delete_components, atoi(value));
  251. } else {
  252. if (input_file_path != NULL) {
  253. usage(program_name);
  254. fprintf(stderr, "ERROR: input file path was already provided\n");
  255. return_defer(1);
  256. }
  257. input_file_path = flag;
  258. }
  259. }
  260. if (input_file_path == NULL) {
  261. usage(program_name);
  262. fprintf(stderr, "ERROR: no input file path is provided\n");
  263. return_defer(1);
  264. }
  265. if (output_file_path == NULL) {
  266. usage(program_name);
  267. fprintf(stderr, "ERROR: no output file path is provided\n");
  268. return_defer(1);
  269. }
  270. String_Builder buffer = {0};
  271. if (!read_entire_file(input_file_path, &buffer)) return_defer(1);
  272. String_View content = sb_to_sv(buffer);
  273. Vertices vertices = {0};
  274. TexCoords texcoords = {0};
  275. Normals normals = {0};
  276. Faces faces = {0};
  277. float lx = FLT_MAX, hx = FLT_MIN;
  278. float ly = FLT_MAX, hy = FLT_MIN;
  279. float lz = FLT_MAX, hz = FLT_MIN;
  280. int lf = INT_MAX, hf = INT_MIN;
  281. bool one_object_encountered = false;
  282. size_t one_object_line_number = 0;
  283. for (size_t line_number = 1; content.count > 0; ++line_number) {
  284. String_View line = sv_trim_left(sv_chop_by_delim(&content, '\n'));
  285. if (line.count > 0 && *line.data != '#') {
  286. String_View kind = sv_chop_by_delim(&line, ' ');
  287. if (sv_eq(kind, sv_from_cstr("v"))) {
  288. char *endptr;
  289. line = sv_trim_left(line);
  290. float x = strtof(line.data, &endptr);
  291. if (lx > x) lx = x;
  292. if (hx < x) hx = x;
  293. sv_chop_left(&line, endptr - line.data);
  294. line = sv_trim_left(line);
  295. float y = strtof(line.data, &endptr);
  296. if (ly > y) ly = y;
  297. if (hy < y) hy = y;
  298. sv_chop_left(&line, endptr - line.data);
  299. line = sv_trim_left(line);
  300. float z = strtof(line.data, &endptr);
  301. if (lz > z) lz = z;
  302. if (hz < z) hz = z;
  303. sv_chop_left(&line, endptr - line.data);
  304. da_append(&vertices, make_vertex(x, y, z));
  305. } else if (sv_eq(kind, sv_from_cstr("f"))) {
  306. // TODO: This code assumes that we already parsed all of the vertices.
  307. // Since we don't have any OBJ files in the assets that have faces before
  308. // vertices, it does not really matter that much. If we ever have any
  309. // of such OBJ files, it's easy to restructure this loop to support any
  310. // order of the elements.
  311. int v1, v2, v3, vt1, vt2, vt3, vn1, vn2, vn3;
  312. int face_index = faces.count;
  313. parse_face_triple(&line, &lf, &hf, &v1, &vt1, &vn1);
  314. da_append(&vertices.items[v1].faces, face_index);
  315. parse_face_triple(&line, &lf, &hf, &v2, &vt2, &vn2);
  316. da_append(&vertices.items[v2].faces, face_index);
  317. parse_face_triple(&line, &lf, &hf, &v3, &vt3, &vn3);
  318. da_append(&vertices.items[v3].faces, face_index);
  319. da_append(&faces, make_face(v1, v2, v3, vt1, vt2, vt3, vn1, vn2, vn3));
  320. } else if (sv_eq(kind, sv_from_cstr("mtllib"))) {
  321. fprintf(stderr, "%s:%zu: WARNING: mtllib is not supported yet. Ignoring it...\n", input_file_path, line_number);
  322. } else if (sv_eq(kind, sv_from_cstr("usemtl"))) {
  323. fprintf(stderr, "%s:%zu: WARNING: usemtl is not supported yet. Ignoring it...\n", input_file_path, line_number);
  324. } else if (sv_eq(kind, sv_from_cstr("o"))) {
  325. if (one_object_encountered) {
  326. fprintf(stderr, "%s:%zu: ERROR: %s supports only one object as of right now.\n", input_file_path, line_number, program_name);
  327. fprintf(stderr, "%s:%zu: NOTE: we already processing this object\n", input_file_path, one_object_line_number);
  328. return_defer(1);
  329. }
  330. line = sv_trim_left(line);
  331. String_View name = line;
  332. fprintf(stderr, "%s:%zu: INFO: processing object `"SV_Fmt"`\n", input_file_path, line_number, SV_Arg(name));
  333. one_object_encountered = true;
  334. one_object_line_number = line_number;
  335. } else if (sv_eq(kind, sv_from_cstr("s"))) {
  336. fprintf(stderr, "%s:%zu: WARNING: smooth groups are not supported right now. Ignoring them...\n", input_file_path, line_number);
  337. } else if (sv_eq(kind, sv_from_cstr("vn"))) {
  338. char *endptr;
  339. line = sv_trim_left(line);
  340. float x = strtof(line.data, &endptr);
  341. sv_chop_left(&line, endptr - line.data);
  342. line = sv_trim_left(line);
  343. float y = strtof(line.data, &endptr);
  344. sv_chop_left(&line, endptr - line.data);
  345. line = sv_trim_left(line);
  346. float z = strtof(line.data, &endptr);
  347. sv_chop_left(&line, endptr - line.data);
  348. da_append(&normals, make_vector3(x, y, z));
  349. } else if (sv_eq(kind, sv_from_cstr("vt"))) {
  350. char *endptr;
  351. line = sv_trim_left(line);
  352. float x = strtof(line.data, &endptr);
  353. sv_chop_left(&line, endptr - line.data);
  354. line = sv_trim_left(line);
  355. float y = strtof(line.data, &endptr);
  356. sv_chop_left(&line, endptr - line.data);
  357. da_append(&texcoords, make_vector2(x, y));
  358. } else {
  359. fprintf(stderr, "%s:%zu: ERROR: unknown kind of entry `"SV_Fmt"`\n", input_file_path, line_number, SV_Arg(kind));
  360. return_defer(1);
  361. }
  362. }
  363. }
  364. int min_faces = INT_MAX;
  365. int max_faces = INT_MIN;
  366. for (size_t i = 0; i < vertices.count; ++i) {
  367. int count = vertices.items[i].faces.count;
  368. if (min_faces > count) min_faces = count;
  369. if (max_faces < count) max_faces = count;
  370. }
  371. size_t comp_count = 0;
  372. int start = unvisited_vertex(vertices);
  373. while (start >= 0) {
  374. comp_count += 1;
  375. Vertex_Indices wave = {0};
  376. Vertex_Indices next_wave = {0};
  377. da_append(&wave, start);
  378. vertices.items[start].component = comp_count;
  379. while (wave.count > 0) {
  380. for (size_t i = 0; i < wave.count; ++i) {
  381. Vertex *vertex = &vertices.items[wave.items[i]];
  382. for (size_t j = 0; j < vertex->faces.count; ++j) {
  383. for (size_t k = 0; k < VERTICES_PER_FACE; ++k) {
  384. int neighbor_index = faces.items[vertex->faces.items[j]].v[k];
  385. if (!vertices.items[neighbor_index].component) {
  386. da_append(&next_wave, neighbor_index);
  387. vertices.items[neighbor_index].component = comp_count;
  388. }
  389. }
  390. }
  391. }
  392. wave.count = 0;
  393. Vertex_Indices temp = wave;
  394. wave = next_wave;
  395. next_wave = temp;
  396. }
  397. start = unvisited_vertex(vertices);
  398. }
  399. printf("Input: %s\n", input_file_path);
  400. printf("Output: %s\n", output_file_path);
  401. printf("Vertices: %zu (x: %f..%f, y: %f..%f, z: %f..%f)\n", vertices.count, lx, hx, ly, hy, lz, hz);
  402. printf("Normals: %zu\n", normals.count);
  403. printf("Texture Coordinates: %zu\n", texcoords.count);
  404. printf("Faces: %zu (index: %d..%d)\n", faces.count, lf, hf);
  405. printf("Faces per vertex: %d..%d\n", min_faces, max_faces);
  406. printf("Components Count: %zu\n", comp_count);
  407. printf("Deleted Components: ");
  408. for (size_t i = 0; i < delete_components.count; ++i) {
  409. printf("%d ", delete_components.items[i]);
  410. }
  411. printf("\n");
  412. for (size_t i = 0; i < vertices.count; ++i) {
  413. vertices.items[i].position = remap_object(vertices.items[i].position, scale, lx, hx, ly, hy, lz, hz);
  414. }
  415. FILE *out = fopen(output_file_path, "wb");
  416. if (out == NULL) {
  417. fprintf(stderr, "ERROR: Could not write file %s: %s\n", output_file_path, strerror(errno));
  418. return_defer(1);
  419. }
  420. generate_code(out, vertices, texcoords, normals, faces, delete_components);
  421. defer:
  422. return result;
  423. }