geometryc.cpp 38 KB

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