topology.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * Copyright 2011-2018 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/math.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[1] = i0; dst[0] = i1;
  47. dst[3] = i1; dst[2] = i2;
  48. dst[5] = i0; dst[4] = 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. {
  75. union Un { SortT key; struct { IndexT i0; IndexT i1; } u16; } un = { sorted[0] };
  76. dst[0] = un.u16.i0;
  77. dst[1] = un.u16.i1;
  78. dst += 2;
  79. }
  80. for (uint32_t ii = 1; ii < _numIndices && dst < end; ++ii)
  81. {
  82. if (last != sorted[ii])
  83. {
  84. union Un { SortT key; struct { IndexT i0; IndexT i1; } u16; } un = { sorted[ii] };
  85. dst[0] = un.u16.i0;
  86. dst[1] = un.u16.i1;
  87. dst += 2;
  88. last = sorted[ii];
  89. }
  90. }
  91. num = uint32_t(dst - (IndexT*)_dst);
  92. }
  93. return num;
  94. }
  95. template<typename IndexT, typename SortT>
  96. static uint32_t topologyConvertTriListToLineList(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices, bx::AllocatorI* _allocator)
  97. {
  98. IndexT* temp = (IndexT*)BX_ALLOC(_allocator, _numIndices*2*sizeof(IndexT)*2);
  99. SortT* tempSort = (SortT*)&temp[_numIndices*2];
  100. uint32_t num = topologyConvertTriListToLineList(_dst, _dstSize, _indices, _numIndices, temp, tempSort);
  101. BX_FREE(_allocator, temp);
  102. return num;
  103. }
  104. template<typename IndexT>
  105. static uint32_t topologyConvertTriStripToTriList(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices)
  106. {
  107. IndexT* dst = (IndexT*)_dst;
  108. IndexT* end = &dst[_dstSize/sizeof(IndexT)];
  109. for (uint32_t ii = 0, num = _numIndices-2; ii < num && dst < end; ++ii)
  110. {
  111. IndexT i0 = _indices[ii+0];
  112. IndexT i1 = _indices[ii+1];
  113. IndexT i2 = _indices[ii+2];
  114. if (i0 != i1
  115. && i1 != i2)
  116. {
  117. dst[0] = i0;
  118. dst[1] = i1;
  119. dst[2] = i2;
  120. dst += 3;
  121. }
  122. }
  123. return uint32_t(dst - (IndexT*)_dst);
  124. }
  125. template<typename IndexT>
  126. static uint32_t topologyConvertLineStripToLineList(void* _dst, uint32_t _dstSize, const IndexT* _indices, uint32_t _numIndices)
  127. {
  128. IndexT* dst = (IndexT*)_dst;
  129. IndexT* end = &dst[_dstSize/sizeof(IndexT)];
  130. IndexT i0 = _indices[0];
  131. for (uint32_t ii = 1; ii < _numIndices && dst < end; ++ii)
  132. {
  133. IndexT i1 = _indices[ii];
  134. if (i0 != i1)
  135. {
  136. dst[0] = i0;
  137. dst[1] = i1;
  138. dst += 2;
  139. i0 = i1;
  140. }
  141. }
  142. return uint32_t(dst - (IndexT*)_dst);
  143. }
  144. uint32_t topologyConvert(
  145. TopologyConvert::Enum _conversion
  146. , void* _dst
  147. , uint32_t _dstSize
  148. , const void* _indices
  149. , uint32_t _numIndices
  150. , bool _index32
  151. , bx::AllocatorI* _allocator
  152. )
  153. {
  154. switch (_conversion)
  155. {
  156. case TopologyConvert::TriStripToTriList:
  157. if (_index32)
  158. {
  159. return topologyConvertTriStripToTriList(_dst, _dstSize, (const uint32_t*)_indices, _numIndices);
  160. }
  161. return topologyConvertTriStripToTriList(_dst, _dstSize, (const uint16_t*)_indices, _numIndices);
  162. case TopologyConvert::TriListFlipWinding:
  163. if (_index32)
  164. {
  165. return topologyConvertTriListFlipWinding(_dst, _dstSize, (const uint32_t*)_indices, _numIndices);
  166. }
  167. return topologyConvertTriListFlipWinding(_dst, _dstSize, (const uint16_t*)_indices, _numIndices);
  168. case TopologyConvert::TriListToLineList:
  169. if (NULL == _allocator)
  170. {
  171. return 0;
  172. }
  173. if (_index32)
  174. {
  175. return topologyConvertTriListToLineList<uint32_t, uint64_t>(_dst, _dstSize, (const uint32_t*)_indices, _numIndices, _allocator);
  176. }
  177. return topologyConvertTriListToLineList<uint16_t, uint32_t>(_dst, _dstSize, (const uint16_t*)_indices, _numIndices, _allocator);
  178. case TopologyConvert::LineStripToLineList:
  179. if (_index32)
  180. {
  181. return topologyConvertLineStripToLineList(_dst, _dstSize, (const uint32_t*)_indices, _numIndices);
  182. }
  183. return topologyConvertLineStripToLineList(_dst, _dstSize, (const uint16_t*)_indices, _numIndices);
  184. default:
  185. break;
  186. }
  187. return 0;
  188. }
  189. inline float fmin3(float _a, float _b, float _c)
  190. {
  191. return bx::min(_a, _b, _c);
  192. }
  193. inline float fmax3(float _a, float _b, float _c)
  194. {
  195. return bx::max(_a, _b, _c);
  196. }
  197. inline float favg3(float _a, float _b, float _c)
  198. {
  199. return (_a + _b + _c) * 1.0f/3.0f;
  200. }
  201. const float* vertexPos(const void* _vertices, uint32_t _stride, uint32_t _index)
  202. {
  203. const uint8_t* vertices = (const uint8_t*)_vertices;
  204. return (const float*)&vertices[_index*_stride];
  205. }
  206. inline float distanceDir(const float* __restrict _dir, const void* __restrict _vertices, uint32_t _stride, uint32_t _index)
  207. {
  208. return bx::vec3Dot(vertexPos(_vertices, _stride, _index), _dir);
  209. }
  210. inline float distancePos(const float* __restrict _pos, const void* __restrict _vertices, uint32_t _stride, uint32_t _index)
  211. {
  212. float tmp[3];
  213. bx::vec3Sub(tmp, _pos, vertexPos(_vertices, _stride, _index) );
  214. return bx::sqrt(bx::vec3Dot(tmp, tmp) );
  215. }
  216. typedef float (*KeyFn)(float, float, float);
  217. typedef float (*DistanceFn)(const float*, const void*, uint32_t, uint32_t);
  218. template<typename IndexT, DistanceFn dfn, KeyFn kfn, uint32_t xorBits>
  219. inline void calcSortKeys(
  220. uint32_t* __restrict _keys
  221. , uint32_t* __restrict _values
  222. , const float _dirOrPos[3]
  223. , const void* __restrict _vertices
  224. , uint32_t _stride
  225. , const IndexT* _indices
  226. , uint32_t _num
  227. )
  228. {
  229. for (uint32_t ii = 0; ii < _num; ++ii)
  230. {
  231. const uint32_t idx0 = _indices[0];
  232. const uint32_t idx1 = _indices[1];
  233. const uint32_t idx2 = _indices[2];
  234. _indices += 3;
  235. float distance0 = dfn(_dirOrPos, _vertices, _stride, idx0);
  236. float distance1 = dfn(_dirOrPos, _vertices, _stride, idx1);
  237. float distance2 = dfn(_dirOrPos, _vertices, _stride, idx2);
  238. uint32_t ui = bx::floatToBits(kfn(distance0, distance1, distance2) );
  239. _keys[ii] = bx::floatFlip(ui) ^ xorBits;
  240. _values[ii] = ii;
  241. }
  242. }
  243. template<typename IndexT>
  244. void topologySortTriList(
  245. TopologySort::Enum _sort
  246. , IndexT* _dst
  247. , uint32_t* _keys
  248. , uint32_t* _values
  249. , uint32_t* _tempKeys
  250. , uint32_t* _tempValues
  251. , uint32_t _num
  252. , const float _dir[3]
  253. , const float _pos[3]
  254. , const void* _vertices
  255. , uint32_t _stride
  256. , const IndexT* _indices
  257. )
  258. {
  259. using namespace bx;
  260. switch (_sort)
  261. {
  262. default:
  263. case TopologySort::DirectionFrontToBackMin: calcSortKeys<IndexT, distanceDir, fmin3, 0 >(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  264. case TopologySort::DirectionFrontToBackAvg: calcSortKeys<IndexT, distanceDir, favg3, 0 >(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  265. case TopologySort::DirectionFrontToBackMax: calcSortKeys<IndexT, distanceDir, fmax3, 0 >(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  266. case TopologySort::DirectionBackToFrontMin: calcSortKeys<IndexT, distanceDir, fmin3, UINT32_MAX>(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  267. case TopologySort::DirectionBackToFrontAvg: calcSortKeys<IndexT, distanceDir, favg3, UINT32_MAX>(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  268. case TopologySort::DirectionBackToFrontMax: calcSortKeys<IndexT, distanceDir, fmax3, UINT32_MAX>(_keys, _values, _dir, _vertices, _stride, _indices, _num); break;
  269. case TopologySort::DistanceFrontToBackMin: calcSortKeys<IndexT, distancePos, fmin3, 0 >(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  270. case TopologySort::DistanceFrontToBackAvg: calcSortKeys<IndexT, distancePos, favg3, 0 >(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  271. case TopologySort::DistanceFrontToBackMax: calcSortKeys<IndexT, distancePos, fmax3, 0 >(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  272. case TopologySort::DistanceBackToFrontMin: calcSortKeys<IndexT, distancePos, fmin3, UINT32_MAX>(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  273. case TopologySort::DistanceBackToFrontAvg: calcSortKeys<IndexT, distancePos, favg3, UINT32_MAX>(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  274. case TopologySort::DistanceBackToFrontMax: calcSortKeys<IndexT, distancePos, fmax3, UINT32_MAX>(_keys, _values, _pos, _vertices, _stride, _indices, _num); break;
  275. }
  276. radixSort(_keys, _tempKeys, _values, _tempValues, _num);
  277. IndexT* sorted = _dst;
  278. for (uint32_t ii = 0; ii < _num; ++ii)
  279. {
  280. uint32_t face = _values[ii]*3;
  281. const IndexT idx0 = _indices[face+0];
  282. const IndexT idx1 = _indices[face+1];
  283. const IndexT idx2 = _indices[face+2];
  284. sorted[0] = idx0;
  285. sorted[1] = idx1;
  286. sorted[2] = idx2;
  287. sorted += 3;
  288. }
  289. }
  290. void topologySortTriList(
  291. TopologySort::Enum _sort
  292. , void* _dst
  293. , uint32_t _dstSize
  294. , const float _dir[3]
  295. , const float _pos[3]
  296. , const void* _vertices
  297. , uint32_t _stride
  298. , const void* _indices
  299. , uint32_t _numIndices
  300. , bool _index32
  301. , bx::AllocatorI* _allocator
  302. )
  303. {
  304. uint32_t indexSize = _index32
  305. ? sizeof(uint32_t)
  306. : sizeof(uint16_t)
  307. ;
  308. uint32_t num = bx::uint32_min(_numIndices*indexSize, _dstSize)/(indexSize*3);
  309. uint32_t* temp = (uint32_t*)BX_ALLOC(_allocator, sizeof(uint32_t)*num*4);
  310. uint32_t* keys = &temp[num*0];
  311. uint32_t* values = &temp[num*1];
  312. uint32_t* tempKeys = &temp[num*2];
  313. uint32_t* tempValues = &temp[num*3];
  314. if (_index32)
  315. {
  316. topologySortTriList(
  317. _sort
  318. , (uint32_t*)_dst
  319. , keys
  320. , values
  321. , tempKeys
  322. , tempValues
  323. , num
  324. , _dir
  325. , _pos
  326. , _vertices
  327. , _stride
  328. , (const uint32_t*)_indices
  329. );
  330. }
  331. else
  332. {
  333. topologySortTriList(
  334. _sort
  335. , (uint16_t*)_dst
  336. , keys
  337. , values
  338. , tempKeys
  339. , tempValues
  340. , num
  341. , _dir
  342. , _pos
  343. , _vertices
  344. , _stride
  345. , (const uint16_t*)_indices
  346. );
  347. }
  348. BX_FREE(_allocator, temp);
  349. }
  350. } //namespace bgfx