objparser.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. #ifndef _CRT_SECURE_NO_WARNINGS
  2. #define _CRT_SECURE_NO_WARNINGS
  3. #endif
  4. #include "objparser.h"
  5. #include <cassert>
  6. #include <cmath>
  7. #include <cstdio>
  8. #include <cstdlib>
  9. #include <cstring>
  10. template <typename T>
  11. static void growArray(T*& data, size_t& capacity)
  12. {
  13. size_t newcapacity = capacity == 0 ? 32 : capacity + capacity / 2;
  14. T* newdata = new T[newcapacity];
  15. if (data)
  16. {
  17. memcpy(newdata, data, capacity * sizeof(T));
  18. delete[] data;
  19. }
  20. data = newdata;
  21. capacity = newcapacity;
  22. }
  23. static int fixupIndex(int index, size_t size)
  24. {
  25. return (index >= 0) ? index - 1 : int(size) + index;
  26. }
  27. static int parseInt(const char* s, const char** end)
  28. {
  29. // skip whitespace
  30. while (*s == ' ' || *s == '\t')
  31. s++;
  32. // read sign bit
  33. int sign = (*s == '-');
  34. s += (*s == '-' || *s == '+');
  35. unsigned int result = 0;
  36. for (;;)
  37. {
  38. if (unsigned(*s - '0') < 10)
  39. result = result * 10 + (*s - '0');
  40. else
  41. break;
  42. s++;
  43. }
  44. // return end-of-string
  45. *end = s;
  46. return sign ? -int(result) : int(result);
  47. }
  48. static float parseFloat(const char* s, const char** end)
  49. {
  50. static const double digits[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
  51. static const double powers[] = {1e0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22};
  52. // skip whitespace
  53. while (*s == ' ' || *s == '\t')
  54. s++;
  55. // read sign
  56. double sign = (*s == '-') ? -1 : 1;
  57. s += (*s == '-' || *s == '+');
  58. // read integer part
  59. double result = 0;
  60. int power = 0;
  61. while (unsigned(*s - '0') < 10)
  62. {
  63. result = result * 10 + digits[*s - '0'];
  64. s++;
  65. }
  66. // read fractional part
  67. if (*s == '.')
  68. {
  69. s++;
  70. while (unsigned(*s - '0') < 10)
  71. {
  72. result = result * 10 + digits[*s - '0'];
  73. s++;
  74. power--;
  75. }
  76. }
  77. // read exponent part
  78. if ((*s | ' ') == 'e')
  79. {
  80. s++;
  81. // read exponent sign
  82. int expsign = (*s == '-') ? -1 : 1;
  83. s += (*s == '-' || *s == '+');
  84. // read exponent
  85. int exppower = 0;
  86. while (unsigned(*s - '0') < 10)
  87. {
  88. exppower = exppower * 10 + (*s - '0');
  89. s++;
  90. }
  91. // done!
  92. power += expsign * exppower;
  93. }
  94. // return end-of-string
  95. *end = s;
  96. // note: this is precise if result < 9e15
  97. // for longer inputs we lose a bit of precision here
  98. if (unsigned(-power) < sizeof(powers) / sizeof(powers[0]))
  99. return float(sign * result / powers[-power]);
  100. else if (unsigned(power) < sizeof(powers) / sizeof(powers[0]))
  101. return float(sign * result * powers[power]);
  102. else
  103. return float(sign * result * pow(10.0, power));
  104. }
  105. static const char* parseFace(const char* s, int& vi, int& vti, int& vni)
  106. {
  107. while (*s == ' ' || *s == '\t')
  108. s++;
  109. vi = parseInt(s, &s);
  110. if (*s != '/')
  111. return s;
  112. s++;
  113. // handle vi//vni indices
  114. if (*s != '/')
  115. vti = parseInt(s, &s);
  116. if (*s != '/')
  117. return s;
  118. s++;
  119. vni = parseInt(s, &s);
  120. return s;
  121. }
  122. ObjFile::ObjFile()
  123. : v(0)
  124. , v_size(0)
  125. , v_cap(0)
  126. , vt(0)
  127. , vt_size(0)
  128. , vt_cap(0)
  129. , vn(0)
  130. , vn_size(0)
  131. , vn_cap(0)
  132. , f(0)
  133. , f_size(0)
  134. , f_cap(0)
  135. , g(0)
  136. , g_size(0)
  137. , g_cap(0)
  138. {
  139. }
  140. ObjFile::~ObjFile()
  141. {
  142. delete[] v;
  143. delete[] vt;
  144. delete[] vn;
  145. delete[] f;
  146. delete[] g;
  147. }
  148. void objParseLine(ObjFile& result, const char* line)
  149. {
  150. if (line[0] == 'v' && line[1] == ' ')
  151. {
  152. const char* s = line + 2;
  153. float x = parseFloat(s, &s);
  154. float y = parseFloat(s, &s);
  155. float z = parseFloat(s, &s);
  156. if (result.v_size + 3 > result.v_cap)
  157. growArray(result.v, result.v_cap);
  158. result.v[result.v_size++] = x;
  159. result.v[result.v_size++] = y;
  160. result.v[result.v_size++] = z;
  161. }
  162. else if (line[0] == 'v' && line[1] == 't' && line[2] == ' ')
  163. {
  164. const char* s = line + 3;
  165. float u = parseFloat(s, &s);
  166. float v = parseFloat(s, &s);
  167. float w = parseFloat(s, &s);
  168. if (result.vt_size + 3 > result.vt_cap)
  169. growArray(result.vt, result.vt_cap);
  170. result.vt[result.vt_size++] = u;
  171. result.vt[result.vt_size++] = v;
  172. result.vt[result.vt_size++] = w;
  173. }
  174. else if (line[0] == 'v' && line[1] == 'n' && line[2] == ' ')
  175. {
  176. const char* s = line + 3;
  177. float x = parseFloat(s, &s);
  178. float y = parseFloat(s, &s);
  179. float z = parseFloat(s, &s);
  180. if (result.vn_size + 3 > result.vn_cap)
  181. growArray(result.vn, result.vn_cap);
  182. result.vn[result.vn_size++] = x;
  183. result.vn[result.vn_size++] = y;
  184. result.vn[result.vn_size++] = z;
  185. }
  186. else if (line[0] == 'f' && line[1] == ' ')
  187. {
  188. const char* s = line + 2;
  189. if (!result.g)
  190. {
  191. growArray(result.g, result.g_cap);
  192. ObjGroup g = {};
  193. result.g[result.g_size++] = g;
  194. }
  195. size_t v = result.v_size / 3;
  196. size_t vt = result.vt_size / 3;
  197. size_t vn = result.vn_size / 3;
  198. int fv = 0;
  199. int f[3][3] = {};
  200. while (*s)
  201. {
  202. int vi = 0, vti = 0, vni = 0;
  203. s = parseFace(s, vi, vti, vni);
  204. if (vi == 0)
  205. break;
  206. f[fv][0] = fixupIndex(vi, v);
  207. f[fv][1] = fixupIndex(vti, vt);
  208. f[fv][2] = fixupIndex(vni, vn);
  209. if (fv == 2)
  210. {
  211. if (result.f_size + 9 > result.f_cap)
  212. growArray(result.f, result.f_cap);
  213. memcpy(&result.f[result.f_size], f, 9 * sizeof(int));
  214. result.f_size += 9;
  215. result.g[result.g_size - 1].index_count += 3;
  216. f[1][0] = f[2][0];
  217. f[1][1] = f[2][1];
  218. f[1][2] = f[2][2];
  219. }
  220. else
  221. {
  222. fv++;
  223. }
  224. }
  225. }
  226. else if (strncmp(line, "usemtl", 6) == 0)
  227. {
  228. const char* s = line + 6;
  229. // skip whitespace
  230. while (*s == ' ' || *s == '\t')
  231. s++;
  232. if (result.g_size + 1 > result.g_cap)
  233. growArray(result.g, result.g_cap);
  234. ObjGroup g = {};
  235. g.index_offset = result.f_size / 3;
  236. strncpy(g.material, s, sizeof(g.material));
  237. g.material[sizeof(g.material) - 1] = 0;
  238. result.g[result.g_size++] = g;
  239. }
  240. }
  241. bool objParseFile(ObjFile& result, const char* path)
  242. {
  243. FILE* file = fopen(path, "rb");
  244. if (!file)
  245. return false;
  246. char buffer[65536];
  247. size_t size = 0;
  248. while (!feof(file))
  249. {
  250. size += fread(buffer + size, 1, sizeof(buffer) - size, file);
  251. size_t line = 0;
  252. while (line < size)
  253. {
  254. // find the end of current line
  255. void* eol = memchr(buffer + line, '\n', size - line);
  256. if (!eol)
  257. break;
  258. // zero-terminate for objParseLine
  259. size_t next = static_cast<char*>(eol) - buffer;
  260. buffer[next] = 0;
  261. // process next line
  262. objParseLine(result, buffer + line);
  263. line = next + 1;
  264. }
  265. // move prefix of the last line in the buffer to the beginning of the buffer for next iteration
  266. assert(line <= size);
  267. memmove(buffer, buffer + line, size - line);
  268. size -= line;
  269. }
  270. if (size)
  271. {
  272. // process last line
  273. assert(size < sizeof(buffer));
  274. buffer[size] = 0;
  275. objParseLine(result, buffer);
  276. }
  277. fclose(file);
  278. return true;
  279. }
  280. bool objValidate(const ObjFile& result)
  281. {
  282. size_t v = result.v_size / 3;
  283. size_t vt = result.vt_size / 3;
  284. size_t vn = result.vn_size / 3;
  285. for (size_t i = 0; i < result.f_size; i += 3)
  286. {
  287. int vi = result.f[i + 0];
  288. int vti = result.f[i + 1];
  289. int vni = result.f[i + 2];
  290. if (vi < 0)
  291. return false;
  292. if (vi >= 0 && size_t(vi) >= v)
  293. return false;
  294. if (vti >= 0 && size_t(vti) >= vt)
  295. return false;
  296. if (vni >= 0 && size_t(vni) >= vn)
  297. return false;
  298. }
  299. return true;
  300. }