2
0

obj2c.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <float.h>
  4. #include <limits.h>
  5. #include <string.h>
  6. #define SV_IMPLEMENTATION
  7. #include "sv.h"
  8. #define ARENA_IMPLEMENTATION
  9. #include "arena.h"
  10. #define return_defer(value) do { result = (value); goto defer; } while (0)
  11. typedef int Errno;
  12. #define UNUSED(x) (void)(x)
  13. const char *shift(int *argc, char ***argv)
  14. {
  15. assert(*argc > 0);
  16. const char *result = *argv[0];
  17. *argc -= 1;
  18. *argv += 1;
  19. return result;
  20. }
  21. static Arena default_arena = {0};
  22. static Arena *context_arena = &default_arena;
  23. static void *context_alloc(size_t size)
  24. {
  25. assert(context_arena);
  26. return arena_alloc(context_arena, size);
  27. }
  28. static void *context_realloc(void *oldp, size_t oldsz, size_t newsz)
  29. {
  30. if (newsz <= oldsz) return oldp;
  31. return memcpy(context_alloc(newsz), oldp, oldsz);
  32. }
  33. Errno read_entire_file(const char *file_path, char **buffer, size_t *buffer_size)
  34. {
  35. Errno result = 0;
  36. FILE *f = NULL;
  37. f = fopen(file_path, "rb");
  38. if (f == NULL) return_defer(errno);
  39. if (fseek(f, 0, SEEK_END) < 0) return_defer(errno);
  40. long m = ftell(f);
  41. if (m < 0) return_defer(errno);
  42. if (fseek(f, 0, SEEK_SET) < 0) return_defer(errno);
  43. *buffer_size = m;
  44. *buffer = context_alloc(*buffer_size + 1);
  45. (*buffer)[*buffer_size] = '\0';
  46. fread(*buffer, *buffer_size, 1, f);
  47. if (ferror(f)) return_defer(errno);
  48. defer:
  49. if (f) fclose(f);
  50. return result;
  51. }
  52. typedef struct {
  53. float x, y;
  54. } Vector2;
  55. Vector2 make_vector2(float x, float y)
  56. {
  57. Vector2 v2;
  58. v2.x = x;
  59. v2.y = y;
  60. return v2;
  61. }
  62. typedef struct {
  63. float x, y, z;
  64. } Vector3;
  65. Vector3 make_vector3(float x, float y, float z)
  66. {
  67. Vector3 v3;
  68. v3.x = x;
  69. v3.y = y;
  70. v3.z = z;
  71. return v3;
  72. }
  73. typedef struct {
  74. Vector3 *items;
  75. size_t capacity;
  76. size_t count;
  77. } Vertices;
  78. typedef struct {
  79. int a, b, c;
  80. } Face;
  81. Face make_face(int a, int b, int c)
  82. {
  83. Face f = {
  84. .a = a,
  85. .b = b,
  86. .c = c,
  87. };
  88. return f;
  89. }
  90. typedef struct {
  91. Face *items;
  92. size_t capacity;
  93. size_t count;
  94. } Faces;
  95. #define DA_INIT_CAPACITY 8192
  96. #define DA_REALLOC context_realloc
  97. #define da_append(da, item) \
  98. do { \
  99. if ((da)->count >= (da)->capacity) { \
  100. size_t new_capacity = (da)->capacity*2; \
  101. if (new_capacity == 0) { \
  102. new_capacity = DA_INIT_CAPACITY; \
  103. } \
  104. \
  105. (da)->items = DA_REALLOC((da)->items, \
  106. (da)->capacity*sizeof((da)->items[0]), \
  107. new_capacity*sizeof((da)->items[0])); \
  108. (da)->capacity = new_capacity; \
  109. } \
  110. \
  111. (da)->items[(da)->count++] = (item); \
  112. } while (0)
  113. void generate_code(FILE *out, Vertices vertices, Faces faces)
  114. {
  115. fprintf(out, "#ifndef OBJ_H_\n");
  116. fprintf(out, "#define OBJ_H_\n");
  117. fprintf(out, "#define vertices_count %zu\n", vertices.count);
  118. fprintf(out, "static const float vertices[][3] = {\n");
  119. for (size_t i = 0; i < vertices.count; ++i) {
  120. Vector3 v = vertices.items[i];
  121. fprintf(out, " {%f, %f, %f},\n", v.x, v.y, v.z);
  122. }
  123. fprintf(out, "};\n");
  124. fprintf(out, "static const int faces[%zu][3] = {\n", faces.count);
  125. for (size_t i = 0; i < faces.count; ++i) {
  126. Face f = faces.items[i];
  127. fprintf(out, " {%d, %d, %d},\n", f.a, f.b, f.c);
  128. }
  129. fprintf(out, "};\n");
  130. fprintf(out, "#define faces_count %zu\n", faces.count);
  131. fprintf(out, "#endif // OBJ_H_\n");
  132. }
  133. Vector3 remap_object(Vector3 v, float scale, float lx, float hx, float ly, float hy, float lz, float hz)
  134. {
  135. float cx = lx + (hx - lx)/2;
  136. float cy = ly + (hy - ly)/2;
  137. float cz = lz + (hz - lz)/2;
  138. v.z = (v.z - cz)*scale;
  139. v.x = (v.x - cx)*scale;
  140. v.y = (v.y - cy)*scale;
  141. return v;
  142. }
  143. void usage(const char *program_name)
  144. {
  145. fprintf(stderr, "Usage: %s [OPTIONS] <INPUT.obj>\n", program_name);
  146. fprintf(stderr, "Options:\n");
  147. fprintf(stderr, " -o output file path\n");
  148. fprintf(stderr, " -s scale the model\n");
  149. }
  150. int main(int argc, char **argv)
  151. {
  152. int result = 0;
  153. assert(argc > 0);
  154. const char *program_name = shift(&argc, &argv);
  155. const char *output_file_path = NULL;
  156. const char *input_file_path = NULL;
  157. float scale = 0.75;
  158. // TODO: consider using https://github.com/tsoding/flag.h in here
  159. while (argc > 0) {
  160. const char *flag = shift(&argc, &argv);
  161. if (strcmp(flag, "-o") == 0) {
  162. if (argc <= 0) {
  163. usage(program_name);
  164. fprintf(stderr, "ERROR: no value is provided for flag %s\n", flag);
  165. return_defer(1);
  166. }
  167. if (output_file_path != NULL) {
  168. usage(program_name);
  169. fprintf(stderr, "ERROR: %s was already provided\n", flag);
  170. return_defer(1);
  171. }
  172. output_file_path = shift(&argc, &argv);
  173. } else if (strcmp(flag, "-s") == 0) {
  174. if (argc <= 0) {
  175. usage(program_name);
  176. fprintf(stderr, "ERROR: no value is provided for flag %s\n", flag);
  177. return_defer(1);
  178. }
  179. const char *value = shift(&argc, &argv);
  180. scale = strtof(value, NULL);
  181. } else {
  182. if (input_file_path != NULL) {
  183. usage(program_name);
  184. fprintf(stderr, "ERROR: input file path was already provided\n");
  185. return_defer(1);
  186. }
  187. input_file_path = flag;
  188. }
  189. }
  190. if (input_file_path == NULL) {
  191. usage(program_name);
  192. fprintf(stderr, "ERROR: no input file path is provided\n");
  193. return_defer(1);
  194. }
  195. if (output_file_path == NULL) {
  196. usage(program_name);
  197. fprintf(stderr, "ERROR: no output file path is provided\n");
  198. return_defer(1);
  199. }
  200. char *buffer;
  201. size_t buffer_size;
  202. Errno err = read_entire_file(input_file_path, &buffer, &buffer_size);
  203. if (err != 0) {
  204. fprintf(stderr, "ERROR: could not read file %s: %s\n", input_file_path, strerror(errno));
  205. return_defer(1);
  206. }
  207. String_View content = sv_from_parts(buffer, buffer_size);
  208. Vertices vertices = {0};
  209. Faces faces = {0};
  210. float lx = FLT_MAX, hx = FLT_MIN;
  211. float ly = FLT_MAX, hy = FLT_MIN;
  212. float lz = FLT_MAX, hz = FLT_MIN;
  213. int lf = INT_MAX, hf = INT_MIN;
  214. for (size_t line_number = 0; content.count > 0; ++line_number) {
  215. String_View line = sv_trim_left(sv_chop_by_delim(&content, '\n'));
  216. if (line.count > 0 && *line.data != '#') {
  217. String_View kind = sv_chop_by_delim(&line, ' ');
  218. if (sv_eq(kind, SV("v"))) {
  219. char *endptr;
  220. line = sv_trim_left(line);
  221. float x = strtof(line.data, &endptr);
  222. line.data = endptr;
  223. if (lx > x) lx = x;
  224. if (hx < x) hx = x;
  225. line = sv_trim_left(line);
  226. float y = strtof(line.data, &endptr);
  227. line.data = endptr;
  228. if (ly > y) ly = y;
  229. if (hy < y) hy = y;
  230. line = sv_trim_left(line);
  231. float z = strtof(line.data, &endptr);
  232. line.data = endptr;
  233. if (lz > z) lz = z;
  234. if (hz < z) hz = z;
  235. da_append(&vertices, make_vector3(x, y, z));
  236. } else if (sv_eq(kind, SV("f"))) {
  237. char *endptr;
  238. line = sv_trim_left(line);
  239. int a = strtol(line.data, &endptr, 10);
  240. line.data = endptr;
  241. if (lf > a) lf = a;
  242. if (hf < a) hf = a;
  243. line = sv_trim_left(line);
  244. int b = strtol(line.data, &endptr, 10);
  245. line.data = endptr;
  246. if (lf > b) lf = b;
  247. if (hf < b) hf = b;
  248. line = sv_trim_left(line);
  249. int c = strtol(line.data, &endptr, 10);
  250. line.data = endptr;
  251. if (lf > c) lf = c;
  252. if (hf < c) hf = c;
  253. da_append(&faces, make_face(a, b, c));
  254. } else {
  255. fprintf(stderr, "%s:%zu: unknown kind of entry `"SV_Fmt"`\n", input_file_path, line_number, SV_Arg(kind));
  256. return_defer(1);
  257. }
  258. }
  259. }
  260. printf("Input: %s\n", input_file_path);
  261. printf("Output: %s\n", output_file_path);
  262. printf("Vertices: %zu (x: %f..%f, y: %f..%f, z: %f..%f)\n", vertices.count, lx, hx, ly, hy, lz, hz);
  263. printf("Faces: %zu (index: %d..%d)\n", faces.count, lf, hf);
  264. for (size_t i = 0; i < vertices.count; ++i) {
  265. vertices.items[i] = remap_object(vertices.items[i], scale, lx, hx, ly, hy, lz, hz);
  266. }
  267. for (size_t i = 0; i < faces.count; ++i) {
  268. faces.items[i].a -= 1;
  269. faces.items[i].b -= 1;
  270. faces.items[i].c -= 1;
  271. }
  272. FILE *out = fopen(output_file_path, "wb");
  273. if (out == NULL) {
  274. fprintf(stderr, "ERROR: Could not write file %s: %s\n", output_file_path, strerror(errno));
  275. return_defer(1);
  276. }
  277. generate_code(out, vertices, faces);
  278. defer:
  279. return result;
  280. }