2
0

topology.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * Copyright 2011-2017 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include <bx/allocator.h>
  6. #include <bx/debug.h>
  7. #include <bx/fpumath.h>
  8. #include <bx/sort.h>
  9. #include <bx/uint32_t.h>
  10. #include "config.h"
  11. #include "topology.h"
  12. namespace bgfx
  13. {
  14. template<typename IndexT>
  15. static uint32_t topologyConvertTriListFlipWinding(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices)
  16. {
  17. if (NULL == _dst)
  18. {
  19. return _numIndices;
  20. }
  21. IndexT* dst = (IndexT*)_dst;
  22. IndexT* end = &dst[_dstSize/sizeof(IndexT)];
  23. for (uint32_t ii = 0; ii < _numIndices && dst < end; ii += 3, dst += 3)
  24. {
  25. const IndexT* tri = &_indices[ii];
  26. IndexT i0 = tri[0], i1 = tri[1], i2 = tri[2];
  27. dst[0] = i0;
  28. dst[1] = i2;
  29. dst[2] = i1;
  30. }
  31. return _numIndices;
  32. }
  33. template<typename IndexT, typename SortT>
  34. static uint32_t topologyConvertTriListToLineList(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices, IndexT* _temp, SortT* _tempSort)
  35. {
  36. // Create all line pairs and sort indices.
  37. IndexT* dst = _temp;
  38. for (uint32_t ii = 0; ii < _numIndices; ii += 3)
  39. {
  40. const IndexT* tri = &_indices[ii];
  41. IndexT i0 = tri[0], i1 = tri[1], i2 = tri[2];
  42. if (i0 > i1) { bx::xchg(i0, i1); }
  43. if (i1 > i2) { bx::xchg(i1, i2); }
  44. if (i0 > i1) { bx::xchg(i0, i1); }
  45. BX_CHECK(i0 < i1 && i1 < i2, "");
  46. dst[0] = i0; dst[1] = i1;
  47. dst[2] = i1; dst[3] = i2;
  48. dst[4] = i0; dst[5] = i2;
  49. dst += 6;
  50. }
  51. // Sort all line pairs.
  52. SortT* sorted = (SortT*)_temp;
  53. bx::radixSort(sorted, _tempSort, _numIndices);
  54. uint32_t num = 0;
  55. // Remove all line pair duplicates.
  56. if (NULL == _dst)
  57. {
  58. SortT last = sorted[0];
  59. for (uint32_t ii = 1; ii < _numIndices; ++ii)
  60. {
  61. if (last != sorted[ii])
  62. {
  63. num += 2;
  64. last = sorted[ii];
  65. }
  66. }
  67. num += 2;
  68. }
  69. else
  70. {
  71. dst = (IndexT*)_dst;
  72. IndexT* end = &dst[_dstSize/sizeof(IndexT)];
  73. SortT last = sorted[0];
  74. for (uint32_t ii = 1; ii < _numIndices && dst < end; ++ii)
  75. {
  76. if (last != sorted[ii])
  77. {
  78. union Un { SortT key; struct { IndexT i0; IndexT i1; } u16; } un = { last };
  79. dst[0] = un.u16.i0;
  80. dst[1] = un.u16.i1;
  81. dst += 2;
  82. last = sorted[ii];
  83. }
  84. }
  85. if (dst < end)
  86. {
  87. union Un { SortT key; struct { IndexT i0; IndexT i1; } u16; } un = { last };
  88. dst[0] = un.u16.i0;
  89. dst[1] = un.u16.i1;
  90. dst += 2;
  91. }
  92. num = uint32_t(dst - (IndexT*)_dst);
  93. }
  94. return num;
  95. }
  96. template<typename IndexT, typename SortT>
  97. static uint32_t topologyConvertTriListToLineList(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices, bx::AllocatorI* _allocator)
  98. {
  99. IndexT* temp = (IndexT*)BX_ALLOC(_allocator, _numIndices*2*sizeof(IndexT)*2);
  100. SortT* tempSort = (SortT*)&temp[_numIndices*2];
  101. uint32_t num = topologyConvertTriListToLineList(_dst, _dstSize, _indices, _numIndices, temp, tempSort);
  102. BX_FREE(_allocator, temp);
  103. return num;
  104. }
  105. template<typename IndexT>
  106. static uint32_t topologyConvertTriStripToTriList(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices)
  107. {
  108. IndexT* dst = (IndexT*)_dst;
  109. IndexT* end = &dst[_dstSize/sizeof(IndexT)];
  110. for (uint32_t ii = 0, num = _numIndices-2; ii < num && dst < end; ++ii)
  111. {
  112. IndexT i0 = _indices[ii+0];
  113. IndexT i1 = _indices[ii+1];
  114. IndexT i2 = _indices[ii+2];
  115. if (i0 != i1
  116. && i1 != i2)
  117. {
  118. dst[0] = i0;
  119. dst[1] = i1;
  120. dst[2] = i2;
  121. dst += 3;
  122. }
  123. }
  124. return uint32_t(dst - (IndexT*)_dst);
  125. }
  126. template<typename IndexT>
  127. static uint32_t topologyConvertLineStripToLineList(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices)
  128. {
  129. IndexT* dst = (IndexT*)_dst;
  130. IndexT* end = &dst[_dstSize/sizeof(IndexT)];
  131. IndexT i0 = _indices[0];
  132. for (uint32_t ii = 1; ii < _numIndices && dst < end; ++ii)
  133. {
  134. IndexT i1 = _indices[ii];
  135. if (i0 != i1)
  136. {
  137. dst[0] = i0;
  138. dst[1] = i1;
  139. dst += 2;
  140. i0 = i1;
  141. }
  142. }
  143. return uint32_t(dst - (IndexT*)_dst);
  144. }
  145. uint32_t topologyConvert(
  146. TopologyConvert::Enum _conversion
  147. , void* _dst
  148. , uint32_t _dstSize
  149. , const void* _indices
  150. , uint32_t _numIndices
  151. , bool _index32
  152. , bx::AllocatorI* _allocator
  153. )
  154. {
  155. switch (_conversion)
  156. {
  157. case TopologyConvert::TriStripToTriList:
  158. if (_index32)
  159. {
  160. return topologyConvertTriStripToTriList(_dst, _dstSize, (const uint32_t*)_indices, _numIndices);
  161. }
  162. return topologyConvertTriStripToTriList(_dst, _dstSize, (const uint16_t*)_indices, _numIndices);
  163. case TopologyConvert::TriListFlipWinding:
  164. if (_index32)
  165. {
  166. return topologyConvertTriListFlipWinding(_dst, _dstSize, (const uint32_t*)_indices, _numIndices);
  167. }
  168. return topologyConvertTriListFlipWinding(_dst, _dstSize, (const uint16_t*)_indices, _numIndices);
  169. case TopologyConvert::TriListToLineList:
  170. if (NULL == _allocator)
  171. {
  172. return 0;
  173. }
  174. if (_index32)
  175. {
  176. return topologyConvertTriListToLineList<uint32_t, uint64_t>(_dst, _dstSize, (const uint32_t*)_indices, _numIndices, _allocator);
  177. }
  178. return topologyConvertTriListToLineList<uint16_t, uint32_t>(_dst, _dstSize, (const uint16_t*)_indices, _numIndices, _allocator);
  179. case TopologyConvert::LineStripToLineList:
  180. if (_index32)
  181. {
  182. return topologyConvertLineStripToLineList(_dst, _dstSize, (const uint32_t*)_indices, _numIndices);
  183. }
  184. return topologyConvertLineStripToLineList(_dst, _dstSize, (const uint16_t*)_indices, _numIndices);
  185. default:
  186. break;
  187. }
  188. return 0;
  189. }
  190. inline uint32_t floatFlip(uint32_t _value)
  191. {
  192. using namespace bx;
  193. const uint32_t tmp0 = uint32_sra(_value, 31);
  194. const uint32_t tmp1 = uint32_neg(tmp0);
  195. const uint32_t mask = uint32_or(tmp1, 0x80000000);
  196. const uint32_t result = uint32_xor(_value, mask);
  197. return result;
  198. }
  199. inline float favg3(float _a, float _b, float _c)
  200. {
  201. return (_a + _b + _c) * 1.0f/3.0f;
  202. }
  203. const float* vertexPos(const void* _vertices, uint32_t _stride, uint32_t _index)
  204. {
  205. const uint8_t* vertices = (const uint8_t*)_vertices;
  206. return (const float*)&vertices[_index*_stride];
  207. }
  208. inline float distanceDir(const float* __restrict _dir, const void* __restrict _vertices, uint32_t _stride, uint32_t _index)
  209. {
  210. return bx::vec3Dot(vertexPos(_vertices, _stride, _index), _dir);
  211. }
  212. inline float distancePos(const float* __restrict _pos, const void* __restrict _vertices, uint32_t _stride, uint32_t _index)
  213. {
  214. float tmp[3];
  215. bx::vec3Sub(tmp, _pos, vertexPos(_vertices, _stride, _index) );
  216. return bx::fsqrt(bx::vec3Dot(tmp, tmp) );
  217. }
  218. typedef float (*KeyFn)(float, float, float);
  219. typedef float (*DistanceFn)(const float*, const void*, uint32_t, uint32_t);
  220. template<typename IndexT, DistanceFn dfn, KeyFn kfn, uint32_t xorBits>
  221. inline void calcSortKeys(
  222. uint32_t* __restrict _keys
  223. , uint32_t* __restrict _values
  224. , const float _dirOrPos[3]
  225. , const void* __restrict _vertices
  226. , uint32_t _stride
  227. , const IndexT* _indices
  228. , uint32_t _num
  229. )
  230. {
  231. for (uint32_t ii = 0; ii < _num; ++ii)
  232. {
  233. const uint32_t idx0 = _indices[0];
  234. const uint32_t idx1 = _indices[1];
  235. const uint32_t idx2 = _indices[2];
  236. _indices += 3;
  237. float distance0 = dfn(_dirOrPos, _vertices, _stride, idx0);
  238. float distance1 = dfn(_dirOrPos, _vertices, _stride, idx1);
  239. float distance2 = dfn(_dirOrPos, _vertices, _stride, idx2);
  240. union { float fl; uint32_t ui; } un;
  241. un.fl = kfn(distance0, distance1, distance2);
  242. _keys[ii] = floatFlip(un.ui) ^ xorBits;
  243. _values[ii] = ii;
  244. }
  245. }
  246. template<typename IndexT>
  247. void topologySortTriList(
  248. TopologySort::Enum _sort
  249. , IndexT* _dst
  250. , uint32_t* _keys
  251. , uint32_t* _values
  252. , uint32_t* _tempKeys
  253. , uint32_t* _tempValues
  254. , uint32_t _num
  255. , const float _dir[3]
  256. , const float _pos[3]
  257. , const void* _vertices
  258. , uint32_t _stride
  259. , const IndexT* _indices
  260. )
  261. {
  262. using namespace bx;
  263. switch (_sort)
  264. {
  265. default:
  266. case TopologySort::DirectionFrontToBackMin: calcSortKeys<IndexT, distanceDir, fmin3, 0 >(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  267. case TopologySort::DirectionFrontToBackAvg: calcSortKeys<IndexT, distanceDir, favg3, 0 >(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  268. case TopologySort::DirectionFrontToBackMax: calcSortKeys<IndexT, distanceDir, fmax3, 0 >(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  269. case TopologySort::DirectionBackToFrontMin: calcSortKeys<IndexT, distanceDir, fmin3, UINT32_MAX>(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  270. case TopologySort::DirectionBackToFrontAvg: calcSortKeys<IndexT, distanceDir, favg3, UINT32_MAX>(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  271. case TopologySort::DirectionBackToFrontMax: calcSortKeys<IndexT, distanceDir, fmax3, UINT32_MAX>(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  272. case TopologySort::DistanceFrontToBackMin: calcSortKeys<IndexT, distancePos, fmin3, 0 >(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  273. case TopologySort::DistanceFrontToBackAvg: calcSortKeys<IndexT, distancePos, favg3, 0 >(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  274. case TopologySort::DistanceFrontToBackMax: calcSortKeys<IndexT, distancePos, fmax3, 0 >(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  275. case TopologySort::DistanceBackToFrontMin: calcSortKeys<IndexT, distancePos, fmin3, UINT32_MAX>(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  276. case TopologySort::DistanceBackToFrontAvg: calcSortKeys<IndexT, distancePos, favg3, UINT32_MAX>(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  277. case TopologySort::DistanceBackToFrontMax: calcSortKeys<IndexT, distancePos, fmax3, UINT32_MAX>(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  278. }
  279. radixSort(_keys, _tempKeys, _values, _tempValues, _num);
  280. IndexT* sorted = _dst;
  281. for (uint32_t ii = 0; ii < _num; ++ii)
  282. {
  283. uint32_t face = _values[ii]*3;
  284. const IndexT idx0 = _indices[face+0];
  285. const IndexT idx1 = _indices[face+1];
  286. const IndexT idx2 = _indices[face+2];
  287. sorted[0] = idx0;
  288. sorted[1] = idx1;
  289. sorted[2] = idx2;
  290. sorted += 3;
  291. }
  292. }
  293. void topologySortTriList(
  294. TopologySort::Enum _sort
  295. , void* _dst
  296. , uint32_t _dstSize
  297. , const float _dir[3]
  298. , const float _pos[3]
  299. , const void* _vertices
  300. , uint32_t _stride
  301. , const void* _indices
  302. , uint32_t _numIndices
  303. , bool _index32
  304. , bx::AllocatorI* _allocator
  305. )
  306. {
  307. uint32_t indexSize = _index32
  308. ? sizeof(uint32_t)
  309. : sizeof(uint16_t)
  310. ;
  311. uint32_t num = bx::uint32_min(_numIndices*indexSize, _dstSize)/(indexSize*3);
  312. uint32_t* temp = (uint32_t*)BX_ALLOC(_allocator, sizeof(uint32_t)*num*4);
  313. uint32_t* keys = &temp[num*0];
  314. uint32_t* values = &temp[num*1];
  315. uint32_t* tempKeys = &temp[num*2];
  316. uint32_t* tempValues = &temp[num*3];
  317. if (_index32)
  318. {
  319. topologySortTriList(
  320. _sort
  321. , (uint32_t*)_dst
  322. , keys
  323. , values
  324. , tempKeys
  325. , tempValues
  326. , num
  327. , _dir
  328. , _pos
  329. , _vertices
  330. , _stride
  331. , (const uint32_t*)_indices
  332. );
  333. }
  334. else
  335. {
  336. topologySortTriList(
  337. _sort
  338. , (uint16_t*)_dst
  339. , keys
  340. , values
  341. , tempKeys
  342. , tempValues
  343. , num
  344. , _dir
  345. , _pos
  346. , _vertices
  347. , _stride
  348. , (const uint16_t*)_indices
  349. );
  350. }
  351. BX_FREE(_allocator, temp);
  352. }
  353. } //namespace bgfx