geometryc.cpp 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. /*
  2. * Copyright 2011-2014 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. #include <algorithm>
  6. #include <vector>
  7. #include <string>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <bgfx.h>
  12. #include "../../src/vertexdecl.h"
  13. #include <tinystl/allocator.h>
  14. #include <tinystl/unordered_map.h>
  15. #include <tinystl/unordered_set.h>
  16. namespace stl = tinystl;
  17. #include <forsyth-too/forsythtriangleorderoptimizer.h>
  18. #include <ib-compress/indexbuffercompression.h>
  19. #if 0
  20. # define BX_TRACE(_format, ...) \
  21. do { \
  22. printf(BX_FILE_LINE_LITERAL "BGFX " _format "\n", ##__VA_ARGS__); \
  23. } while(0)
  24. # define BX_WARN(_condition, _format, ...) \
  25. do { \
  26. if (!(_condition) ) \
  27. { \
  28. BX_TRACE(BX_FILE_LINE_LITERAL "WARN " _format, ##__VA_ARGS__); \
  29. } \
  30. } while(0)
  31. # define BX_CHECK(_condition, _format, ...) \
  32. do { \
  33. if (!(_condition) ) \
  34. { \
  35. BX_TRACE(BX_FILE_LINE_LITERAL "CHECK " _format, ##__VA_ARGS__); \
  36. bx::debugBreak(); \
  37. } \
  38. } while(0)
  39. #endif // 0
  40. #define EXPECT(_condition) \
  41. do { \
  42. if (!(_condition) ) \
  43. { \
  44. printf("Error parsing at:\n" BX_FILE_LINE_LITERAL "\nExpected: " #_condition "\n"); \
  45. exit(EXIT_FAILURE); \
  46. } \
  47. } while(0)
  48. #include <bx/bx.h>
  49. #include <bx/debug.h>
  50. #include <bx/commandline.h>
  51. #include <bx/timer.h>
  52. #include <bx/readerwriter.h>
  53. #include <bx/hash.h>
  54. #include <bx/uint32_t.h>
  55. #include <bx/fpumath.h>
  56. #include <bx/tokenizecmd.h>
  57. #include "bounds.h"
  58. struct Vector3
  59. {
  60. float x;
  61. float y;
  62. float z;
  63. };
  64. typedef std::vector<Vector3> Vector3Array;
  65. struct Index3
  66. {
  67. int32_t m_position;
  68. int32_t m_texcoord;
  69. int32_t m_normal;
  70. int32_t m_vertexIndex;
  71. };
  72. typedef stl::unordered_map<uint64_t, Index3> Index3Map;
  73. struct Triangle
  74. {
  75. uint64_t m_index[3];
  76. };
  77. typedef std::vector<Triangle> TriangleArray;
  78. struct Group
  79. {
  80. uint32_t m_startTriangle;
  81. uint32_t m_numTriangles;
  82. std::string m_name;
  83. std::string m_material;
  84. };
  85. typedef std::vector<Group> GroupArray;
  86. struct Primitive
  87. {
  88. uint32_t m_startVertex;
  89. uint32_t m_startIndex;
  90. uint32_t m_numVertices;
  91. uint32_t m_numIndices;
  92. std::string m_name;
  93. };
  94. typedef std::vector<Primitive> PrimitiveArray;
  95. static uint32_t s_obbSteps = 17;
  96. #define BGFX_CHUNK_MAGIC_GEO BX_MAKEFOURCC('G', 'E', 'O', 0x0)
  97. #define BGFX_CHUNK_MAGIC_VB BX_MAKEFOURCC('V', 'B', ' ', 0x1)
  98. #define BGFX_CHUNK_MAGIC_IB BX_MAKEFOURCC('I', 'B', ' ', 0x0)
  99. #define BGFX_CHUNK_MAGIC_IBC BX_MAKEFOURCC('I', 'B', 'C', 0x0)
  100. #define BGFX_CHUNK_MAGIC_PRI BX_MAKEFOURCC('P', 'R', 'I', 0x0)
  101. long int fsize(FILE* _file)
  102. {
  103. long int pos = ftell(_file);
  104. fseek(_file, 0L, SEEK_END);
  105. long int size = ftell(_file);
  106. fseek(_file, pos, SEEK_SET);
  107. return size;
  108. }
  109. void triangleReorder(uint16_t* _indices, uint32_t _numIndices, uint32_t _numVertices, uint16_t _cacheSize)
  110. {
  111. uint16_t* newIndexList = new uint16_t[_numIndices];
  112. Forsyth::OptimizeFaces(_indices, _numIndices, _numVertices, newIndexList, _cacheSize);
  113. memcpy(_indices, newIndexList, _numIndices*2);
  114. delete [] newIndexList;
  115. }
  116. void triangleCompress(bx::WriterI* _writer, uint16_t* _indices, uint32_t _numIndices, uint8_t* _vertexData, uint32_t _numVertices, uint16_t _stride)
  117. {
  118. uint32_t* vertexRemap = (uint32_t*)malloc(_numVertices*sizeof(uint32_t) );
  119. WriteBitstream writer;
  120. CompressIndexBuffer(_indices, _numIndices/3, vertexRemap, _numVertices, IBCF_PER_TRIANGLE_1, writer);
  121. writer.Finish();
  122. printf( "uncompressed: %10d, compressed: %10d, ratio: %0.2f%%\n"
  123. , _numIndices*2
  124. , (uint32_t)writer.ByteSize()
  125. , 100.0f - float(writer.ByteSize() ) / float(_numIndices*2)*100.0f
  126. );
  127. BX_UNUSED(_vertexData, _stride);
  128. uint8_t* outVertexData = (uint8_t*)malloc(_numVertices*_stride);
  129. for (uint32_t ii = 0; ii < _numVertices; ++ii)
  130. {
  131. if (UINT32_MAX != vertexRemap[ii])
  132. {
  133. memcpy(&outVertexData[vertexRemap[ii]*_stride], &_vertexData[ii*_stride], _stride);
  134. }
  135. }
  136. memcpy(_vertexData, outVertexData, _numVertices*_stride);
  137. free(outVertexData);
  138. free(vertexRemap);
  139. bx::write(_writer, writer.RawData(), (uint32_t)writer.ByteSize() );
  140. }
  141. void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexDecl _decl, const uint16_t* _indices, uint32_t _numIndices)
  142. {
  143. struct PosTexcoord
  144. {
  145. float m_x;
  146. float m_y;
  147. float m_z;
  148. float m_pad0;
  149. float m_u;
  150. float m_v;
  151. float m_pad1;
  152. float m_pad2;
  153. };
  154. float* tangents = new float[6*_numVertices];
  155. memset(tangents, 0, 6*_numVertices*sizeof(float) );
  156. PosTexcoord v0;
  157. PosTexcoord v1;
  158. PosTexcoord v2;
  159. for (uint32_t ii = 0, num = _numIndices/3; ii < num; ++ii)
  160. {
  161. const uint16_t* indices = &_indices[ii*3];
  162. uint32_t i0 = indices[0];
  163. uint32_t i1 = indices[1];
  164. uint32_t i2 = indices[2];
  165. bgfx::vertexUnpack(&v0.m_x, bgfx::Attrib::Position, _decl, _vertices, i0);
  166. bgfx::vertexUnpack(&v0.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i0);
  167. bgfx::vertexUnpack(&v1.m_x, bgfx::Attrib::Position, _decl, _vertices, i1);
  168. bgfx::vertexUnpack(&v1.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i1);
  169. bgfx::vertexUnpack(&v2.m_x, bgfx::Attrib::Position, _decl, _vertices, i2);
  170. bgfx::vertexUnpack(&v2.m_u, bgfx::Attrib::TexCoord0, _decl, _vertices, i2);
  171. const float bax = v1.m_x - v0.m_x;
  172. const float bay = v1.m_y - v0.m_y;
  173. const float baz = v1.m_z - v0.m_z;
  174. const float bau = v1.m_u - v0.m_u;
  175. const float bav = v1.m_v - v0.m_v;
  176. const float cax = v2.m_x - v0.m_x;
  177. const float cay = v2.m_y - v0.m_y;
  178. const float caz = v2.m_z - v0.m_z;
  179. const float cau = v2.m_u - v0.m_u;
  180. const float cav = v2.m_v - v0.m_v;
  181. const float det = (bau * cav - bav * cau);
  182. const float invDet = 1.0f / det;
  183. const float tx = (bax * cav - cax * bav) * invDet;
  184. const float ty = (bay * cav - cay * bav) * invDet;
  185. const float tz = (baz * cav - caz * bav) * invDet;
  186. const float bx = (cax * bau - bax * cau) * invDet;
  187. const float by = (cay * bau - bay * cau) * invDet;
  188. const float bz = (caz * bau - baz * cau) * invDet;
  189. for (uint32_t jj = 0; jj < 3; ++jj)
  190. {
  191. float* tanu = &tangents[indices[jj]*6];
  192. float* tanv = &tanu[3];
  193. tanu[0] += tx;
  194. tanu[1] += ty;
  195. tanu[2] += tz;
  196. tanv[0] += bx;
  197. tanv[1] += by;
  198. tanv[2] += bz;
  199. }
  200. }
  201. for (uint32_t ii = 0; ii < _numVertices; ++ii)
  202. {
  203. const float* tanu = &tangents[ii*6];
  204. const float* tanv = &tangents[ii*6 + 3];
  205. float normal[4];
  206. bgfx::vertexUnpack(normal, bgfx::Attrib::Normal, _decl, _vertices, ii);
  207. float ndt = bx::vec3Dot(normal, tanu);
  208. float nxt[3];
  209. bx::vec3Cross(nxt, normal, tanu);
  210. float tmp[3];
  211. tmp[0] = tanu[0] - normal[0] * ndt;
  212. tmp[1] = tanu[1] - normal[1] * ndt;
  213. tmp[2] = tanu[2] - normal[2] * ndt;
  214. float tangent[4];
  215. bx::vec3Norm(tangent, tmp);
  216. tangent[3] = bx::vec3Dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
  217. bgfx::vertexPack(tangent, true, bgfx::Attrib::Tangent, _decl, _vertices, ii);
  218. }
  219. delete [] tangents;
  220. }
  221. void write(bx::WriterI* _writer, const void* _vertices, uint32_t _numVertices, uint32_t _stride)
  222. {
  223. Sphere maxSphere;
  224. calcMaxBoundingSphere(maxSphere, _vertices, _numVertices, _stride);
  225. Sphere minSphere;
  226. calcMinBoundingSphere(minSphere, _vertices, _numVertices, _stride);
  227. if (minSphere.m_radius > maxSphere.m_radius)
  228. {
  229. bx::write(_writer, maxSphere);
  230. }
  231. else
  232. {
  233. bx::write(_writer, minSphere);
  234. }
  235. Aabb aabb;
  236. calcAabb(aabb, _vertices, _numVertices, _stride);
  237. bx::write(_writer, aabb);
  238. Obb obb;
  239. calcObb(obb, _vertices, _numVertices, _stride, s_obbSteps);
  240. bx::write(_writer, obb);
  241. }
  242. void write(bx::WriterI* _writer
  243. , const uint8_t* _vertices
  244. , uint32_t _numVertices
  245. , const bgfx::VertexDecl& _decl
  246. , const uint16_t* _indices
  247. , uint32_t _numIndices
  248. , const uint8_t* _compressedIndices
  249. , uint32_t _compressedSize
  250. , const std::string& _material
  251. , const PrimitiveArray& _primitives
  252. )
  253. {
  254. using namespace bx;
  255. using namespace bgfx;
  256. uint32_t stride = _decl.getStride();
  257. write(_writer, BGFX_CHUNK_MAGIC_VB);
  258. write(_writer, _vertices, _numVertices, stride);
  259. write(_writer, _decl);
  260. write(_writer, uint16_t(_numVertices) );
  261. write(_writer, _vertices, _numVertices*stride);
  262. if (NULL != _compressedIndices)
  263. {
  264. write(_writer, BGFX_CHUNK_MAGIC_IBC);
  265. write(_writer, _numIndices);
  266. write(_writer, _compressedSize);
  267. write(_writer, _compressedIndices, _compressedSize);
  268. }
  269. else
  270. {
  271. write(_writer, BGFX_CHUNK_MAGIC_IB);
  272. write(_writer, _numIndices);
  273. write(_writer, _indices, _numIndices*2);
  274. }
  275. write(_writer, BGFX_CHUNK_MAGIC_PRI);
  276. uint16_t nameLen = uint16_t(_material.size() );
  277. write(_writer, nameLen);
  278. write(_writer, _material.c_str(), nameLen);
  279. write(_writer, uint16_t(_primitives.size() ) );
  280. for (PrimitiveArray::const_iterator primIt = _primitives.begin(); primIt != _primitives.end(); ++primIt)
  281. {
  282. const Primitive& prim = *primIt;
  283. nameLen = uint16_t(prim.m_name.size() );
  284. write(_writer, nameLen);
  285. write(_writer, prim.m_name.c_str(), nameLen);
  286. write(_writer, prim.m_startIndex);
  287. write(_writer, prim.m_numIndices);
  288. write(_writer, prim.m_startVertex);
  289. write(_writer, prim.m_numVertices);
  290. write(_writer, &_vertices[prim.m_startVertex*stride], prim.m_numVertices, stride);
  291. }
  292. }
  293. void help(const char* _error = NULL)
  294. {
  295. if (NULL != _error)
  296. {
  297. fprintf(stderr, "Error:\n%s\n\n", _error);
  298. }
  299. fprintf(stderr
  300. , "geometryc, bgfx geometry compiler tool\n"
  301. "Copyright 2011-2014 Branimir Karadzic. All rights reserved.\n"
  302. "License: http://www.opensource.org/licenses/BSD-2-Clause\n\n"
  303. );
  304. fprintf(stderr
  305. , "Usage: geometryc -f <in> -o <out>\n"
  306. "\n"
  307. "Supported input file types:\n"
  308. " *.obj Wavefront\n"
  309. "\n"
  310. "Options:\n"
  311. " -f <file path> Input file path.\n"
  312. " -o <file path> Output file path.\n"
  313. " -s, --scale <num> Scale factor.\n"
  314. " --ccw Counter-clockwise winding order.\n"
  315. " --flipv Flip texture coordinate V.\n"
  316. " --obb <num> Number of steps for calculating oriented bounding box.\n"
  317. " Default value is 17. Less steps less precise OBB is.\n"
  318. " More steps slower calculation.\n"
  319. " --packnormal <num> Normal packing.\n"
  320. " 0 - unpacked 12 bytes (default).\n"
  321. " 1 - packed 4 bytes.\n"
  322. " --packuv <num> Texture coordinate packing.\n"
  323. " 0 - unpacked 8 bytes (default).\n"
  324. " 1 - packed 4 bytes.\n"
  325. " --tangent Calculate tangent vectors (packing mode is the same as normal).\n"
  326. " -c, --compress Compress indices.\n"
  327. "\n"
  328. "For additional information, see https://github.com/bkaradzic/bgfx\n"
  329. );
  330. }
  331. inline uint32_t rgbaToAbgr(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a)
  332. {
  333. return (uint32_t(_r)<<0)
  334. | (uint32_t(_g)<<8)
  335. | (uint32_t(_b)<<16)
  336. | (uint32_t(_a)<<24)
  337. ;
  338. }
  339. struct GroupSortByMaterial
  340. {
  341. bool operator()(const Group& _lhs, const Group& _rhs)
  342. {
  343. return _lhs.m_material < _rhs.m_material;
  344. }
  345. };
  346. int main(int _argc, const char* _argv[])
  347. {
  348. bx::CommandLine cmdLine(_argc, _argv);
  349. const char* filePath = cmdLine.findOption('f');
  350. if (NULL == filePath)
  351. {
  352. help("Input file name must be specified.");
  353. return EXIT_FAILURE;
  354. }
  355. const char* outFilePath = cmdLine.findOption('o');
  356. if (NULL == outFilePath)
  357. {
  358. help("Output file name must be specified.");
  359. return EXIT_FAILURE;
  360. }
  361. float scale = 1.0f;
  362. const char* scaleArg = cmdLine.findOption('s', "scale");
  363. if (NULL != scaleArg)
  364. {
  365. scale = (float)atof(scaleArg);
  366. }
  367. bool compress = cmdLine.hasArg('c', "compress");
  368. cmdLine.hasArg(s_obbSteps, '\0', "obb");
  369. s_obbSteps = bx::uint32_min(bx::uint32_max(s_obbSteps, 1), 90);
  370. uint32_t packNormal = 0;
  371. cmdLine.hasArg(packNormal, '\0', "packnormal");
  372. uint32_t packUv = 0;
  373. cmdLine.hasArg(packUv, '\0', "packuv");
  374. bool ccw = cmdLine.hasArg("ccw");
  375. bool flipV = cmdLine.hasArg("flipv");
  376. bool hasTangent = cmdLine.hasArg("tangent");
  377. FILE* file = fopen(filePath, "r");
  378. if (NULL == file)
  379. {
  380. printf("Unable to open input file '%s'.", filePath);
  381. exit(EXIT_FAILURE);
  382. }
  383. int64_t parseElapsed = -bx::getHPCounter();
  384. int64_t triReorderElapsed = 0;
  385. uint32_t size = (uint32_t)fsize(file);
  386. char* data = new char[size+1];
  387. size = (uint32_t)fread(data, 1, size, file);
  388. data[size] = '\0';
  389. fclose(file);
  390. // https://en.wikipedia.org/wiki/Wavefront_.obj_file
  391. Vector3Array positions;
  392. Vector3Array normals;
  393. Vector3Array texcoords;
  394. Index3Map indexMap;
  395. TriangleArray triangles;
  396. GroupArray groups;
  397. uint32_t num = 0;
  398. Group group;
  399. group.m_startTriangle = 0;
  400. group.m_numTriangles = 0;
  401. char commandLine[2048];
  402. uint32_t len = sizeof(commandLine);
  403. int argc;
  404. char* argv[64];
  405. const char* next = data;
  406. do
  407. {
  408. next = bx::tokenizeCommandLine(next, commandLine, len, argc, argv, BX_COUNTOF(argv), '\n');
  409. if (0 < argc)
  410. {
  411. if (0 == strcmp(argv[0], "#") )
  412. {
  413. if (2 < argc
  414. && 0 == strcmp(argv[2], "polygons") )
  415. {
  416. }
  417. }
  418. else if (0 == strcmp(argv[0], "f") )
  419. {
  420. Triangle triangle;
  421. memset(&triangle, 0, sizeof(Triangle) );
  422. for (uint32_t edge = 0, numEdges = argc-1; edge < numEdges; ++edge)
  423. {
  424. Index3 index;
  425. index.m_texcoord = -1;
  426. index.m_normal = -1;
  427. index.m_vertexIndex = -1;
  428. char* vertex = argv[edge+1];
  429. char* texcoord = strchr(vertex, '/');
  430. if (NULL != texcoord)
  431. {
  432. *texcoord++ = '\0';
  433. char* normal = strchr(texcoord, '/');
  434. if (NULL != normal)
  435. {
  436. *normal++ = '\0';
  437. index.m_normal = atoi(normal)-1;
  438. }
  439. index.m_texcoord = atoi(texcoord)-1;
  440. }
  441. index.m_position = atoi(vertex)-1;
  442. uint64_t hash0 = index.m_position;
  443. uint64_t hash1 = uint64_t(index.m_texcoord)<<20;
  444. uint64_t hash2 = uint64_t(index.m_normal)<<40;
  445. uint64_t hash = hash0^hash1^hash2;
  446. stl::pair<Index3Map::iterator, bool> result = indexMap.insert(stl::make_pair(hash, index) );
  447. if (!result.second)
  448. {
  449. Index3& oldIndex = result.first->second;
  450. BX_UNUSED(oldIndex);
  451. BX_CHECK(oldIndex.m_position == index.m_position
  452. && oldIndex.m_texcoord == index.m_texcoord
  453. && oldIndex.m_normal == index.m_normal
  454. , "Hash collision!"
  455. );
  456. }
  457. switch (edge)
  458. {
  459. case 0:
  460. case 1:
  461. case 2:
  462. triangle.m_index[edge] = hash;
  463. if (2 == edge)
  464. {
  465. if (ccw)
  466. {
  467. std::swap(triangle.m_index[1], triangle.m_index[2]);
  468. }
  469. triangles.push_back(triangle);
  470. }
  471. break;
  472. default:
  473. if (ccw)
  474. {
  475. triangle.m_index[2] = triangle.m_index[1];
  476. triangle.m_index[1] = hash;
  477. }
  478. else
  479. {
  480. triangle.m_index[1] = triangle.m_index[2];
  481. triangle.m_index[2] = hash;
  482. }
  483. triangles.push_back(triangle);
  484. break;
  485. }
  486. }
  487. }
  488. else if (0 == strcmp(argv[0], "g") )
  489. {
  490. EXPECT(1 < argc);
  491. group.m_name = argv[1];
  492. }
  493. else if (*argv[0] == 'v')
  494. {
  495. group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
  496. if (0 < group.m_numTriangles)
  497. {
  498. groups.push_back(group);
  499. group.m_startTriangle = (uint32_t)(triangles.size() );
  500. group.m_numTriangles = 0;
  501. }
  502. if (0 == strcmp(argv[0], "vn") )
  503. {
  504. Vector3 normal;
  505. normal.x = (float)atof(argv[1]);
  506. normal.y = (float)atof(argv[2]);
  507. normal.z = (float)atof(argv[3]);
  508. normals.push_back(normal);
  509. }
  510. else if (0 == strcmp(argv[0], "vp") )
  511. {
  512. static bool once = true;
  513. if (once)
  514. {
  515. once = false;
  516. printf("warning: 'parameter space vertices' are unsupported.\n");
  517. }
  518. }
  519. else if (0 == strcmp(argv[0], "vt") )
  520. {
  521. Vector3 texcoord;
  522. texcoord.x = (float)atof(argv[1]);
  523. texcoord.y = 0.0f;
  524. texcoord.z = 0.0f;
  525. switch (argc)
  526. {
  527. case 4:
  528. texcoord.z = (float)atof(argv[3]);
  529. // fallthrough
  530. case 3:
  531. texcoord.y = (float)atof(argv[2]);
  532. break;
  533. default:
  534. break;
  535. }
  536. texcoords.push_back(texcoord);
  537. }
  538. else
  539. {
  540. float px = (float)atof(argv[1]);
  541. float py = (float)atof(argv[2]);
  542. float pz = (float)atof(argv[3]);
  543. float pw = 1.0f;
  544. if (argc > 4)
  545. {
  546. pw = (float)atof(argv[4]);
  547. }
  548. float invW = scale/pw;
  549. px *= invW;
  550. py *= invW;
  551. pz *= invW;
  552. Vector3 pos;
  553. pos.x = px;
  554. pos.y = py;
  555. pos.z = pz;
  556. positions.push_back(pos);
  557. }
  558. }
  559. else if (0 == strcmp(argv[0], "usemtl") )
  560. {
  561. std::string material(argv[1]);
  562. if (material != group.m_material)
  563. {
  564. group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
  565. if (0 < group.m_numTriangles)
  566. {
  567. groups.push_back(group);
  568. group.m_startTriangle = (uint32_t)(triangles.size() );
  569. group.m_numTriangles = 0;
  570. }
  571. }
  572. group.m_material = material;
  573. }
  574. // unsupported tags
  575. // else if (0 == strcmp(argv[0], "mtllib") )
  576. // {
  577. // }
  578. // else if (0 == strcmp(argv[0], "o") )
  579. // {
  580. // }
  581. // else if (0 == strcmp(argv[0], "s") )
  582. // {
  583. // }
  584. }
  585. ++num;
  586. }
  587. while ('\0' != *next);
  588. group.m_numTriangles = (uint32_t)(triangles.size() ) - group.m_startTriangle;
  589. if (0 < group.m_numTriangles)
  590. {
  591. groups.push_back(group);
  592. group.m_startTriangle = (uint32_t)(triangles.size() );
  593. group.m_numTriangles = 0;
  594. }
  595. delete [] data;
  596. int64_t now = bx::getHPCounter();
  597. parseElapsed += now;
  598. int64_t convertElapsed = -now;
  599. std::sort(groups.begin(), groups.end(), GroupSortByMaterial() );
  600. bool hasColor = false;
  601. bool hasNormal;
  602. bool hasTexcoord;
  603. {
  604. Index3Map::const_iterator it = indexMap.begin();
  605. hasNormal = -1 != it->second.m_normal;
  606. hasTexcoord = -1 != it->second.m_texcoord;
  607. if (!hasTexcoord
  608. && texcoords.size() == positions.size() )
  609. {
  610. hasTexcoord = true;
  611. for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
  612. {
  613. it->second.m_texcoord = it->second.m_position;
  614. }
  615. }
  616. if (!hasNormal
  617. && normals.size() == positions.size() )
  618. {
  619. hasNormal = true;
  620. for (Index3Map::iterator it = indexMap.begin(), itEnd = indexMap.end(); it != itEnd; ++it)
  621. {
  622. it->second.m_normal = it->second.m_position;
  623. }
  624. }
  625. }
  626. bgfx::VertexDecl decl;
  627. decl.begin();
  628. decl.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);
  629. if (hasColor)
  630. {
  631. decl.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true);
  632. }
  633. if (hasTexcoord)
  634. {
  635. switch (packUv)
  636. {
  637. default:
  638. case 0:
  639. decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float);
  640. break;
  641. case 1:
  642. decl.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Half);
  643. break;
  644. }
  645. }
  646. if (hasNormal)
  647. {
  648. hasTangent &= hasTexcoord;
  649. switch (packNormal)
  650. {
  651. default:
  652. case 0:
  653. decl.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float);
  654. if (hasTangent)
  655. {
  656. decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Float);
  657. }
  658. break;
  659. case 1:
  660. decl.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true);
  661. if (hasTangent)
  662. {
  663. decl.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true);
  664. }
  665. break;
  666. }
  667. }
  668. decl.end();
  669. uint32_t stride = decl.getStride();
  670. uint8_t* vertexData = new uint8_t[triangles.size() * 3 * stride];
  671. uint16_t* indexData = new uint16_t[triangles.size() * 3];
  672. int32_t numVertices = 0;
  673. int32_t numIndices = 0;
  674. int32_t numPrimitives = 0;
  675. uint8_t* vertices = vertexData;
  676. uint16_t* indices = indexData;
  677. std::string material = groups.begin()->m_material;
  678. PrimitiveArray primitives;
  679. bx::CrtFileWriter writer;
  680. if (0 != writer.open(outFilePath) )
  681. {
  682. printf("Unable to open output file '%s'.", outFilePath);
  683. exit(EXIT_FAILURE);
  684. }
  685. Primitive prim;
  686. prim.m_startVertex = 0;
  687. prim.m_startIndex = 0;
  688. uint32_t positionOffset = decl.getOffset(bgfx::Attrib::Position);
  689. uint32_t color0Offset = decl.getOffset(bgfx::Attrib::Color0);
  690. bx::CrtAllocator crtAllocator;
  691. bx::MemoryBlock memBlock(&crtAllocator);
  692. uint32_t ii = 0;
  693. for (GroupArray::const_iterator groupIt = groups.begin(); groupIt != groups.end(); ++groupIt, ++ii)
  694. {
  695. for (uint32_t tri = groupIt->m_startTriangle, end = tri + groupIt->m_numTriangles; tri < end; ++tri)
  696. {
  697. if (material != groupIt->m_material
  698. || 65533 < numVertices)
  699. {
  700. prim.m_numVertices = numVertices - prim.m_startVertex;
  701. prim.m_numIndices = numIndices - prim.m_startIndex;
  702. if (0 < prim.m_numVertices)
  703. {
  704. primitives.push_back(prim);
  705. }
  706. if (hasTangent)
  707. {
  708. calcTangents(vertexData, numVertices, decl, indexData, numIndices);
  709. }
  710. bx::MemoryWriter memWriter(&memBlock);
  711. triReorderElapsed -= bx::getHPCounter();
  712. for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
  713. {
  714. const Primitive& prim = *primIt;
  715. triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
  716. if (compress)
  717. {
  718. triangleCompress(&memWriter
  719. , indexData + prim.m_startIndex
  720. , prim.m_numIndices
  721. , vertexData + prim.m_startVertex
  722. , numVertices
  723. , stride
  724. );
  725. }
  726. }
  727. triReorderElapsed += bx::getHPCounter();
  728. write(&writer
  729. , vertexData
  730. , numVertices
  731. , decl
  732. , indexData
  733. , numIndices
  734. , (uint8_t*)memBlock.more()
  735. , memBlock.getSize()
  736. , material
  737. , primitives
  738. );
  739. primitives.clear();
  740. for (Index3Map::iterator indexIt = indexMap.begin(); indexIt != indexMap.end(); ++indexIt)
  741. {
  742. indexIt->second.m_vertexIndex = -1;
  743. }
  744. vertices = vertexData;
  745. indices = indexData;
  746. numVertices = 0;
  747. numIndices = 0;
  748. prim.m_startVertex = 0;
  749. prim.m_startIndex = 0;
  750. ++numPrimitives;
  751. material = groupIt->m_material;
  752. }
  753. Triangle& triangle = triangles[tri];
  754. for (uint32_t edge = 0; edge < 3; ++edge)
  755. {
  756. uint64_t hash = triangle.m_index[edge];
  757. Index3& index = indexMap[hash];
  758. if (index.m_vertexIndex == -1)
  759. {
  760. index.m_vertexIndex = numVertices++;
  761. float* position = (float*)(vertices + positionOffset);
  762. memcpy(position, &positions[index.m_position], 3*sizeof(float) );
  763. if (hasColor)
  764. {
  765. uint32_t* color0 = (uint32_t*)(vertices + color0Offset);
  766. *color0 = rgbaToAbgr(numVertices%255, numIndices%255, 0, 0xff);
  767. }
  768. if (hasTexcoord)
  769. {
  770. float uv[2];
  771. memcpy(uv, &texcoords[index.m_texcoord], 2*sizeof(float) );
  772. if (flipV)
  773. {
  774. uv[1] = -uv[1];
  775. }
  776. bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, decl, vertices);
  777. }
  778. if (hasNormal)
  779. {
  780. float normal[4];
  781. bx::vec3Norm(normal, (float*)&normals[index.m_normal]);
  782. bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, decl, vertices);
  783. }
  784. vertices += stride;
  785. }
  786. *indices++ = (uint16_t)index.m_vertexIndex;
  787. ++numIndices;
  788. }
  789. }
  790. if (0 < numVertices)
  791. {
  792. prim.m_numVertices = numVertices - prim.m_startVertex;
  793. prim.m_numIndices = numIndices - prim.m_startIndex;
  794. prim.m_name = groupIt->m_name;
  795. primitives.push_back(prim);
  796. prim.m_startVertex = numVertices;
  797. prim.m_startIndex = numIndices;
  798. }
  799. BX_TRACE("%3d: s %5d, n %5d, %s\n"
  800. , ii
  801. , groupIt->m_startTriangle
  802. , groupIt->m_numTriangles
  803. , groupIt->m_material.c_str()
  804. );
  805. }
  806. if (0 < primitives.size() )
  807. {
  808. if (hasTangent)
  809. {
  810. calcTangents(vertexData, numVertices, decl, indexData, numIndices);
  811. }
  812. bx::MemoryWriter memWriter(&memBlock);
  813. triReorderElapsed -= bx::getHPCounter();
  814. for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
  815. {
  816. const Primitive& prim = *primIt;
  817. triangleReorder(indexData + prim.m_startIndex, prim.m_numIndices, numVertices, 32);
  818. if (compress)
  819. {
  820. triangleCompress(&memWriter
  821. , indexData + prim.m_startIndex
  822. , prim.m_numIndices
  823. , vertexData + prim.m_startVertex
  824. , numVertices
  825. , stride
  826. );
  827. }
  828. }
  829. triReorderElapsed += bx::getHPCounter();
  830. write(&writer
  831. , vertexData
  832. , numVertices
  833. , decl
  834. , indexData
  835. , numIndices
  836. , (uint8_t*)memBlock.more()
  837. , memBlock.getSize()
  838. , material
  839. , primitives
  840. );
  841. }
  842. printf("size: %d\n", uint32_t(writer.seek() ) );
  843. writer.close();
  844. delete [] indexData;
  845. delete [] vertexData;
  846. now = bx::getHPCounter();
  847. convertElapsed += now;
  848. printf("parse %f [s]\ntri reorder %f [s]\nconvert %f [s]\n# %d, g %d, p %d, v %d, i %d\n"
  849. , double(parseElapsed)/bx::getHPFrequency()
  850. , double(triReorderElapsed)/bx::getHPFrequency()
  851. , double(convertElapsed)/bx::getHPFrequency()
  852. , num
  853. , uint32_t(groups.size() )
  854. , numPrimitives
  855. , numVertices
  856. , numIndices
  857. );
  858. return EXIT_SUCCESS;
  859. }