indexgenerator.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  1. // This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
  2. #include "meshoptimizer.h"
  3. #include <assert.h>
  4. #include <string.h>
  5. // This work is based on:
  6. // John McDonald, Mark Kilgard. Crack-Free Point-Normal Triangles using Adjacent Edge Normals. 2010
  7. namespace meshopt
  8. {
  9. static unsigned int hashUpdate4(unsigned int h, const unsigned char* key, size_t len)
  10. {
  11. // MurmurHash2
  12. const unsigned int m = 0x5bd1e995;
  13. const int r = 24;
  14. while (len >= 4)
  15. {
  16. unsigned int k = *reinterpret_cast<const unsigned int*>(key);
  17. k *= m;
  18. k ^= k >> r;
  19. k *= m;
  20. h *= m;
  21. h ^= k;
  22. key += 4;
  23. len -= 4;
  24. }
  25. return h;
  26. }
  27. struct VertexHasher
  28. {
  29. const unsigned char* vertices;
  30. size_t vertex_size;
  31. size_t vertex_stride;
  32. size_t hash(unsigned int index) const
  33. {
  34. return hashUpdate4(0, vertices + index * vertex_stride, vertex_size);
  35. }
  36. bool equal(unsigned int lhs, unsigned int rhs) const
  37. {
  38. return memcmp(vertices + lhs * vertex_stride, vertices + rhs * vertex_stride, vertex_size) == 0;
  39. }
  40. };
  41. struct VertexStreamHasher
  42. {
  43. const meshopt_Stream* streams;
  44. size_t stream_count;
  45. size_t hash(unsigned int index) const
  46. {
  47. unsigned int h = 0;
  48. for (size_t i = 0; i < stream_count; ++i)
  49. {
  50. const meshopt_Stream& s = streams[i];
  51. const unsigned char* data = static_cast<const unsigned char*>(s.data);
  52. h = hashUpdate4(h, data + index * s.stride, s.size);
  53. }
  54. return h;
  55. }
  56. bool equal(unsigned int lhs, unsigned int rhs) const
  57. {
  58. for (size_t i = 0; i < stream_count; ++i)
  59. {
  60. const meshopt_Stream& s = streams[i];
  61. const unsigned char* data = static_cast<const unsigned char*>(s.data);
  62. if (memcmp(data + lhs * s.stride, data + rhs * s.stride, s.size) != 0)
  63. return false;
  64. }
  65. return true;
  66. }
  67. };
  68. struct EdgeHasher
  69. {
  70. const unsigned int* remap;
  71. size_t hash(unsigned long long edge) const
  72. {
  73. unsigned int e0 = unsigned(edge >> 32);
  74. unsigned int e1 = unsigned(edge);
  75. unsigned int h1 = remap[e0];
  76. unsigned int h2 = remap[e1];
  77. const unsigned int m = 0x5bd1e995;
  78. // MurmurHash64B finalizer
  79. h1 ^= h2 >> 18;
  80. h1 *= m;
  81. h2 ^= h1 >> 22;
  82. h2 *= m;
  83. h1 ^= h2 >> 17;
  84. h1 *= m;
  85. h2 ^= h1 >> 19;
  86. h2 *= m;
  87. return h2;
  88. }
  89. bool equal(unsigned long long lhs, unsigned long long rhs) const
  90. {
  91. unsigned int l0 = unsigned(lhs >> 32);
  92. unsigned int l1 = unsigned(lhs);
  93. unsigned int r0 = unsigned(rhs >> 32);
  94. unsigned int r1 = unsigned(rhs);
  95. return remap[l0] == remap[r0] && remap[l1] == remap[r1];
  96. }
  97. };
  98. static size_t hashBuckets(size_t count)
  99. {
  100. size_t buckets = 1;
  101. while (buckets < count + count / 4)
  102. buckets *= 2;
  103. return buckets;
  104. }
  105. template <typename T, typename Hash>
  106. static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty)
  107. {
  108. assert(buckets > 0);
  109. assert((buckets & (buckets - 1)) == 0);
  110. size_t hashmod = buckets - 1;
  111. size_t bucket = hash.hash(key) & hashmod;
  112. for (size_t probe = 0; probe <= hashmod; ++probe)
  113. {
  114. T& item = table[bucket];
  115. if (item == empty)
  116. return &item;
  117. if (hash.equal(item, key))
  118. return &item;
  119. // hash collision, quadratic probing
  120. bucket = (bucket + probe + 1) & hashmod;
  121. }
  122. assert(false && "Hash table is full"); // unreachable
  123. return NULL;
  124. }
  125. static void buildPositionRemap(unsigned int* remap, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator)
  126. {
  127. VertexHasher vertex_hasher = {reinterpret_cast<const unsigned char*>(vertex_positions), 3 * sizeof(float), vertex_positions_stride};
  128. size_t vertex_table_size = hashBuckets(vertex_count);
  129. unsigned int* vertex_table = allocator.allocate<unsigned int>(vertex_table_size);
  130. memset(vertex_table, -1, vertex_table_size * sizeof(unsigned int));
  131. for (size_t i = 0; i < vertex_count; ++i)
  132. {
  133. unsigned int index = unsigned(i);
  134. unsigned int* entry = hashLookup(vertex_table, vertex_table_size, vertex_hasher, index, ~0u);
  135. if (*entry == ~0u)
  136. *entry = index;
  137. remap[index] = *entry;
  138. }
  139. allocator.deallocate(vertex_table);
  140. }
  141. template <size_t BlockSize>
  142. static void remapVertices(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap)
  143. {
  144. size_t block_size = BlockSize == 0 ? vertex_size : BlockSize;
  145. assert(block_size == vertex_size);
  146. for (size_t i = 0; i < vertex_count; ++i)
  147. if (remap[i] != ~0u)
  148. {
  149. assert(remap[i] < vertex_count);
  150. memcpy(static_cast<unsigned char*>(destination) + remap[i] * block_size, static_cast<const unsigned char*>(vertices) + i * block_size, block_size);
  151. }
  152. }
  153. } // namespace meshopt
  154. size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
  155. {
  156. using namespace meshopt;
  157. assert(indices || index_count == vertex_count);
  158. assert(!indices || index_count % 3 == 0);
  159. assert(vertex_size > 0 && vertex_size <= 256);
  160. meshopt_Allocator allocator;
  161. memset(destination, -1, vertex_count * sizeof(unsigned int));
  162. VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_size};
  163. size_t table_size = hashBuckets(vertex_count);
  164. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  165. memset(table, -1, table_size * sizeof(unsigned int));
  166. unsigned int next_vertex = 0;
  167. for (size_t i = 0; i < index_count; ++i)
  168. {
  169. unsigned int index = indices ? indices[i] : unsigned(i);
  170. assert(index < vertex_count);
  171. if (destination[index] == ~0u)
  172. {
  173. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  174. if (*entry == ~0u)
  175. {
  176. *entry = index;
  177. destination[index] = next_vertex++;
  178. }
  179. else
  180. {
  181. assert(destination[*entry] != ~0u);
  182. destination[index] = destination[*entry];
  183. }
  184. }
  185. }
  186. assert(next_vertex <= vertex_count);
  187. return next_vertex;
  188. }
  189. size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count)
  190. {
  191. using namespace meshopt;
  192. assert(indices || index_count == vertex_count);
  193. assert(index_count % 3 == 0);
  194. assert(stream_count > 0 && stream_count <= 16);
  195. for (size_t i = 0; i < stream_count; ++i)
  196. {
  197. assert(streams[i].size > 0 && streams[i].size <= 256);
  198. assert(streams[i].size <= streams[i].stride);
  199. }
  200. meshopt_Allocator allocator;
  201. memset(destination, -1, vertex_count * sizeof(unsigned int));
  202. VertexStreamHasher hasher = {streams, stream_count};
  203. size_t table_size = hashBuckets(vertex_count);
  204. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  205. memset(table, -1, table_size * sizeof(unsigned int));
  206. unsigned int next_vertex = 0;
  207. for (size_t i = 0; i < index_count; ++i)
  208. {
  209. unsigned int index = indices ? indices[i] : unsigned(i);
  210. assert(index < vertex_count);
  211. if (destination[index] == ~0u)
  212. {
  213. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  214. if (*entry == ~0u)
  215. {
  216. *entry = index;
  217. destination[index] = next_vertex++;
  218. }
  219. else
  220. {
  221. assert(destination[*entry] != ~0u);
  222. destination[index] = destination[*entry];
  223. }
  224. }
  225. }
  226. assert(next_vertex <= vertex_count);
  227. return next_vertex;
  228. }
  229. void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap)
  230. {
  231. using namespace meshopt;
  232. assert(vertex_size > 0 && vertex_size <= 256);
  233. meshopt_Allocator allocator;
  234. // support in-place remap
  235. if (destination == vertices)
  236. {
  237. unsigned char* vertices_copy = allocator.allocate<unsigned char>(vertex_count * vertex_size);
  238. memcpy(vertices_copy, vertices, vertex_count * vertex_size);
  239. vertices = vertices_copy;
  240. }
  241. // specialize the loop for common vertex sizes to ensure memcpy is compiled as an inlined intrinsic
  242. switch (vertex_size)
  243. {
  244. case 4:
  245. return remapVertices<4>(destination, vertices, vertex_count, vertex_size, remap);
  246. case 8:
  247. return remapVertices<8>(destination, vertices, vertex_count, vertex_size, remap);
  248. case 12:
  249. return remapVertices<12>(destination, vertices, vertex_count, vertex_size, remap);
  250. case 16:
  251. return remapVertices<16>(destination, vertices, vertex_count, vertex_size, remap);
  252. default:
  253. return remapVertices<0>(destination, vertices, vertex_count, vertex_size, remap);
  254. }
  255. }
  256. void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap)
  257. {
  258. assert(index_count % 3 == 0);
  259. for (size_t i = 0; i < index_count; ++i)
  260. {
  261. unsigned int index = indices ? indices[i] : unsigned(i);
  262. assert(remap[index] != ~0u);
  263. destination[i] = remap[index];
  264. }
  265. }
  266. void meshopt_generateShadowIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride)
  267. {
  268. using namespace meshopt;
  269. assert(indices);
  270. assert(index_count % 3 == 0);
  271. assert(vertex_size > 0 && vertex_size <= 256);
  272. assert(vertex_size <= vertex_stride);
  273. meshopt_Allocator allocator;
  274. unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
  275. memset(remap, -1, vertex_count * sizeof(unsigned int));
  276. VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_stride};
  277. size_t table_size = hashBuckets(vertex_count);
  278. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  279. memset(table, -1, table_size * sizeof(unsigned int));
  280. for (size_t i = 0; i < index_count; ++i)
  281. {
  282. unsigned int index = indices[i];
  283. assert(index < vertex_count);
  284. if (remap[index] == ~0u)
  285. {
  286. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  287. if (*entry == ~0u)
  288. *entry = index;
  289. remap[index] = *entry;
  290. }
  291. destination[i] = remap[index];
  292. }
  293. }
  294. void meshopt_generateShadowIndexBufferMulti(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const struct meshopt_Stream* streams, size_t stream_count)
  295. {
  296. using namespace meshopt;
  297. assert(indices);
  298. assert(index_count % 3 == 0);
  299. assert(stream_count > 0 && stream_count <= 16);
  300. for (size_t i = 0; i < stream_count; ++i)
  301. {
  302. assert(streams[i].size > 0 && streams[i].size <= 256);
  303. assert(streams[i].size <= streams[i].stride);
  304. }
  305. meshopt_Allocator allocator;
  306. unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
  307. memset(remap, -1, vertex_count * sizeof(unsigned int));
  308. VertexStreamHasher hasher = {streams, stream_count};
  309. size_t table_size = hashBuckets(vertex_count);
  310. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  311. memset(table, -1, table_size * sizeof(unsigned int));
  312. for (size_t i = 0; i < index_count; ++i)
  313. {
  314. unsigned int index = indices[i];
  315. assert(index < vertex_count);
  316. if (remap[index] == ~0u)
  317. {
  318. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  319. if (*entry == ~0u)
  320. *entry = index;
  321. remap[index] = *entry;
  322. }
  323. destination[i] = remap[index];
  324. }
  325. }
  326. void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
  327. {
  328. using namespace meshopt;
  329. assert(index_count % 3 == 0);
  330. assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
  331. assert(vertex_positions_stride % sizeof(float) == 0);
  332. meshopt_Allocator allocator;
  333. static const int next[4] = {1, 2, 0, 1};
  334. // build position remap: for each vertex, which other (canonical) vertex does it map to?
  335. unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
  336. buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator);
  337. // build edge set; this stores all triangle edges but we can look these up by any other wedge
  338. EdgeHasher edge_hasher = {remap};
  339. size_t edge_table_size = hashBuckets(index_count);
  340. unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size);
  341. unsigned int* edge_vertex_table = allocator.allocate<unsigned int>(edge_table_size);
  342. memset(edge_table, -1, edge_table_size * sizeof(unsigned long long));
  343. memset(edge_vertex_table, -1, edge_table_size * sizeof(unsigned int));
  344. for (size_t i = 0; i < index_count; i += 3)
  345. {
  346. for (int e = 0; e < 3; ++e)
  347. {
  348. unsigned int i0 = indices[i + e];
  349. unsigned int i1 = indices[i + next[e]];
  350. unsigned int i2 = indices[i + next[e + 1]];
  351. assert(i0 < vertex_count && i1 < vertex_count && i2 < vertex_count);
  352. unsigned long long edge = ((unsigned long long)i0 << 32) | i1;
  353. unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
  354. if (*entry == ~0ull)
  355. {
  356. *entry = edge;
  357. // store vertex opposite to the edge
  358. edge_vertex_table[entry - edge_table] = i2;
  359. }
  360. }
  361. }
  362. // build resulting index buffer: 6 indices for each input triangle
  363. for (size_t i = 0; i < index_count; i += 3)
  364. {
  365. unsigned int patch[6];
  366. for (int e = 0; e < 3; ++e)
  367. {
  368. unsigned int i0 = indices[i + e];
  369. unsigned int i1 = indices[i + next[e]];
  370. assert(i0 < vertex_count && i1 < vertex_count);
  371. // note: this refers to the opposite edge!
  372. unsigned long long edge = ((unsigned long long)i1 << 32) | i0;
  373. unsigned long long* oppe = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
  374. patch[e * 2 + 0] = i0;
  375. patch[e * 2 + 1] = (*oppe == ~0ull) ? i0 : edge_vertex_table[oppe - edge_table];
  376. }
  377. memcpy(destination + i * 2, patch, sizeof(patch));
  378. }
  379. }
  380. void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
  381. {
  382. using namespace meshopt;
  383. assert(index_count % 3 == 0);
  384. assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
  385. assert(vertex_positions_stride % sizeof(float) == 0);
  386. meshopt_Allocator allocator;
  387. static const int next[3] = {1, 2, 0};
  388. // build position remap: for each vertex, which other (canonical) vertex does it map to?
  389. unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
  390. buildPositionRemap(remap, vertex_positions, vertex_count, vertex_positions_stride, allocator);
  391. // build edge set; this stores all triangle edges but we can look these up by any other wedge
  392. EdgeHasher edge_hasher = {remap};
  393. size_t edge_table_size = hashBuckets(index_count);
  394. unsigned long long* edge_table = allocator.allocate<unsigned long long>(edge_table_size);
  395. memset(edge_table, -1, edge_table_size * sizeof(unsigned long long));
  396. for (size_t i = 0; i < index_count; i += 3)
  397. {
  398. for (int e = 0; e < 3; ++e)
  399. {
  400. unsigned int i0 = indices[i + e];
  401. unsigned int i1 = indices[i + next[e]];
  402. assert(i0 < vertex_count && i1 < vertex_count);
  403. unsigned long long edge = ((unsigned long long)i0 << 32) | i1;
  404. unsigned long long* entry = hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
  405. if (*entry == ~0ull)
  406. *entry = edge;
  407. }
  408. }
  409. // build resulting index buffer: 12 indices for each input triangle
  410. for (size_t i = 0; i < index_count; i += 3)
  411. {
  412. unsigned int patch[12];
  413. for (int e = 0; e < 3; ++e)
  414. {
  415. unsigned int i0 = indices[i + e];
  416. unsigned int i1 = indices[i + next[e]];
  417. assert(i0 < vertex_count && i1 < vertex_count);
  418. // note: this refers to the opposite edge!
  419. unsigned long long edge = ((unsigned long long)i1 << 32) | i0;
  420. unsigned long long oppe = *hashLookup(edge_table, edge_table_size, edge_hasher, edge, ~0ull);
  421. // use the same edge if opposite edge doesn't exist (border)
  422. oppe = (oppe == ~0ull) ? edge : oppe;
  423. // triangle index (0, 1, 2)
  424. patch[e] = i0;
  425. // opposite edge (3, 4; 5, 6; 7, 8)
  426. patch[3 + e * 2 + 0] = unsigned(oppe);
  427. patch[3 + e * 2 + 1] = unsigned(oppe >> 32);
  428. // dominant vertex (9, 10, 11)
  429. patch[9 + e] = remap[i0];
  430. }
  431. memcpy(destination + i * 4, patch, sizeof(patch));
  432. }
  433. }