geometryc.cpp 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464
  1. /*
  2. * Copyright 2011-2022 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE
  4. */
  5. #include <algorithm>
  6. #include <bx/string.h>
  7. #include <bgfx/bgfx.h>
  8. #include "../../src/vertexlayout.h"
  9. #include <tinystl/allocator.h>
  10. #include <tinystl/string.h>
  11. #include <tinystl/vector.h>
  12. namespace stl = tinystl;
  13. #include <meshoptimizer/src/meshoptimizer.h>
  14. #define CGLTF_IMPLEMENTATION
  15. #include <cgltf/cgltf.h>
  16. #define BGFX_GEOMETRYC_VERSION_MAJOR 1
  17. #define BGFX_GEOMETRYC_VERSION_MINOR 0
  18. #if 0
  19. # define BX_TRACE(_format, ...) \
  20. do { \
  21. bx::printf(BX_FILE_LINE_LITERAL "BGFX " _format "\n", ##__VA_ARGS__); \
  22. } while(0)
  23. # define BX_WARN(_condition, _format, ...) \
  24. do { \
  25. if (!(_condition) ) \
  26. { \
  27. BX_TRACE(BX_FILE_LINE_LITERAL "WARN " _format, ##__VA_ARGS__); \
  28. } \
  29. } while(0)
  30. # define BX_ASSERT(_condition, _format, ...) \
  31. do { \
  32. if (!(_condition) ) \
  33. { \
  34. BX_TRACE(BX_FILE_LINE_LITERAL "CHECK " _format, ##__VA_ARGS__); \
  35. bx::debugBreak(); \
  36. } \
  37. } while(0)
  38. #endif // 0
  39. #include <bx/bx.h>
  40. #include <bx/bounds.h>
  41. #include <bx/commandline.h>
  42. #include <bx/debug.h>
  43. #include <bx/file.h>
  44. #include <bx/hash.h>
  45. #include <bx/math.h>
  46. #include <bx/timer.h>
  47. #include <bx/uint32_t.h>
  48. typedef stl::vector<bx::Vec3> Vec3Array;
  49. struct Index3
  50. {
  51. int32_t m_position;
  52. int32_t m_texcoord;
  53. int32_t m_normal;
  54. int32_t m_vbc; // Barycentric ID. Holds either 0, 1 or 2.
  55. };
  56. struct TriIndices
  57. {
  58. Index3 m_index[3];
  59. };
  60. typedef stl::vector<TriIndices> TriangleArray;
  61. struct Group
  62. {
  63. uint32_t m_startTriangle;
  64. uint32_t m_numTriangles;
  65. stl::string m_name;
  66. stl::string m_material;
  67. };
  68. typedef stl::vector<Group> GroupArray;
  69. struct Primitive
  70. {
  71. uint32_t m_startVertex;
  72. uint32_t m_startIndex;
  73. uint32_t m_numVertices;
  74. uint32_t m_numIndices;
  75. stl::string m_name;
  76. };
  77. typedef stl::vector<Primitive> PrimitiveArray;
  78. struct Axis
  79. {
  80. enum Enum
  81. {
  82. NegativeX,
  83. PositiveX,
  84. NegativeY,
  85. PositiveY,
  86. NegativeZ,
  87. PositiveZ,
  88. };
  89. };
  90. static bx::Vec3 s_axisVectors[6] =
  91. {
  92. bx::Vec3(-1.0f, 0.0f, 0.0f),
  93. bx::Vec3( 1.0f, 0.0f, 0.0f),
  94. bx::Vec3( 0.0f,-1.0f, 0.0f),
  95. bx::Vec3( 0.0f, 1.0f, 0.0f),
  96. bx::Vec3( 0.0f, 0.0f,-1.0f),
  97. bx::Vec3( 0.0f, 0.0f, 1.0f),
  98. };
  99. struct CoordinateSystem
  100. {
  101. bx::Handness::Enum m_handness;
  102. Axis::Enum m_up;
  103. Axis::Enum m_forward;
  104. };
  105. struct CoordinateSystemMapping
  106. {
  107. const char* m_param;
  108. CoordinateSystem m_coordinateSystem;
  109. };
  110. static const CoordinateSystemMapping s_coordinateSystemMappings[] =
  111. {
  112. { "lh-up+y", { bx::Handness::Left, Axis::PositiveY, Axis::PositiveZ } },
  113. { "lh-up+z", { bx::Handness::Left, Axis::PositiveZ, Axis::PositiveY } },
  114. { "rh-up+y", { bx::Handness::Right, Axis::PositiveY, Axis::PositiveZ } },
  115. { "rh-up+z", { bx::Handness::Right, Axis::PositiveZ, Axis::PositiveY } },
  116. };
  117. struct Mesh
  118. {
  119. Vec3Array m_positions;
  120. Vec3Array m_normals;
  121. Vec3Array m_texcoords;
  122. TriangleArray m_triangles;
  123. GroupArray m_groups;
  124. CoordinateSystem m_coordinateSystem;
  125. };
  126. static uint32_t s_obbSteps = 17;
  127. constexpr uint32_t kChunkVertexBuffer = BX_MAKEFOURCC('V', 'B', ' ', 0x1);
  128. constexpr uint32_t kChunkVertexBufferCompressed = BX_MAKEFOURCC('V', 'B', 'C', 0x0);
  129. constexpr uint32_t kChunkIndexBuffer = BX_MAKEFOURCC('I', 'B', ' ', 0x0);
  130. constexpr uint32_t kChunkIndexBufferCompressed = BX_MAKEFOURCC('I', 'B', 'C', 0x1);
  131. constexpr uint32_t kChunkPrimitive = BX_MAKEFOURCC('P', 'R', 'I', 0x0);
  132. void optimizeVertexCache(uint16_t* _indices, uint32_t _numIndices, uint32_t _numVertices)
  133. {
  134. uint16_t* newIndexList = new uint16_t[_numIndices];
  135. meshopt_optimizeVertexCache(newIndexList, _indices, _numIndices, _numVertices);
  136. bx::memCopy(_indices, newIndexList, _numIndices * 2);
  137. delete[] newIndexList;
  138. }
  139. uint32_t optimizeVertexFetch(
  140. uint16_t* _indices
  141. , uint32_t _numIndices
  142. , uint8_t* _vertexData
  143. , uint32_t _numVertices
  144. , uint16_t _stride
  145. )
  146. {
  147. unsigned char* newVertices = (unsigned char*)malloc(_numVertices * _stride );
  148. size_t vertexCount = meshopt_optimizeVertexFetch(newVertices, _indices, _numIndices, _vertexData, _numVertices, _stride);
  149. bx::memCopy(_vertexData, newVertices, _numVertices * _stride);
  150. free(newVertices);
  151. return uint32_t(vertexCount);
  152. }
  153. void writeCompressedIndices(
  154. bx::WriterI* _writer
  155. , const uint16_t* _indices
  156. , uint32_t _numIndices
  157. , uint32_t _numVertices
  158. , bx::Error* _err
  159. )
  160. {
  161. size_t maxSize = meshopt_encodeIndexBufferBound(_numIndices, _numVertices);
  162. unsigned char* compressedIndices = (unsigned char*)malloc(maxSize);
  163. size_t compressedSize = meshopt_encodeIndexBuffer(compressedIndices, maxSize, _indices, _numIndices);
  164. bx::printf("Indices uncompressed: %10d, compressed: %10d, ratio: %0.2f%%\n"
  165. , _numIndices*2
  166. , (uint32_t)compressedSize
  167. , 100.0f - float(compressedSize ) / float(_numIndices*2)*100.0f
  168. );
  169. bx::write(_writer, (uint32_t)compressedSize, _err);
  170. bx::write(_writer, compressedIndices, (uint32_t)compressedSize, _err);
  171. free(compressedIndices);
  172. }
  173. void writeCompressedVertices(
  174. bx::WriterI* _writer
  175. , const uint8_t* _vertices
  176. , uint32_t _numVertices
  177. , uint16_t _stride
  178. , bx::Error* _err
  179. )
  180. {
  181. size_t maxSize = meshopt_encodeVertexBufferBound(_numVertices, _stride);
  182. unsigned char* compressedVertices = (unsigned char*)malloc(maxSize);
  183. size_t compressedSize = meshopt_encodeVertexBuffer(compressedVertices, maxSize, _vertices, _numVertices, _stride);
  184. bx::printf("Vertices uncompressed: %10d, compressed: %10d, ratio: %0.2f%%\n"
  185. , _numVertices * _stride
  186. , (uint32_t)compressedSize
  187. , 100.0f - float(compressedSize) / float(_numVertices * _stride)*100.0f
  188. );
  189. bx::write(_writer, (uint32_t)compressedSize, _err);
  190. bx::write(_writer, compressedVertices, (uint32_t)compressedSize, _err);
  191. free(compressedVertices);
  192. }
  193. void calcTangents(void* _vertices, uint16_t _numVertices, bgfx::VertexLayout _layout, const uint16_t* _indices, uint32_t _numIndices)
  194. {
  195. struct PosTexcoord
  196. {
  197. float m_x;
  198. float m_y;
  199. float m_z;
  200. float m_pad0;
  201. float m_u;
  202. float m_v;
  203. float m_pad1;
  204. float m_pad2;
  205. };
  206. float* tangents = new float[6*_numVertices];
  207. bx::memSet(tangents, 0, 6*_numVertices*sizeof(float) );
  208. PosTexcoord v0;
  209. PosTexcoord v1;
  210. PosTexcoord v2;
  211. for (uint32_t ii = 0, num = _numIndices/3; ii < num; ++ii)
  212. {
  213. const uint16_t* indices = &_indices[ii*3];
  214. uint32_t i0 = indices[0];
  215. uint32_t i1 = indices[1];
  216. uint32_t i2 = indices[2];
  217. bgfx::vertexUnpack(&v0.m_x, bgfx::Attrib::Position, _layout, _vertices, i0);
  218. bgfx::vertexUnpack(&v0.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i0);
  219. bgfx::vertexUnpack(&v1.m_x, bgfx::Attrib::Position, _layout, _vertices, i1);
  220. bgfx::vertexUnpack(&v1.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i1);
  221. bgfx::vertexUnpack(&v2.m_x, bgfx::Attrib::Position, _layout, _vertices, i2);
  222. bgfx::vertexUnpack(&v2.m_u, bgfx::Attrib::TexCoord0, _layout, _vertices, i2);
  223. const float bax = v1.m_x - v0.m_x;
  224. const float bay = v1.m_y - v0.m_y;
  225. const float baz = v1.m_z - v0.m_z;
  226. const float bau = v1.m_u - v0.m_u;
  227. const float bav = v1.m_v - v0.m_v;
  228. const float cax = v2.m_x - v0.m_x;
  229. const float cay = v2.m_y - v0.m_y;
  230. const float caz = v2.m_z - v0.m_z;
  231. const float cau = v2.m_u - v0.m_u;
  232. const float cav = v2.m_v - v0.m_v;
  233. const float det = (bau * cav - bav * cau);
  234. const float invDet = 1.0f / det;
  235. const float tx = (bax * cav - cax * bav) * invDet;
  236. const float ty = (bay * cav - cay * bav) * invDet;
  237. const float tz = (baz * cav - caz * bav) * invDet;
  238. const float bx = (cax * bau - bax * cau) * invDet;
  239. const float by = (cay * bau - bay * cau) * invDet;
  240. const float bz = (caz * bau - baz * cau) * invDet;
  241. for (uint32_t jj = 0; jj < 3; ++jj)
  242. {
  243. float* tanu = &tangents[indices[jj]*6];
  244. float* tanv = &tanu[3];
  245. tanu[0] += tx;
  246. tanu[1] += ty;
  247. tanu[2] += tz;
  248. tanv[0] += bx;
  249. tanv[1] += by;
  250. tanv[2] += bz;
  251. }
  252. }
  253. for (uint32_t ii = 0; ii < _numVertices; ++ii)
  254. {
  255. const bx::Vec3 tanu = bx::load<bx::Vec3>(&tangents[ii*6]);
  256. const bx::Vec3 tanv = bx::load<bx::Vec3>(&tangents[ii*6 + 3]);
  257. float nxyzw[4];
  258. bgfx::vertexUnpack(nxyzw, bgfx::Attrib::Normal, _layout, _vertices, ii);
  259. const bx::Vec3 normal = bx::load<bx::Vec3>(nxyzw);
  260. const float ndt = bx::dot(normal, tanu);
  261. const bx::Vec3 nxt = bx::cross(normal, tanu);
  262. const bx::Vec3 tmp = bx::sub(tanu, bx::mul(normal, ndt) );
  263. float tangent[4];
  264. bx::store(tangent, bx::normalize(tmp) );
  265. tangent[3] = bx::dot(nxt, tanv) < 0.0f ? -1.0f : 1.0f;
  266. bgfx::vertexPack(tangent, true, bgfx::Attrib::Tangent, _layout, _vertices, ii);
  267. }
  268. delete [] tangents;
  269. }
  270. void write(
  271. bx::WriterI* _writer
  272. , const void* _vertices
  273. , uint32_t _numVertices
  274. , uint32_t _stride
  275. , bx::Error* _err
  276. )
  277. {
  278. bx::Sphere maxSphere;
  279. bx::calcMaxBoundingSphere(maxSphere, _vertices, _numVertices, _stride);
  280. bx::Sphere minSphere;
  281. bx::calcMinBoundingSphere(minSphere, _vertices, _numVertices, _stride);
  282. if (minSphere.radius > maxSphere.radius)
  283. {
  284. bx::write(_writer, maxSphere, _err);
  285. }
  286. else
  287. {
  288. bx::write(_writer, minSphere, _err);
  289. }
  290. bx::Aabb aabb;
  291. bx::toAabb(aabb, _vertices, _numVertices, _stride);
  292. bx::write(_writer, aabb, _err);
  293. bx::Obb obb;
  294. bx::calcObb(obb, _vertices, _numVertices, _stride, s_obbSteps);
  295. bx::write(_writer, obb, _err);
  296. }
  297. void write(
  298. bx::WriterI* _writer
  299. , const uint8_t* _vertices
  300. , uint32_t _numVertices
  301. , const bgfx::VertexLayout& _layout
  302. , const uint16_t* _indices
  303. , uint32_t _numIndices
  304. , bool _compress
  305. , const stl::string& _material
  306. , const PrimitiveArray& _primitives
  307. , bx::Error* _err
  308. )
  309. {
  310. using namespace bx;
  311. using namespace bgfx;
  312. uint32_t stride = _layout.getStride();
  313. if (_compress)
  314. {
  315. write(_writer, kChunkVertexBufferCompressed, _err);
  316. write(_writer, _vertices, _numVertices, stride, _err);
  317. write(_writer, _layout);
  318. write(_writer, uint16_t(_numVertices), _err);
  319. writeCompressedVertices(_writer, _vertices, _numVertices, uint16_t(stride), _err);
  320. }
  321. else
  322. {
  323. write(_writer, kChunkVertexBuffer, _err);
  324. write(_writer, _vertices, _numVertices, stride, _err);
  325. write(_writer, _layout, _err);
  326. write(_writer, uint16_t(_numVertices), _err);
  327. write(_writer, _vertices, _numVertices*stride, _err);
  328. }
  329. if (_compress)
  330. {
  331. write(_writer, kChunkIndexBufferCompressed, _err);
  332. write(_writer, _numIndices, _err);
  333. writeCompressedIndices(_writer, _indices, _numIndices, _numVertices, _err);
  334. }
  335. else
  336. {
  337. write(_writer, kChunkIndexBuffer, _err);
  338. write(_writer, _numIndices, _err);
  339. write(_writer, _indices, _numIndices*2, _err);
  340. }
  341. write(_writer, kChunkPrimitive, _err);
  342. uint16_t nameLen = uint16_t(_material.size() );
  343. write(_writer, nameLen, _err);
  344. write(_writer, _material.c_str(), nameLen, _err);
  345. write(_writer, uint16_t(_primitives.size() ), _err);
  346. for (PrimitiveArray::const_iterator primIt = _primitives.begin(); primIt != _primitives.end(); ++primIt)
  347. {
  348. const Primitive& prim = *primIt;
  349. nameLen = uint16_t(prim.m_name.size() );
  350. write(_writer, nameLen, _err);
  351. write(_writer, prim.m_name.c_str(), nameLen, _err);
  352. write(_writer, prim.m_startIndex, _err);
  353. write(_writer, prim.m_numIndices, _err);
  354. write(_writer, prim.m_startVertex, _err);
  355. write(_writer, prim.m_numVertices, _err);
  356. write(_writer, &_vertices[prim.m_startVertex*stride], prim.m_numVertices, stride, _err);
  357. }
  358. }
  359. inline uint32_t rgbaToAbgr(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a)
  360. {
  361. return (uint32_t(_r)<<0)
  362. | (uint32_t(_g)<<8)
  363. | (uint32_t(_b)<<16)
  364. | (uint32_t(_a)<<24)
  365. ;
  366. }
  367. struct GroupSortByMaterial
  368. {
  369. bool operator()(const Group& _lhs, const Group& _rhs)
  370. {
  371. return 0 < bx::strCmp(_lhs.m_material.c_str(), _rhs.m_material.c_str() );
  372. }
  373. };
  374. void mtxCoordinateTransform(float* _result, const CoordinateSystem& _cs)
  375. {
  376. bx::Vec3 up = s_axisVectors[_cs.m_up];
  377. bx::Vec3 forward = s_axisVectors[_cs.m_forward];
  378. bx::Vec3 right = cross(forward,up);
  379. if (_cs.m_handness == bx::Handness::Left)
  380. {
  381. right = bx::mul(right, -1.0f);
  382. }
  383. bx::mtxIdentity(_result);
  384. bx::store(&_result[0], right);
  385. bx::store(&_result[4], forward);
  386. bx::store(&_result[8], up);
  387. }
  388. float mtxDeterminant(const float* _a)
  389. {
  390. const float xx = _a[ 0];
  391. const float xy = _a[ 1];
  392. const float xz = _a[ 2];
  393. const float xw = _a[ 3];
  394. const float yx = _a[ 4];
  395. const float yy = _a[ 5];
  396. const float yz = _a[ 6];
  397. const float yw = _a[ 7];
  398. const float zx = _a[ 8];
  399. const float zy = _a[ 9];
  400. const float zz = _a[10];
  401. const float zw = _a[11];
  402. const float wx = _a[12];
  403. const float wy = _a[13];
  404. const float wz = _a[14];
  405. const float ww = _a[15];
  406. float det = 0.0f;
  407. det += xx * (yy*(zz*ww - zw*wz) - yz*(zy*ww - zw*wy) + yw*(zy*wz - zz*wy) );
  408. det -= xy * (yx*(zz*ww - zw*wz) - yz*(zx*ww - zw*wx) + yw*(zx*wz - zz*wx) );
  409. det += xz * (yx*(zy*ww - zw*wy) - yy*(zx*ww - zw*wx) + yw*(zx*wy - zy*wx) );
  410. det -= xw * (yx*(zy*wz - zz*wy) - yy*(zx*wz - zz*wx) + yz*(zx*wy - zy*wx) );
  411. return det;
  412. }
  413. void parseObj(char* _data, uint32_t _size, Mesh* _mesh, bool _hasBc)
  414. {
  415. // Reference(s):
  416. // - Wavefront .obj file
  417. // https://en.wikipedia.org/wiki/Wavefront_.obj_file
  418. // Coordinate system is right-handed, but up/forward is not defined, but +Y Up, +Z Forward seems to be a common default
  419. _mesh->m_coordinateSystem.m_handness = bx::Handness::Right;
  420. _mesh->m_coordinateSystem.m_up = Axis::PositiveY;
  421. _mesh->m_coordinateSystem.m_forward = Axis::PositiveZ;
  422. uint32_t num = 0;
  423. Group group;
  424. group.m_startTriangle = 0;
  425. group.m_numTriangles = 0;
  426. char commandLine[2048];
  427. uint32_t len = sizeof(commandLine);
  428. int argc;
  429. char* argv[64];
  430. for (bx::StringView next(_data, _size); !next.isEmpty(); )
  431. {
  432. next = bx::tokenizeCommandLine(next, commandLine, len, argc, argv, BX_COUNTOF(argv), '\n');
  433. if (0 < argc)
  434. {
  435. if (0 == bx::strCmp(argv[0], "#") )
  436. {
  437. if (2 < argc
  438. && 0 == bx::strCmp(argv[2], "polygons") )
  439. {
  440. }
  441. }
  442. else if (0 == bx::strCmp(argv[0], "f") )
  443. {
  444. TriIndices triangle;
  445. bx::memSet(&triangle, 0, sizeof(TriIndices) );
  446. const int numNormals = (int)_mesh->m_normals.size();
  447. const int numTexcoords = (int)_mesh->m_texcoords.size();
  448. const int numPositions = (int)_mesh->m_positions.size();
  449. for (uint32_t edge = 0, numEdges = argc-1; edge < numEdges; ++edge)
  450. {
  451. Index3 index;
  452. index.m_texcoord = -1;
  453. index.m_normal = -1;
  454. if (_hasBc)
  455. {
  456. index.m_vbc = edge < 3 ? edge : (1+(edge+1) )&1;
  457. }
  458. else
  459. {
  460. index.m_vbc = 0;
  461. }
  462. {
  463. bx::StringView triplet(argv[edge + 1]);
  464. bx::StringView vertex(triplet);
  465. bx::StringView texcoord = bx::strFind(triplet, '/');
  466. if (!texcoord.isEmpty() )
  467. {
  468. vertex.set(vertex.getPtr(), texcoord.getPtr() );
  469. const bx::StringView normal = bx::strFind(bx::StringView(texcoord.getPtr() + 1, triplet.getTerm() ), '/');
  470. if (!normal.isEmpty() )
  471. {
  472. int32_t nn;
  473. bx::fromString(&nn, bx::StringView(normal.getPtr() + 1, triplet.getTerm() ) );
  474. index.m_normal = (nn < 0) ? nn + numNormals : nn - 1;
  475. }
  476. texcoord.set(texcoord.getPtr() + 1, normal.getPtr() );
  477. // Reference(s):
  478. // - Wavefront .obj file / Vertex normal indices without texture coordinate indices
  479. // https://en.wikipedia.org/wiki/Wavefront_.obj_file#Vertex_Normal_Indices_Without_Texture_Coordinate_Indices
  480. if (!texcoord.isEmpty() )
  481. {
  482. int32_t tex;
  483. bx::fromString(&tex, texcoord);
  484. index.m_texcoord = (tex < 0) ? tex + numTexcoords : tex - 1;
  485. }
  486. }
  487. int32_t pos;
  488. bx::fromString(&pos, vertex);
  489. index.m_position = (pos < 0) ? pos + numPositions : pos - 1;
  490. }
  491. switch (edge)
  492. {
  493. case 0: case 1: case 2:
  494. triangle.m_index[edge] = index;
  495. if (2 == edge)
  496. {
  497. _mesh->m_triangles.push_back(triangle);
  498. }
  499. break;
  500. default:
  501. triangle.m_index[1] = triangle.m_index[2];
  502. triangle.m_index[2] = index;
  503. _mesh->m_triangles.push_back(triangle);
  504. break;
  505. }
  506. }
  507. }
  508. else if (0 == bx::strCmp(argv[0], "g") )
  509. {
  510. group.m_name = argv[1];
  511. }
  512. else if (*argv[0] == 'v')
  513. {
  514. group.m_numTriangles = (uint32_t)(_mesh->m_triangles.size() ) - group.m_startTriangle;
  515. if (0 < group.m_numTriangles)
  516. {
  517. _mesh->m_groups.push_back(group);
  518. group.m_startTriangle = (uint32_t)(_mesh->m_triangles.size() );
  519. group.m_numTriangles = 0;
  520. }
  521. if (0 == bx::strCmp(argv[0], "vn") )
  522. {
  523. bx::Vec3 normal(bx::init::None);
  524. bx::fromString(&normal.x, argv[1]);
  525. bx::fromString(&normal.y, argv[2]);
  526. bx::fromString(&normal.z, argv[3]);
  527. _mesh->m_normals.push_back(normal);
  528. }
  529. else if (0 == bx::strCmp(argv[0], "vp") )
  530. {
  531. static bool once = true;
  532. if (once)
  533. {
  534. once = false;
  535. bx::printf("warning: 'parameter space vertices' are unsupported.\n");
  536. }
  537. }
  538. else if (0 == bx::strCmp(argv[0], "vt") )
  539. {
  540. bx::Vec3 texcoord(bx::init::None);
  541. texcoord.y = 0.0f;
  542. texcoord.z = 0.0f;
  543. bx::fromString(&texcoord.x, argv[1]);
  544. switch (argc)
  545. {
  546. case 4:
  547. bx::fromString(&texcoord.z, argv[3]);
  548. BX_FALLTHROUGH;
  549. case 3:
  550. bx::fromString(&texcoord.y, argv[2]);
  551. break;
  552. default:
  553. break;
  554. }
  555. _mesh->m_texcoords.push_back(texcoord);
  556. }
  557. else
  558. {
  559. float px, py, pz, pw;
  560. bx::fromString(&px, argv[1]);
  561. bx::fromString(&py, argv[2]);
  562. bx::fromString(&pz, argv[3]);
  563. if (argc == 5 || argc == 8)
  564. {
  565. bx::fromString(&pw, argv[4]);
  566. }
  567. else
  568. {
  569. pw = 1.0f;
  570. }
  571. bx::Vec3 pos(px, py, pz);
  572. const float invW = bx::rcp(pw);
  573. pos = bx::mul(pos, invW);
  574. _mesh->m_positions.push_back(pos);
  575. }
  576. }
  577. else if (0 == bx::strCmp(argv[0], "usemtl") )
  578. {
  579. stl::string material(argv[1]);
  580. if (0 != bx::strCmp(material.c_str(), group.m_material.c_str() ) )
  581. {
  582. group.m_numTriangles = (uint32_t)(_mesh->m_triangles.size() ) - group.m_startTriangle;
  583. if (0 < group.m_numTriangles)
  584. {
  585. _mesh->m_groups.push_back(group);
  586. group.m_startTriangle = (uint32_t)(_mesh->m_triangles.size() );
  587. group.m_numTriangles = 0;
  588. }
  589. }
  590. group.m_material = material;
  591. }
  592. // unsupported tags
  593. // else if (0 == bx::strCmp(argv[0], "mtllib") )
  594. // {
  595. // }
  596. // else if (0 == bx::strCmp(argv[0], "o") )
  597. // {
  598. // }
  599. // else if (0 == bx::strCmp(argv[0], "s") )
  600. // {
  601. // }
  602. }
  603. ++num;
  604. }
  605. group.m_numTriangles = (uint32_t)(_mesh->m_triangles.size() ) - group.m_startTriangle;
  606. if (0 < group.m_numTriangles)
  607. {
  608. _mesh->m_groups.push_back(group);
  609. group.m_startTriangle = (uint32_t)(_mesh->m_triangles.size() );
  610. group.m_numTriangles = 0;
  611. }
  612. bx::printf("obj parser # %d\n", num);
  613. }
  614. void gltfReadFloat(const float* _accessorData, cgltf_size _accessorNumComponents, cgltf_size _index, cgltf_float* _out, cgltf_size _outElementSize)
  615. {
  616. const float* input = &_accessorData[_accessorNumComponents * _index];
  617. for (cgltf_size ii = 0; ii < _outElementSize; ++ii)
  618. {
  619. _out[ii] = (ii < _accessorNumComponents) ? input[ii] : 0.0f;
  620. }
  621. }
  622. void processGltfNode(cgltf_node* _node, Mesh* _mesh, Group* _group, bool _hasBc)
  623. {
  624. cgltf_mesh* mesh = _node->mesh;
  625. if (NULL != mesh)
  626. {
  627. float nodeToWorld[16];
  628. cgltf_node_transform_world(_node, nodeToWorld);
  629. float nodeToWorldNormal[16];
  630. bx::mtxCofactor(nodeToWorldNormal, nodeToWorld);
  631. for (cgltf_size primitiveIndex = 0; primitiveIndex < mesh->primitives_count; ++primitiveIndex)
  632. {
  633. cgltf_primitive* primitive = &mesh->primitives[primitiveIndex];
  634. cgltf_size numVertex = primitive->attributes[0].data->count;
  635. int32_t basePositionIndex = (int32_t)_mesh->m_positions.size();
  636. int32_t baseNormalIndex = (int32_t)_mesh->m_normals.size();
  637. int32_t baseTexcoordIndex = (int32_t)_mesh->m_texcoords.size();
  638. bool hasNormal = false;
  639. bool hasTexcoord = false;
  640. for (cgltf_size attributeIndex = 0; attributeIndex < primitive->attributes_count; ++attributeIndex)
  641. {
  642. cgltf_attribute* attribute = &primitive->attributes[attributeIndex];
  643. cgltf_accessor* accessor = attribute->data;
  644. cgltf_size accessorCount = accessor->count;
  645. BX_ASSERT(numVertex == accessorCount, "Invalid attribute count");
  646. cgltf_size floatCount = cgltf_accessor_unpack_floats(accessor, NULL, 0);
  647. float* accessorData = (float*)malloc(floatCount * sizeof(float) );
  648. cgltf_accessor_unpack_floats(accessor, accessorData, floatCount);
  649. cgltf_size numComponents = cgltf_num_components(accessor->type);
  650. if (attribute->type == cgltf_attribute_type_position && attribute->index == 0)
  651. {
  652. _mesh->m_positions.reserve(_mesh->m_positions.size() + accessorCount);
  653. bx::Vec3 pos(bx::init::None);
  654. for (cgltf_size v = 0; v < accessorCount; ++v)
  655. {
  656. gltfReadFloat(accessorData, numComponents, v, &pos.x, 3);
  657. pos = mul(pos, nodeToWorld);
  658. _mesh->m_positions.push_back(pos);
  659. }
  660. }
  661. else if (attribute->type == cgltf_attribute_type_normal && attribute->index == 0)
  662. {
  663. _mesh->m_normals.reserve(_mesh->m_normals.size() + accessorCount);
  664. hasNormal = true;
  665. bx::Vec3 normal(bx::init::None);
  666. for (cgltf_size v = 0; v < accessorCount; ++v)
  667. {
  668. gltfReadFloat(accessorData, numComponents, v, &normal.x, 3);
  669. normal = mul(normal, nodeToWorldNormal);
  670. _mesh->m_normals.push_back(normal);
  671. }
  672. }
  673. else if (attribute->type == cgltf_attribute_type_texcoord && attribute->index == 0)
  674. {
  675. _mesh->m_texcoords.reserve(_mesh->m_texcoords.size() + accessorCount);
  676. hasTexcoord = true;
  677. bx::Vec3 texcoord(bx::init::None);
  678. for (cgltf_size v = 0; v < accessorCount; ++v)
  679. {
  680. gltfReadFloat(accessorData, numComponents, v, &texcoord.x, 3);
  681. _mesh->m_texcoords.push_back(texcoord);
  682. }
  683. }
  684. free(accessorData);
  685. }
  686. if (primitive->indices != NULL)
  687. {
  688. cgltf_accessor* accessor = primitive->indices;
  689. for (cgltf_size v = 0; v < accessor->count; v += 3)
  690. {
  691. TriIndices triangle;
  692. for (int i = 0; i < 3; ++i)
  693. {
  694. Index3 index;
  695. int32_t vertexIndex = int32_t(cgltf_accessor_read_index(accessor, v+i) );
  696. index.m_position = basePositionIndex + vertexIndex;
  697. index.m_normal = hasNormal ? baseNormalIndex + vertexIndex : -1;
  698. index.m_texcoord = hasTexcoord ? baseTexcoordIndex + vertexIndex : -1;
  699. index.m_vbc = _hasBc ? i : 0;
  700. triangle.m_index[i] = index;
  701. }
  702. _mesh->m_triangles.push_back(triangle);
  703. }
  704. }
  705. else
  706. {
  707. for (cgltf_size v = 0; v < numVertex; v += 3)
  708. {
  709. TriIndices triangle;
  710. for (int i = 0; i < 3; ++i)
  711. {
  712. Index3 index;
  713. int32_t vertexIndex = int32_t(v * 3 + i);
  714. index.m_position = basePositionIndex + vertexIndex;
  715. index.m_normal = hasNormal ? baseNormalIndex + vertexIndex : -1;
  716. index.m_texcoord = hasTexcoord ? baseTexcoordIndex + vertexIndex : -1;
  717. index.m_vbc = _hasBc ? i : 0;
  718. triangle.m_index[i] = index;
  719. }
  720. _mesh->m_triangles.push_back(triangle);
  721. }
  722. }
  723. _group->m_numTriangles = (uint32_t)(_mesh->m_triangles.size() ) - _group->m_startTriangle;
  724. if (0 < _group->m_numTriangles)
  725. {
  726. _mesh->m_groups.push_back(*_group);
  727. _group->m_startTriangle = (uint32_t)(_mesh->m_triangles.size() );
  728. _group->m_numTriangles = 0;
  729. }
  730. }
  731. }
  732. for (cgltf_size childIndex = 0; childIndex < _node->children_count; ++childIndex)
  733. processGltfNode(_node->children[childIndex], _mesh, _group, _hasBc);
  734. }
  735. void parseGltf(char* _data, uint32_t _size, Mesh* _mesh, bool _hasBc, const bx::StringView& _path)
  736. {
  737. // Reference(s):
  738. // - Gltf 2.0 specification
  739. // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0
  740. _mesh->m_coordinateSystem.m_handness = bx::Handness::Right;
  741. _mesh->m_coordinateSystem.m_forward = Axis::PositiveZ;
  742. _mesh->m_coordinateSystem.m_up = Axis::PositiveY;
  743. Group group;
  744. group.m_startTriangle = 0;
  745. group.m_numTriangles = 0;
  746. cgltf_options options = { };
  747. cgltf_data* data = NULL;
  748. cgltf_result result = cgltf_parse(&options, _data, _size, &data);
  749. if (result == cgltf_result_success)
  750. {
  751. char* path = (char*)malloc(_path.getLength()+1);
  752. bx::memCopy(path, _path.getPtr(), _path.getLength() );
  753. path[_path.getLength()] = 0;
  754. result = cgltf_load_buffers(&options, data, path);
  755. free(path);
  756. if (result == cgltf_result_success)
  757. {
  758. for (cgltf_size sceneIndex = 0; sceneIndex < data->scenes_count; ++sceneIndex)
  759. {
  760. cgltf_scene* scene = &data->scenes[sceneIndex];
  761. for (cgltf_size nodeIndex = 0; nodeIndex < scene->nodes_count; ++nodeIndex)
  762. {
  763. cgltf_node* node = scene->nodes[nodeIndex];
  764. processGltfNode(node, _mesh, &group, _hasBc);
  765. }
  766. }
  767. }
  768. cgltf_free(data);
  769. }
  770. }
  771. void help(const char* _error = NULL)
  772. {
  773. if (NULL != _error)
  774. {
  775. bx::printf("Error:\n%s\n\n", _error);
  776. }
  777. bx::printf(
  778. "geometryc, bgfx geometry compiler tool, version %d.%d.%d.\n"
  779. "Copyright 2011-2022 Branimir Karadzic. All rights reserved.\n"
  780. "License: https://github.com/bkaradzic/bgfx/blob/master/LICENSE\n\n"
  781. , BGFX_GEOMETRYC_VERSION_MAJOR
  782. , BGFX_GEOMETRYC_VERSION_MINOR
  783. , BGFX_API_VERSION
  784. );
  785. bx::printf(
  786. "Usage: geometryc -f <in> -o <out>\n"
  787. "\n"
  788. "Supported input file types:\n"
  789. " *.obj Wavefront\n"
  790. " *.gltf,*.glb glTF 2.0\n"
  791. "\n"
  792. "Options:\n"
  793. " -h, --help Display this help and exit.\n"
  794. " -v, --version Output version information and exit.\n"
  795. " -f <file path> Input's file path.\n"
  796. " -o <file path> Output's file path.\n"
  797. " -s, --scale <num> Scale factor.\n"
  798. " --ccw Front face is counter-clockwise winding order.\n"
  799. " --flipv Flip texture coordinate V.\n"
  800. " --obb <num> Number of steps for calculating oriented bounding box.\n"
  801. " Defaults to 17.\n"
  802. " Less steps = less precise OBB.\n"
  803. " More steps = slower calculation.\n"
  804. " --packnormal <num> Normal packing.\n"
  805. " 0 - unpacked 12 bytes. (default)\n"
  806. " 1 - packed 4 bytes.\n"
  807. " --packuv <num> Texture coordinate packing.\n"
  808. " 0 - unpacked 8 bytes. (default)\n"
  809. " 1 - packed 4 bytes.\n"
  810. " --tangent Calculate tangent vectors. (packing mode is the same as normal)\n"
  811. " --barycentric Adds barycentric vertex attribute. (Packed in bgfx::Attrib::Color1)\n"
  812. " -c, --compress Compress indices.\n"
  813. " --[l/r]h-up+[y/z] Coordinate system. Defaults to '--lh-up+y' — Left-Handed +Y is up.\n"
  814. "\n"
  815. "For additional information, see https://github.com/bkaradzic/bgfx\n"
  816. );
  817. }
  818. int main(int _argc, const char* _argv[])
  819. {
  820. bx::CommandLine cmdLine(_argc, _argv);
  821. if (cmdLine.hasArg('v', "version") )
  822. {
  823. bx::printf(
  824. "geometryc, bgfx geometry compiler tool, version %d.%d.%d.\n"
  825. , BGFX_GEOMETRYC_VERSION_MAJOR
  826. , BGFX_GEOMETRYC_VERSION_MINOR
  827. , BGFX_API_VERSION
  828. );
  829. return bx::kExitSuccess;
  830. }
  831. if (cmdLine.hasArg('h', "help") )
  832. {
  833. help();
  834. return bx::kExitFailure;
  835. }
  836. const char* filePath = cmdLine.findOption('f');
  837. if (NULL == filePath)
  838. {
  839. help("Input file name must be specified.");
  840. return bx::kExitFailure;
  841. }
  842. const char* outFilePath = cmdLine.findOption('o');
  843. if (NULL == outFilePath)
  844. {
  845. help("Output file name must be specified.");
  846. return bx::kExitFailure;
  847. }
  848. float scale = 1.0f;
  849. const char* scaleArg = cmdLine.findOption('s', "scale");
  850. if (NULL != scaleArg)
  851. {
  852. if (!bx::fromString(&scale, scaleArg) )
  853. {
  854. scale = 1.0f;
  855. }
  856. }
  857. bool compress = cmdLine.hasArg('c', "compress");
  858. cmdLine.hasArg(s_obbSteps, '\0', "obb");
  859. s_obbSteps = bx::uint32_min(bx::uint32_max(s_obbSteps, 1), 90);
  860. uint32_t packNormal = 0;
  861. cmdLine.hasArg(packNormal, '\0', "packnormal");
  862. uint32_t packUv = 0;
  863. cmdLine.hasArg(packUv, '\0', "packuv");
  864. bool ccw = cmdLine.hasArg("ccw");
  865. bool flipV = cmdLine.hasArg("flipv");
  866. bool hasTangent = cmdLine.hasArg("tangent");
  867. bool hasBc = cmdLine.hasArg("barycentric");
  868. CoordinateSystem outputCoordinateSystem;
  869. outputCoordinateSystem.m_handness = bx::Handness::Left;
  870. outputCoordinateSystem.m_forward = Axis::PositiveZ;
  871. outputCoordinateSystem.m_up = Axis::PositiveY;
  872. for (uint32_t ii = 0; ii < BX_COUNTOF(s_coordinateSystemMappings); ++ii)
  873. {
  874. if (cmdLine.hasArg(s_coordinateSystemMappings[ii].m_param) )
  875. {
  876. outputCoordinateSystem = s_coordinateSystemMappings[ii].m_coordinateSystem;
  877. }
  878. }
  879. bx::FileReader fr;
  880. if (!bx::open(&fr, filePath) )
  881. {
  882. bx::printf("Unable to open input file '%s'.", filePath);
  883. return bx::kExitFailure;
  884. }
  885. int64_t parseElapsed = -bx::getHPCounter();
  886. int64_t triReorderElapsed = 0;
  887. uint32_t size = (uint32_t)bx::getSize(&fr);
  888. char* data = new char[size+1];
  889. size = bx::read(&fr, data, size, bx::ErrorAssert{});
  890. data[size] = '\0';
  891. bx::close(&fr);
  892. Mesh mesh;
  893. bx::StringView ext = bx::FilePath(filePath).getExt();
  894. if (0 == bx::strCmpI(ext, ".obj") )
  895. {
  896. parseObj(data, size, &mesh, hasBc);
  897. }
  898. else if (0 == bx::strCmpI(ext, ".gltf") || 0 == bx::strCmpI(ext, ".glb") )
  899. {
  900. parseGltf(data, size, &mesh, hasBc, bx::FilePath(filePath).getPath() );
  901. }
  902. else
  903. {
  904. bx::printf("Unsupported input file format '%s'.", filePath);
  905. exit(bx::kExitFailure);
  906. }
  907. delete [] data;
  908. int64_t now = bx::getHPCounter();
  909. parseElapsed += now;
  910. int64_t convertElapsed = -now;
  911. std::sort(mesh.m_groups.begin(), mesh.m_groups.end(), GroupSortByMaterial() );
  912. bool changeWinding = ccw;
  913. if (scale != 1.0f)
  914. {
  915. for (Vec3Array::iterator it = mesh.m_positions.begin(), itEnd = mesh.m_positions.end(); it != itEnd; ++it)
  916. {
  917. it->x *= scale;
  918. it->y *= scale;
  919. it->z *= scale;
  920. }
  921. }
  922. {
  923. float meshTransform[16];
  924. mtxCoordinateTransform(meshTransform, mesh.m_coordinateSystem);
  925. float meshInvTranform[16];
  926. bx::mtxTranspose(meshInvTranform, meshTransform);
  927. float outTransform[16];
  928. mtxCoordinateTransform(outTransform, outputCoordinateSystem);
  929. float transform[16];
  930. bx::mtxMul(transform, meshInvTranform, outTransform);
  931. if ( mtxDeterminant(transform) < 0.0f )
  932. {
  933. changeWinding = !changeWinding;
  934. }
  935. float identity[16];
  936. bx::mtxIdentity(identity);
  937. if ( 0 != bx::memCmp(identity, transform, sizeof(transform) ) )
  938. {
  939. for (Vec3Array::iterator it = mesh.m_positions.begin(), itEnd = mesh.m_positions.end(); it != itEnd; ++it)
  940. {
  941. *it = bx::mul(*it, transform);
  942. }
  943. for (Vec3Array::iterator it = mesh.m_normals.begin(), itEnd = mesh.m_normals.end(); it != itEnd; ++it)
  944. {
  945. *it = bx::mul(*it, transform);
  946. }
  947. }
  948. }
  949. bool hasColor = false;
  950. bool hasNormal = false;
  951. bool hasTexcoord = false;
  952. {
  953. for (TriangleArray::iterator jt = mesh.m_triangles.begin(), jtEnd = mesh.m_triangles.end(); jt != jtEnd && !hasTexcoord; ++jt)
  954. {
  955. for (uint32_t i = 0; i < 3; ++i)
  956. {
  957. hasTexcoord |= -1 != jt->m_index[i].m_texcoord;
  958. }
  959. }
  960. for (TriangleArray::iterator jt = mesh.m_triangles.begin(), jtEnd = mesh.m_triangles.end(); jt != jtEnd && !hasNormal; ++jt)
  961. {
  962. for (uint32_t i = 0; i < 3; ++i)
  963. {
  964. hasNormal |= -1 != jt->m_index[i].m_normal;
  965. }
  966. }
  967. if (changeWinding)
  968. {
  969. for (TriangleArray::iterator jt = mesh.m_triangles.begin(), jtEnd = mesh.m_triangles.end(); jt != jtEnd; ++jt)
  970. {
  971. bx::swap(jt->m_index[1], jt->m_index[2]);
  972. }
  973. }
  974. }
  975. bgfx::VertexLayout layout;
  976. layout.begin();
  977. layout.add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float);
  978. if (hasColor)
  979. {
  980. layout.add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true);
  981. }
  982. if (hasBc)
  983. {
  984. layout.add(bgfx::Attrib::Color1, 4, bgfx::AttribType::Uint8, true);
  985. }
  986. if (hasTexcoord)
  987. {
  988. switch (packUv)
  989. {
  990. default:
  991. case 0:
  992. layout.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float);
  993. break;
  994. case 1:
  995. layout.add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Half);
  996. break;
  997. }
  998. }
  999. if (hasNormal)
  1000. {
  1001. hasTangent &= hasTexcoord;
  1002. switch (packNormal)
  1003. {
  1004. default:
  1005. case 0:
  1006. layout.add(bgfx::Attrib::Normal, 3, bgfx::AttribType::Float);
  1007. if (hasTangent)
  1008. {
  1009. layout.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Float);
  1010. }
  1011. break;
  1012. case 1:
  1013. layout.add(bgfx::Attrib::Normal, 4, bgfx::AttribType::Uint8, true, true);
  1014. if (hasTangent)
  1015. {
  1016. layout.add(bgfx::Attrib::Tangent, 4, bgfx::AttribType::Uint8, true, true);
  1017. }
  1018. break;
  1019. }
  1020. }
  1021. layout.end();
  1022. uint32_t stride = layout.getStride();
  1023. uint8_t* vertexData = new uint8_t[mesh.m_triangles.size() * 3 * stride];
  1024. uint16_t* indexData = new uint16_t[mesh.m_triangles.size() * 3];
  1025. int32_t numVertices = 0;
  1026. int32_t numIndices = 0;
  1027. int32_t writtenPrimitives = 0;
  1028. int32_t writtenVertices = 0;
  1029. int32_t writtenIndices = 0;
  1030. uint8_t* vertices = vertexData;
  1031. uint16_t* indices = indexData;
  1032. const uint32_t tableSize = 65536 * 2;
  1033. const uint32_t hashmod = tableSize - 1;
  1034. uint32_t* table = new uint32_t[tableSize];
  1035. bx::memSet(table, 0xff, tableSize * sizeof(uint32_t) );
  1036. stl::string material = mesh.m_groups.empty() ? "" : mesh.m_groups.begin()->m_material;
  1037. PrimitiveArray primitives;
  1038. bx::FileWriter writer;
  1039. if (!bx::open(&writer, outFilePath) )
  1040. {
  1041. bx::printf("Unable to open output file '%s'.", outFilePath);
  1042. exit(bx::kExitFailure);
  1043. }
  1044. Primitive prim;
  1045. prim.m_startVertex = 0;
  1046. prim.m_startIndex = 0;
  1047. uint32_t positionOffset = layout.getOffset(bgfx::Attrib::Position);
  1048. uint32_t color0Offset = layout.getOffset(bgfx::Attrib::Color0);
  1049. Group sentinelGroup;
  1050. sentinelGroup.m_startTriangle = 0;
  1051. sentinelGroup.m_numTriangles = UINT32_MAX;
  1052. mesh.m_groups.push_back(sentinelGroup);
  1053. bx::Error err;
  1054. uint32_t ii = 0;
  1055. for (GroupArray::const_iterator groupIt = mesh.m_groups.begin(); groupIt != mesh.m_groups.end(); ++groupIt, ++ii)
  1056. {
  1057. const bool sentinel = groupIt->m_startTriangle == 0 && groupIt->m_numTriangles == UINT32_MAX;
  1058. for (uint32_t tri = groupIt->m_startTriangle, end = tri + groupIt->m_numTriangles; tri < end; ++tri)
  1059. {
  1060. if (0 != bx::strCmp(material.c_str(), groupIt->m_material.c_str() )
  1061. || sentinel
  1062. || 65533 <= numVertices)
  1063. {
  1064. prim.m_numVertices = numVertices - prim.m_startVertex;
  1065. prim.m_numIndices = numIndices - prim.m_startIndex;
  1066. if (0 < prim.m_numVertices)
  1067. {
  1068. primitives.push_back(prim);
  1069. }
  1070. if (hasTangent)
  1071. {
  1072. calcTangents(vertexData, uint16_t(numVertices), layout, indexData, numIndices);
  1073. }
  1074. triReorderElapsed -= bx::getHPCounter();
  1075. for (PrimitiveArray::const_iterator primIt = primitives.begin(); primIt != primitives.end(); ++primIt)
  1076. {
  1077. const Primitive& prim1 = *primIt;
  1078. optimizeVertexCache(indexData + prim1.m_startIndex, prim1.m_numIndices, numVertices);
  1079. }
  1080. numVertices = optimizeVertexFetch(indexData, numIndices, vertexData, numVertices, uint16_t(stride) );
  1081. triReorderElapsed += bx::getHPCounter();
  1082. if (0 < numVertices
  1083. && 0 < numIndices)
  1084. {
  1085. write(&writer
  1086. , vertexData
  1087. , numVertices
  1088. , layout
  1089. , indexData
  1090. , numIndices
  1091. , compress
  1092. , material
  1093. , primitives
  1094. , &err
  1095. );
  1096. }
  1097. primitives.clear();
  1098. bx::memSet(table, 0xff, tableSize * sizeof(uint32_t) );
  1099. ++writtenPrimitives;
  1100. writtenVertices += numVertices;
  1101. writtenIndices += numIndices;
  1102. vertices = vertexData;
  1103. indices = indexData;
  1104. numVertices = 0;
  1105. numIndices = 0;
  1106. prim.m_startVertex = 0;
  1107. prim.m_startIndex = 0;
  1108. material = groupIt->m_material;
  1109. if (sentinel)
  1110. {
  1111. break;
  1112. }
  1113. }
  1114. TriIndices& triangle = mesh.m_triangles[tri];
  1115. for (uint32_t edge = 0; edge < 3; ++edge)
  1116. {
  1117. Index3& index = triangle.m_index[edge];
  1118. float* position = (float*)(vertices + positionOffset);
  1119. bx::memCopy(position, &mesh.m_positions[index.m_position], 3*sizeof(float) );
  1120. if (hasColor)
  1121. {
  1122. uint32_t* color0 = (uint32_t*)(vertices + color0Offset);
  1123. *color0 = rgbaToAbgr(numVertices%255, numIndices%255, 0, 0xff);
  1124. }
  1125. if (hasBc)
  1126. {
  1127. const float bc[4] =
  1128. {
  1129. (index.m_vbc == 0) ? 1.0f : 0.0f,
  1130. (index.m_vbc == 1) ? 1.0f : 0.0f,
  1131. (index.m_vbc == 2) ? 1.0f : 0.0f,
  1132. 0.0f
  1133. };
  1134. bgfx::vertexPack(bc, true, bgfx::Attrib::Color1, layout, vertices);
  1135. }
  1136. if (hasTexcoord)
  1137. {
  1138. float uv[2];
  1139. bx::memCopy(uv, &mesh.m_texcoords[index.m_texcoord == -1 ? 0 : index.m_texcoord], 2*sizeof(float) );
  1140. if (flipV)
  1141. {
  1142. uv[1] = -uv[1];
  1143. }
  1144. bgfx::vertexPack(uv, true, bgfx::Attrib::TexCoord0, layout, vertices);
  1145. }
  1146. if (hasNormal)
  1147. {
  1148. float normal[4];
  1149. bx::store(normal, bx::normalize(bx::load<bx::Vec3>(&mesh.m_normals[index.m_normal == -1 ? 0 : index.m_normal]) ) );
  1150. normal[3] = 0.0f;
  1151. bgfx::vertexPack(normal, true, bgfx::Attrib::Normal, layout, vertices);
  1152. }
  1153. uint32_t hash = bx::hash<bx::HashMurmur2A>(vertices, stride);
  1154. size_t bucket = hash & hashmod;
  1155. uint32_t vertexIndex = UINT32_MAX;
  1156. for (size_t probe = 0; probe <= hashmod; ++probe)
  1157. {
  1158. uint32_t& item = table[bucket];
  1159. if (item == ~0u)
  1160. {
  1161. vertices += stride;
  1162. item = numVertices++;
  1163. vertexIndex = item;
  1164. break;
  1165. }
  1166. if (0 == bx::memCmp(vertexData + item * stride, vertices, stride) )
  1167. {
  1168. vertexIndex = item;
  1169. break;
  1170. }
  1171. bucket = (bucket + probe + 1) & hashmod;
  1172. }
  1173. if ( vertexIndex == UINT32_MAX )
  1174. {
  1175. bx::printf("hash table insert failed");
  1176. exit(bx::kExitFailure);
  1177. }
  1178. *indices++ = (uint16_t)vertexIndex;
  1179. ++numIndices;
  1180. }
  1181. }
  1182. prim.m_numVertices = numVertices - prim.m_startVertex;
  1183. if (0 < prim.m_numVertices)
  1184. {
  1185. prim.m_numIndices = numIndices - prim.m_startIndex;
  1186. prim.m_name = groupIt->m_name;
  1187. primitives.push_back(prim);
  1188. prim.m_startVertex = numVertices;
  1189. prim.m_startIndex = numIndices;
  1190. }
  1191. BX_TRACE("%3d: s %5d, n %5d, %s\n"
  1192. , ii
  1193. , groupIt->m_startTriangle
  1194. , groupIt->m_numTriangles
  1195. , groupIt->m_material.c_str()
  1196. );
  1197. }
  1198. BX_ASSERT(0 == primitives.size(), "Not all primitives are written");
  1199. bx::printf("size: %d\n", uint32_t(bx::seek(&writer) ) );
  1200. bx::close(&writer);
  1201. delete [] table;
  1202. delete [] indexData;
  1203. delete [] vertexData;
  1204. now = bx::getHPCounter();
  1205. convertElapsed += now;
  1206. bx::printf("parse %f [s]\ntri reorder %f [s]\nconvert %f [s]\ng %d, p %d, v %d, i %d\n"
  1207. , double(parseElapsed)/bx::getHPFrequency()
  1208. , double(triReorderElapsed)/bx::getHPFrequency()
  1209. , double(convertElapsed)/bx::getHPFrequency()
  1210. , uint32_t(mesh.m_groups.size()-1)
  1211. , writtenPrimitives
  1212. , writtenVertices
  1213. , writtenIndices
  1214. );
  1215. return bx::kExitSuccess;
  1216. }