indexgenerator.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  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. namespace meshopt
  6. {
  7. static unsigned int hashUpdate4(unsigned int h, const unsigned char* key, size_t len)
  8. {
  9. // MurmurHash2
  10. const unsigned int m = 0x5bd1e995;
  11. const int r = 24;
  12. while (len >= 4)
  13. {
  14. unsigned int k = *reinterpret_cast<const unsigned int*>(key);
  15. k *= m;
  16. k ^= k >> r;
  17. k *= m;
  18. h *= m;
  19. h ^= k;
  20. key += 4;
  21. len -= 4;
  22. }
  23. return h;
  24. }
  25. struct VertexHasher
  26. {
  27. const unsigned char* vertices;
  28. size_t vertex_size;
  29. size_t vertex_stride;
  30. size_t hash(unsigned int index) const
  31. {
  32. return hashUpdate4(0, vertices + index * vertex_stride, vertex_size);
  33. }
  34. bool equal(unsigned int lhs, unsigned int rhs) const
  35. {
  36. return memcmp(vertices + lhs * vertex_stride, vertices + rhs * vertex_stride, vertex_size) == 0;
  37. }
  38. };
  39. struct VertexStreamHasher
  40. {
  41. const meshopt_Stream* streams;
  42. size_t stream_count;
  43. size_t hash(unsigned int index) const
  44. {
  45. unsigned int h = 0;
  46. for (size_t i = 0; i < stream_count; ++i)
  47. {
  48. const meshopt_Stream& s = streams[i];
  49. const unsigned char* data = static_cast<const unsigned char*>(s.data);
  50. h = hashUpdate4(h, data + index * s.stride, s.size);
  51. }
  52. return h;
  53. }
  54. bool equal(unsigned int lhs, unsigned int rhs) const
  55. {
  56. for (size_t i = 0; i < stream_count; ++i)
  57. {
  58. const meshopt_Stream& s = streams[i];
  59. const unsigned char* data = static_cast<const unsigned char*>(s.data);
  60. if (memcmp(data + lhs * s.stride, data + rhs * s.stride, s.size) != 0)
  61. return false;
  62. }
  63. return true;
  64. }
  65. };
  66. static size_t hashBuckets(size_t count)
  67. {
  68. size_t buckets = 1;
  69. while (buckets < count)
  70. buckets *= 2;
  71. return buckets;
  72. }
  73. template <typename T, typename Hash>
  74. static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty)
  75. {
  76. assert(buckets > 0);
  77. assert((buckets & (buckets - 1)) == 0);
  78. size_t hashmod = buckets - 1;
  79. size_t bucket = hash.hash(key) & hashmod;
  80. for (size_t probe = 0; probe <= hashmod; ++probe)
  81. {
  82. T& item = table[bucket];
  83. if (item == empty)
  84. return &item;
  85. if (hash.equal(item, key))
  86. return &item;
  87. // hash collision, quadratic probing
  88. bucket = (bucket + probe + 1) & hashmod;
  89. }
  90. assert(false && "Hash table is full"); // unreachable
  91. return 0;
  92. }
  93. } // namespace meshopt
  94. 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)
  95. {
  96. using namespace meshopt;
  97. assert(indices || index_count == vertex_count);
  98. assert(index_count % 3 == 0);
  99. assert(vertex_size > 0 && vertex_size <= 256);
  100. meshopt_Allocator allocator;
  101. memset(destination, -1, vertex_count * sizeof(unsigned int));
  102. VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_size};
  103. size_t table_size = hashBuckets(vertex_count);
  104. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  105. memset(table, -1, table_size * sizeof(unsigned int));
  106. unsigned int next_vertex = 0;
  107. for (size_t i = 0; i < index_count; ++i)
  108. {
  109. unsigned int index = indices ? indices[i] : unsigned(i);
  110. assert(index < vertex_count);
  111. if (destination[index] == ~0u)
  112. {
  113. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  114. if (*entry == ~0u)
  115. {
  116. *entry = index;
  117. destination[index] = next_vertex++;
  118. }
  119. else
  120. {
  121. assert(destination[*entry] != ~0u);
  122. destination[index] = destination[*entry];
  123. }
  124. }
  125. }
  126. assert(next_vertex <= vertex_count);
  127. return next_vertex;
  128. }
  129. 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)
  130. {
  131. using namespace meshopt;
  132. assert(indices || index_count == vertex_count);
  133. assert(index_count % 3 == 0);
  134. assert(stream_count > 0 && stream_count <= 16);
  135. for (size_t i = 0; i < stream_count; ++i)
  136. {
  137. assert(streams[i].size > 0 && streams[i].size <= 256);
  138. assert(streams[i].size <= streams[i].stride);
  139. }
  140. meshopt_Allocator allocator;
  141. memset(destination, -1, vertex_count * sizeof(unsigned int));
  142. VertexStreamHasher hasher = {streams, stream_count};
  143. size_t table_size = hashBuckets(vertex_count);
  144. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  145. memset(table, -1, table_size * sizeof(unsigned int));
  146. unsigned int next_vertex = 0;
  147. for (size_t i = 0; i < index_count; ++i)
  148. {
  149. unsigned int index = indices ? indices[i] : unsigned(i);
  150. assert(index < vertex_count);
  151. if (destination[index] == ~0u)
  152. {
  153. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  154. if (*entry == ~0u)
  155. {
  156. *entry = index;
  157. destination[index] = next_vertex++;
  158. }
  159. else
  160. {
  161. assert(destination[*entry] != ~0u);
  162. destination[index] = destination[*entry];
  163. }
  164. }
  165. }
  166. assert(next_vertex <= vertex_count);
  167. return next_vertex;
  168. }
  169. void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap)
  170. {
  171. assert(vertex_size > 0 && vertex_size <= 256);
  172. meshopt_Allocator allocator;
  173. // support in-place remap
  174. if (destination == vertices)
  175. {
  176. unsigned char* vertices_copy = allocator.allocate<unsigned char>(vertex_count * vertex_size);
  177. memcpy(vertices_copy, vertices, vertex_count * vertex_size);
  178. vertices = vertices_copy;
  179. }
  180. for (size_t i = 0; i < vertex_count; ++i)
  181. {
  182. if (remap[i] != ~0u)
  183. {
  184. assert(remap[i] < vertex_count);
  185. memcpy(static_cast<unsigned char*>(destination) + remap[i] * vertex_size, static_cast<const unsigned char*>(vertices) + i * vertex_size, vertex_size);
  186. }
  187. }
  188. }
  189. void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap)
  190. {
  191. assert(index_count % 3 == 0);
  192. for (size_t i = 0; i < index_count; ++i)
  193. {
  194. unsigned int index = indices ? indices[i] : unsigned(i);
  195. assert(remap[index] != ~0u);
  196. destination[i] = remap[index];
  197. }
  198. }
  199. 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)
  200. {
  201. using namespace meshopt;
  202. assert(indices);
  203. assert(index_count % 3 == 0);
  204. assert(vertex_size > 0 && vertex_size <= 256);
  205. assert(vertex_size <= vertex_stride);
  206. meshopt_Allocator allocator;
  207. unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
  208. memset(remap, -1, vertex_count * sizeof(unsigned int));
  209. VertexHasher hasher = {static_cast<const unsigned char*>(vertices), vertex_size, vertex_stride};
  210. size_t table_size = hashBuckets(vertex_count);
  211. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  212. memset(table, -1, table_size * sizeof(unsigned int));
  213. for (size_t i = 0; i < index_count; ++i)
  214. {
  215. unsigned int index = indices[i];
  216. assert(index < vertex_count);
  217. if (remap[index] == ~0u)
  218. {
  219. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  220. if (*entry == ~0u)
  221. *entry = index;
  222. remap[index] = *entry;
  223. }
  224. destination[i] = remap[index];
  225. }
  226. }
  227. 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)
  228. {
  229. using namespace meshopt;
  230. assert(indices);
  231. assert(index_count % 3 == 0);
  232. assert(stream_count > 0 && stream_count <= 16);
  233. for (size_t i = 0; i < stream_count; ++i)
  234. {
  235. assert(streams[i].size > 0 && streams[i].size <= 256);
  236. assert(streams[i].size <= streams[i].stride);
  237. }
  238. meshopt_Allocator allocator;
  239. unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
  240. memset(remap, -1, vertex_count * sizeof(unsigned int));
  241. VertexStreamHasher hasher = {streams, stream_count};
  242. size_t table_size = hashBuckets(vertex_count);
  243. unsigned int* table = allocator.allocate<unsigned int>(table_size);
  244. memset(table, -1, table_size * sizeof(unsigned int));
  245. for (size_t i = 0; i < index_count; ++i)
  246. {
  247. unsigned int index = indices[i];
  248. assert(index < vertex_count);
  249. if (remap[index] == ~0u)
  250. {
  251. unsigned int* entry = hashLookup(table, table_size, hasher, index, ~0u);
  252. if (*entry == ~0u)
  253. *entry = index;
  254. remap[index] = *entry;
  255. }
  256. destination[i] = remap[index];
  257. }
  258. }