meshoptimizer.h 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851
  1. /**
  2. * meshoptimizer - version 0.12
  3. *
  4. * Copyright (C) 2016-2019, by Arseny Kapoulkine ([email protected])
  5. * Report bugs and download new versions at https://github.com/zeux/meshoptimizer
  6. *
  7. * This library is distributed under the MIT License. See notice at the end of this file.
  8. */
  9. #pragma once
  10. #include <assert.h>
  11. #include <stddef.h>
  12. /* Version macro; major * 1000 + minor * 10 + patch */
  13. #define MESHOPTIMIZER_VERSION 120
  14. /* If no API is defined, assume default */
  15. #ifndef MESHOPTIMIZER_API
  16. #define MESHOPTIMIZER_API
  17. #endif
  18. /* Experimental APIs have unstable interface and might have implementation that's not fully tested or optimized */
  19. #define MESHOPTIMIZER_EXPERIMENTAL MESHOPTIMIZER_API
  20. /* C interface */
  21. #ifdef __cplusplus
  22. extern "C" {
  23. #endif
  24. /**
  25. * Vertex attribute stream, similar to glVertexPointer
  26. * Each element takes size bytes, with stride controlling the spacing between successive elements.
  27. */
  28. struct meshopt_Stream
  29. {
  30. const void* data;
  31. size_t size;
  32. size_t stride;
  33. };
  34. /**
  35. * Generates a vertex remap table from the vertex buffer and an optional index buffer and returns number of unique vertices
  36. * As a result, all vertices that are binary equivalent map to the same (new) location, with no gaps in the resulting sequence.
  37. * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer/meshopt_remapIndexBuffer.
  38. *
  39. * destination must contain enough space for the resulting remap table (vertex_count elements)
  40. * indices can be NULL if the input is unindexed
  41. */
  42. MESHOPTIMIZER_API 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);
  43. /**
  44. * Generates a vertex remap table from multiple vertex streams and an optional index buffer and returns number of unique vertices
  45. * As a result, all vertices that are binary equivalent map to the same (new) location, with no gaps in the resulting sequence.
  46. * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer/meshopt_remapIndexBuffer.
  47. * To remap vertex buffers, you will need to call meshopt_remapVertexBuffer for each vertex stream.
  48. *
  49. * destination must contain enough space for the resulting remap table (vertex_count elements)
  50. * indices can be NULL if the input is unindexed
  51. */
  52. MESHOPTIMIZER_API 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);
  53. /**
  54. * Generates vertex buffer from the source vertex buffer and remap table generated by meshopt_generateVertexRemap
  55. *
  56. * destination must contain enough space for the resulting vertex buffer (unique_vertex_count elements, returned by meshopt_generateVertexRemap)
  57. * vertex_count should be the initial vertex count and not the value returned by meshopt_generateVertexRemap
  58. */
  59. MESHOPTIMIZER_API void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t vertex_count, size_t vertex_size, const unsigned int* remap);
  60. /**
  61. * Generate index buffer from the source index buffer and remap table generated by meshopt_generateVertexRemap
  62. *
  63. * destination must contain enough space for the resulting index buffer (index_count elements)
  64. * indices can be NULL if the input is unindexed
  65. */
  66. MESHOPTIMIZER_API void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap);
  67. /**
  68. * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary
  69. * All vertices that are binary equivalent (wrt first vertex_size bytes) map to the first vertex in the original vertex buffer.
  70. * This makes it possible to use the index buffer for Z pre-pass or shadowmap rendering, while using the original index buffer for regular rendering.
  71. *
  72. * destination must contain enough space for the resulting index buffer (index_count elements)
  73. */
  74. MESHOPTIMIZER_API 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);
  75. /**
  76. * Generate index buffer that can be used for more efficient rendering when only a subset of the vertex attributes is necessary
  77. * All vertices that are binary equivalent (wrt specified streams) map to the first vertex in the original vertex buffer.
  78. * This makes it possible to use the index buffer for Z pre-pass or shadowmap rendering, while using the original index buffer for regular rendering.
  79. *
  80. * destination must contain enough space for the resulting index buffer (index_count elements)
  81. */
  82. MESHOPTIMIZER_API 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);
  83. /**
  84. * Vertex transform cache optimizer
  85. * Reorders indices to reduce the number of GPU vertex shader invocations
  86. * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
  87. *
  88. * destination must contain enough space for the resulting index buffer (index_count elements)
  89. */
  90. MESHOPTIMIZER_API void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count);
  91. /**
  92. * Vertex transform cache optimizer for FIFO caches
  93. * Reorders indices to reduce the number of GPU vertex shader invocations
  94. * Generally takes ~3x less time to optimize meshes but produces inferior results compared to meshopt_optimizeVertexCache
  95. * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
  96. *
  97. * destination must contain enough space for the resulting index buffer (index_count elements)
  98. * cache_size should be less than the actual GPU cache size to avoid cache thrashing
  99. */
  100. MESHOPTIMIZER_API void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size);
  101. /**
  102. * Overdraw optimizer
  103. * Reorders indices to reduce the number of GPU vertex shader invocations and the pixel overdraw
  104. * If index buffer contains multiple ranges for multiple draw calls, this functions needs to be called on each range individually.
  105. *
  106. * destination must contain enough space for the resulting index buffer (index_count elements)
  107. * indices must contain index data that is the result of meshopt_optimizeVertexCache (*not* the original mesh indices!)
  108. * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
  109. * threshold indicates how much the overdraw optimizer can degrade vertex cache efficiency (1.05 = up to 5%) to reduce overdraw more efficiently
  110. */
  111. MESHOPTIMIZER_API void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold);
  112. /**
  113. * Vertex fetch cache optimizer
  114. * Reorders vertices and changes indices to reduce the amount of GPU memory fetches during vertex processing
  115. * Returns the number of unique vertices, which is the same as input vertex count unless some vertices are unused
  116. * This functions works for a single vertex stream; for multiple vertex streams, use meshopt_optimizeVertexFetchRemap + meshopt_remapVertexBuffer for each stream.
  117. *
  118. * destination must contain enough space for the resulting vertex buffer (vertex_count elements)
  119. * indices is used both as an input and as an output index buffer
  120. */
  121. MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
  122. /**
  123. * Vertex fetch cache optimizer
  124. * Generates vertex remap to reduce the amount of GPU memory fetches during vertex processing
  125. * Returns the number of unique vertices, which is the same as input vertex count unless some vertices are unused
  126. * The resulting remap table should be used to reorder vertex/index buffers using meshopt_remapVertexBuffer/meshopt_remapIndexBuffer
  127. *
  128. * destination must contain enough space for the resulting remap table (vertex_count elements)
  129. */
  130. MESHOPTIMIZER_API size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count);
  131. /**
  132. * Index buffer encoder
  133. * Encodes index data into an array of bytes that is generally much smaller (<1.5 bytes/triangle) and compresses better (<1 bytes/triangle) compared to original.
  134. * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space
  135. * For maximum efficiency the index buffer being encoded has to be optimized for vertex cache and vertex fetch first.
  136. *
  137. * buffer must contain enough space for the encoded index buffer (use meshopt_encodeIndexBufferBound to compute worst case size)
  138. */
  139. MESHOPTIMIZER_API size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count);
  140. MESHOPTIMIZER_API size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count);
  141. /**
  142. * Index buffer decoder
  143. * Decodes index data from an array of bytes generated by meshopt_encodeIndexBuffer
  144. * Returns 0 if decoding was successful, and an error code otherwise
  145. * The decoder is safe to use for untrusted input, but it may produce garbage data (e.g. out of range indices).
  146. *
  147. * destination must contain enough space for the resulting index buffer (index_count elements)
  148. */
  149. MESHOPTIMIZER_API int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size);
  150. /**
  151. * Vertex buffer encoder
  152. * Encodes vertex data into an array of bytes that is generally smaller and compresses better compared to original.
  153. * Returns encoded data size on success, 0 on error; the only error condition is if buffer doesn't have enough space
  154. * This function works for a single vertex stream; for multiple vertex streams, call meshopt_encodeVertexBuffer for each stream.
  155. *
  156. * buffer must contain enough space for the encoded vertex buffer (use meshopt_encodeVertexBufferBound to compute worst case size)
  157. */
  158. MESHOPTIMIZER_API size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, const void* vertices, size_t vertex_count, size_t vertex_size);
  159. MESHOPTIMIZER_API size_t meshopt_encodeVertexBufferBound(size_t vertex_count, size_t vertex_size);
  160. /**
  161. * Vertex buffer decoder
  162. * Decodes vertex data from an array of bytes generated by meshopt_encodeVertexBuffer
  163. * Returns 0 if decoding was successful, and an error code otherwise
  164. * The decoder is safe to use for untrusted input, but it may produce garbage data.
  165. *
  166. * destination must contain enough space for the resulting vertex buffer (vertex_count * vertex_size bytes)
  167. */
  168. MESHOPTIMIZER_API int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t vertex_size, const unsigned char* buffer, size_t buffer_size);
  169. /**
  170. * Experimental: Mesh simplifier
  171. * Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible
  172. * The algorithm tries to preserve mesh topology and can stop short of the target goal based on topology constraints or target error.
  173. * If not all attributes from the input mesh are required, it's recommended to reindex the mesh using meshopt_generateShadowIndexBuffer prior to simplification.
  174. * Returns the number of indices after simplification, with destination containing new index data
  175. * The resulting index buffer references vertices from the original vertex buffer.
  176. * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
  177. *
  178. * destination must contain enough space for the *source* index buffer (since optimization is iterative, this means index_count elements - *not* target_index_count!)
  179. * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
  180. */
  181. MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error);
  182. /**
  183. * Experimental: Mesh simplifier (sloppy)
  184. * Reduces the number of triangles in the mesh, sacrificing mesh apperance for simplification performance
  185. * The algorithm doesn't preserve mesh topology but is always able to reach target triangle count.
  186. * Returns the number of indices after simplification, with destination containing new index data
  187. * The resulting index buffer references vertices from the original vertex buffer.
  188. * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
  189. *
  190. * destination must contain enough space for the target index buffer
  191. * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
  192. */
  193. MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count);
  194. /**
  195. * Experimental: Point cloud simplifier
  196. * Reduces the number of points in the cloud to reach the given target
  197. * Returns the number of points after simplification, with destination containing new index data
  198. * The resulting index buffer references vertices from the original vertex buffer.
  199. * If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
  200. *
  201. * destination must contain enough space for the target index buffer
  202. * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
  203. */
  204. MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count);
  205. /**
  206. * Mesh stripifier
  207. * Converts a previously vertex cache optimized triangle list to triangle strip, stitching strips using restart index or degenerate triangles
  208. * Returns the number of indices in the resulting strip, with destination containing new index data
  209. * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
  210. * Using restart indices can result in ~10% smaller index buffers, but on some GPUs restart indices may result in decreased performance.
  211. *
  212. * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_stripifyBound
  213. * restart_index should be 0xffff or 0xffffffff depending on index size, or 0 to use degenerate triangles
  214. */
  215. MESHOPTIMIZER_API size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int restart_index);
  216. MESHOPTIMIZER_API size_t meshopt_stripifyBound(size_t index_count);
  217. /**
  218. * Mesh unstripifier
  219. * Converts a triangle strip to a triangle list
  220. * Returns the number of indices in the resulting list, with destination containing new index data
  221. *
  222. * destination must contain enough space for the target index buffer, worst case can be computed with meshopt_unstripifyBound
  223. */
  224. MESHOPTIMIZER_API size_t meshopt_unstripify(unsigned int* destination, const unsigned int* indices, size_t index_count, unsigned int restart_index);
  225. MESHOPTIMIZER_API size_t meshopt_unstripifyBound(size_t index_count);
  226. struct meshopt_VertexCacheStatistics
  227. {
  228. unsigned int vertices_transformed;
  229. unsigned int warps_executed;
  230. float acmr; /* transformed vertices / triangle count; best case 0.5, worst case 3.0, optimum depends on topology */
  231. float atvr; /* transformed vertices / vertex count; best case 1.0, worst case 6.0, optimum is 1.0 (each vertex is transformed once) */
  232. };
  233. /**
  234. * Vertex transform cache analyzer
  235. * Returns cache hit statistics using a simplified FIFO model
  236. * Results may not match actual GPU performance
  237. */
  238. MESHOPTIMIZER_API struct meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size);
  239. struct meshopt_OverdrawStatistics
  240. {
  241. unsigned int pixels_covered;
  242. unsigned int pixels_shaded;
  243. float overdraw; /* shaded pixels / covered pixels; best case 1.0 */
  244. };
  245. /**
  246. * Overdraw analyzer
  247. * Returns overdraw statistics using a software rasterizer
  248. * Results may not match actual GPU performance
  249. *
  250. * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
  251. */
  252. MESHOPTIMIZER_API struct meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  253. struct meshopt_VertexFetchStatistics
  254. {
  255. unsigned int bytes_fetched;
  256. float overfetch; /* fetched bytes / vertex buffer size; best case 1.0 (each byte is fetched once) */
  257. };
  258. /**
  259. * Vertex fetch cache analyzer
  260. * Returns cache hit statistics using a simplified direct mapped model
  261. * Results may not match actual GPU performance
  262. */
  263. MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size);
  264. struct meshopt_Meshlet
  265. {
  266. unsigned int vertices[64];
  267. unsigned char indices[126][3];
  268. unsigned char triangle_count;
  269. unsigned char vertex_count;
  270. };
  271. /**
  272. * Experimental: Meshlet builder
  273. * Splits the mesh into a set of meshlets where each meshlet has a micro index buffer indexing into meshlet vertices that refer to the original vertex buffer
  274. * The resulting data can be used to render meshes using NVidia programmable mesh shading pipeline, or in other cluster-based renderers.
  275. * For maximum efficiency the index buffer being converted has to be optimized for vertex cache first.
  276. *
  277. * destination must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
  278. * max_vertices and max_triangles can't exceed limits statically declared in meshopt_Meshlet (max_vertices <= 64, max_triangles <= 126)
  279. */
  280. MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshlets(struct meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
  281. MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles);
  282. struct meshopt_Bounds
  283. {
  284. /* bounding sphere, useful for frustum and occlusion culling */
  285. float center[3];
  286. float radius;
  287. /* normal cone, useful for backface culling */
  288. float cone_apex[3];
  289. float cone_axis[3];
  290. float cone_cutoff; /* = cos(angle/2) */
  291. /* normal cone axis and cutoff, stored in 8-bit SNORM format; decode using x/127.0 */
  292. signed char cone_axis_s8[3];
  293. signed char cone_cutoff_s8;
  294. };
  295. /**
  296. * Experimental: Cluster bounds generator
  297. * Creates bounding volumes that can be used for frustum, backface and occlusion culling.
  298. *
  299. * For backface culling with orthographic projection, use the following formula to reject backfacing clusters:
  300. * dot(view, cone_axis) >= cone_cutoff
  301. *
  302. * For perspective projection, you can the formula that needs cone apex in addition to axis & cutoff:
  303. * dot(normalize(cone_apex - camera_position), cone_axis) >= cone_cutoff
  304. *
  305. * Alternatively, you can use the formula that doesn't need cone apex and uses bounding sphere instead:
  306. * dot(normalize(center - camera_position), cone_axis) >= cone_cutoff + radius / length(center - camera_position)
  307. * or an equivalent formula that doesn't have a singularity at center = camera_position:
  308. * dot(center - camera_position, cone_axis) >= cone_cutoff * length(center - camera_position) + radius
  309. *
  310. * The formula that uses the apex is slightly more accurate but needs the apex; if you are already using bounding sphere
  311. * to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable.
  312. *
  313. * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
  314. * index_count should be less than or equal to 256*3 (the function assumes clusters of limited size)
  315. */
  316. MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  317. MESHOPTIMIZER_EXPERIMENTAL struct meshopt_Bounds meshopt_computeMeshletBounds(const struct meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  318. /**
  319. * Experimental: Spatial sorter
  320. * Generates a remap table that can be used to reorder points for spatial locality.
  321. * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer.
  322. *
  323. * destination must contain enough space for the resulting remap table (vertex_count elements)
  324. */
  325. MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  326. /**
  327. * Experimental: Spatial sorter
  328. * Reorders triangles for spatial locality, and generates a new index buffer. The resulting index buffer can be used with other functions like optimizeVertexCache.
  329. *
  330. * destination must contain enough space for the resulting index buffer (index_count elements)
  331. * indices must contain index data that is the result of meshopt_optimizeVertexCache (*not* the original mesh indices!)
  332. * vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
  333. */
  334. MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortTriangles(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  335. /**
  336. * Set allocation callbacks
  337. * These callbacks will be used instead of the default operator new/operator delete for all temporary allocations in the library.
  338. * Note that all algorithms only allocate memory for temporary use.
  339. * allocate/deallocate are always called in a stack-like order - last pointer to be allocated is deallocated first.
  340. */
  341. MESHOPTIMIZER_API void meshopt_setAllocator(void* (*allocate)(size_t), void (*deallocate)(void*));
  342. #ifdef __cplusplus
  343. } /* extern "C" */
  344. #endif
  345. /* Quantization into commonly supported data formats */
  346. #ifdef __cplusplus
  347. /**
  348. * Quantize a float in [0..1] range into an N-bit fixed point unorm value
  349. * Assumes reconstruction function (q / (2^N-1)), which is the case for fixed-function normalized fixed point conversion
  350. * Maximum reconstruction error: 1/2^(N+1)
  351. */
  352. inline int meshopt_quantizeUnorm(float v, int N);
  353. /**
  354. * Quantize a float in [-1..1] range into an N-bit fixed point snorm value
  355. * Assumes reconstruction function (q / (2^(N-1)-1)), which is the case for fixed-function normalized fixed point conversion (except early OpenGL versions)
  356. * Maximum reconstruction error: 1/2^N
  357. */
  358. inline int meshopt_quantizeSnorm(float v, int N);
  359. /**
  360. * Quantize a float into half-precision floating point value
  361. * Generates +-inf for overflow, preserves NaN, flushes denormals to zero, rounds to nearest
  362. * Representable magnitude range: [6e-5; 65504]
  363. * Maximum relative reconstruction error: 5e-4
  364. */
  365. inline unsigned short meshopt_quantizeHalf(float v);
  366. /**
  367. * Quantize a float into a floating point value with a limited number of significant mantissa bits
  368. * Generates +-inf for overflow, preserves NaN, flushes denormals to zero, rounds to nearest
  369. * Assumes N is in a valid mantissa precision range, which is 1..23
  370. */
  371. inline float meshopt_quantizeFloat(float v, int N);
  372. #endif
  373. /**
  374. * C++ template interface
  375. *
  376. * These functions mirror the C interface the library provides, providing template-based overloads so that
  377. * the caller can use an arbitrary type for the index data, both for input and output.
  378. * When the supplied type is the same size as that of unsigned int, the wrappers are zero-cost; when it's not,
  379. * the wrappers end up allocating memory and copying index data to convert from one type to another.
  380. */
  381. #if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS)
  382. template <typename T>
  383. inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
  384. template <typename T>
  385. inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count);
  386. template <typename T>
  387. inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap);
  388. template <typename T>
  389. inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride);
  390. template <typename T>
  391. inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count);
  392. template <typename T>
  393. inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count);
  394. template <typename T>
  395. inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size);
  396. template <typename T>
  397. inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold);
  398. template <typename T>
  399. inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count);
  400. template <typename T>
  401. inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
  402. template <typename T>
  403. inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count);
  404. template <typename T>
  405. inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size);
  406. template <typename T>
  407. inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error);
  408. template <typename T>
  409. inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count);
  410. template <typename T>
  411. inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index);
  412. template <typename T>
  413. inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index);
  414. template <typename T>
  415. inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size);
  416. template <typename T>
  417. inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  418. template <typename T>
  419. inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size);
  420. template <typename T>
  421. inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles);
  422. template <typename T>
  423. inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  424. template <typename T>
  425. inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
  426. #endif
  427. /* Inline implementation */
  428. #ifdef __cplusplus
  429. inline int meshopt_quantizeUnorm(float v, int N)
  430. {
  431. const float scale = float((1 << N) - 1);
  432. v = (v >= 0) ? v : 0;
  433. v = (v <= 1) ? v : 1;
  434. return int(v * scale + 0.5f);
  435. }
  436. inline int meshopt_quantizeSnorm(float v, int N)
  437. {
  438. const float scale = float((1 << (N - 1)) - 1);
  439. float round = (v >= 0 ? 0.5f : -0.5f);
  440. v = (v >= -1) ? v : -1;
  441. v = (v <= +1) ? v : +1;
  442. return int(v * scale + round);
  443. }
  444. inline unsigned short meshopt_quantizeHalf(float v)
  445. {
  446. union { float f; unsigned int ui; } u = {v};
  447. unsigned int ui = u.ui;
  448. int s = (ui >> 16) & 0x8000;
  449. int em = ui & 0x7fffffff;
  450. /* bias exponent and round to nearest; 112 is relative exponent bias (127-15) */
  451. int h = (em - (112 << 23) + (1 << 12)) >> 13;
  452. /* underflow: flush to zero; 113 encodes exponent -14 */
  453. h = (em < (113 << 23)) ? 0 : h;
  454. /* overflow: infinity; 143 encodes exponent 16 */
  455. h = (em >= (143 << 23)) ? 0x7c00 : h;
  456. /* NaN; note that we convert all types of NaN to qNaN */
  457. h = (em > (255 << 23)) ? 0x7e00 : h;
  458. return (unsigned short)(s | h);
  459. }
  460. inline float meshopt_quantizeFloat(float v, int N)
  461. {
  462. union { float f; unsigned int ui; } u = {v};
  463. unsigned int ui = u.ui;
  464. const int mask = (1 << (23 - N)) - 1;
  465. const int round = (1 << (23 - N)) >> 1;
  466. int e = ui & 0x7f800000;
  467. unsigned int rui = (ui + round) & ~mask;
  468. /* round all numbers except inf/nan; this is important to make sure nan doesn't overflow into -0 */
  469. ui = e == 0x7f800000 ? ui : rui;
  470. /* flush denormals to zero */
  471. ui = e == 0 ? 0 : ui;
  472. u.ui = ui;
  473. return u.f;
  474. }
  475. #endif
  476. /* Internal implementation helpers */
  477. #ifdef __cplusplus
  478. class meshopt_Allocator
  479. {
  480. public:
  481. template <typename T>
  482. struct StorageT
  483. {
  484. static void* (*allocate)(size_t);
  485. static void (*deallocate)(void*);
  486. };
  487. typedef StorageT<void> Storage;
  488. meshopt_Allocator()
  489. : blocks()
  490. , count(0)
  491. {
  492. }
  493. ~meshopt_Allocator()
  494. {
  495. for (size_t i = count; i > 0; --i)
  496. Storage::deallocate(blocks[i - 1]);
  497. }
  498. template <typename T> T* allocate(size_t size)
  499. {
  500. assert(count < sizeof(blocks) / sizeof(blocks[0]));
  501. T* result = static_cast<T*>(Storage::allocate(size > size_t(-1) / sizeof(T) ? size_t(-1) : size * sizeof(T)));
  502. blocks[count++] = result;
  503. return result;
  504. }
  505. private:
  506. void* blocks[16];
  507. size_t count;
  508. };
  509. // This makes sure that allocate/deallocate are lazily generated in translation units that need them and are deduplicated by the linker
  510. template <typename T> void* (*meshopt_Allocator::StorageT<T>::allocate)(size_t) = operator new;
  511. template <typename T> void (*meshopt_Allocator::StorageT<T>::deallocate)(void*) = operator delete;
  512. #endif
  513. /* Inline implementation for C++ templated wrappers */
  514. #if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS)
  515. template <typename T, bool ZeroCopy = sizeof(T) == sizeof(unsigned int)>
  516. struct meshopt_IndexAdapter;
  517. template <typename T>
  518. struct meshopt_IndexAdapter<T, false>
  519. {
  520. T* result;
  521. unsigned int* data;
  522. size_t count;
  523. meshopt_IndexAdapter(T* result_, const T* input, size_t count_)
  524. : result(result_)
  525. , data(0)
  526. , count(count_)
  527. {
  528. size_t size = count > size_t(-1) / sizeof(unsigned int) ? size_t(-1) : count * sizeof(unsigned int);
  529. data = static_cast<unsigned int*>(meshopt_Allocator::Storage::allocate(size));
  530. if (input)
  531. {
  532. for (size_t i = 0; i < count; ++i)
  533. data[i] = input[i];
  534. }
  535. }
  536. ~meshopt_IndexAdapter()
  537. {
  538. if (result)
  539. {
  540. for (size_t i = 0; i < count; ++i)
  541. result[i] = T(data[i]);
  542. }
  543. meshopt_Allocator::Storage::deallocate(data);
  544. }
  545. };
  546. template <typename T>
  547. struct meshopt_IndexAdapter<T, true>
  548. {
  549. unsigned int* data;
  550. meshopt_IndexAdapter(T* result, const T* input, size_t)
  551. : data(reinterpret_cast<unsigned int*>(result ? result : const_cast<T*>(input)))
  552. {
  553. }
  554. };
  555. template <typename T>
  556. inline size_t meshopt_generateVertexRemap(unsigned int* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
  557. {
  558. meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0);
  559. return meshopt_generateVertexRemap(destination, indices ? in.data : 0, index_count, vertices, vertex_count, vertex_size);
  560. }
  561. template <typename T>
  562. inline size_t meshopt_generateVertexRemapMulti(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count)
  563. {
  564. meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0);
  565. return meshopt_generateVertexRemapMulti(destination, indices ? in.data : 0, index_count, vertex_count, streams, stream_count);
  566. }
  567. template <typename T>
  568. inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap)
  569. {
  570. meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0);
  571. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  572. meshopt_remapIndexBuffer(out.data, indices ? in.data : 0, index_count, remap);
  573. }
  574. template <typename T>
  575. inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size, size_t vertex_stride)
  576. {
  577. meshopt_IndexAdapter<T> in(0, indices, index_count);
  578. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  579. meshopt_generateShadowIndexBuffer(out.data, in.data, index_count, vertices, vertex_count, vertex_size, vertex_stride);
  580. }
  581. template <typename T>
  582. inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count)
  583. {
  584. meshopt_IndexAdapter<T> in(0, indices, index_count);
  585. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  586. meshopt_generateShadowIndexBufferMulti(out.data, in.data, index_count, vertex_count, streams, stream_count);
  587. }
  588. template <typename T>
  589. inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count)
  590. {
  591. meshopt_IndexAdapter<T> in(0, indices, index_count);
  592. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  593. meshopt_optimizeVertexCache(out.data, in.data, index_count, vertex_count);
  594. }
  595. template <typename T>
  596. inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
  597. {
  598. meshopt_IndexAdapter<T> in(0, indices, index_count);
  599. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  600. meshopt_optimizeVertexCacheFifo(out.data, in.data, index_count, vertex_count, cache_size);
  601. }
  602. template <typename T>
  603. inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, float threshold)
  604. {
  605. meshopt_IndexAdapter<T> in(0, indices, index_count);
  606. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  607. meshopt_optimizeOverdraw(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, threshold);
  608. }
  609. template <typename T>
  610. inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count)
  611. {
  612. meshopt_IndexAdapter<T> in(0, indices, index_count);
  613. return meshopt_optimizeVertexFetchRemap(destination, in.data, index_count, vertex_count);
  614. }
  615. template <typename T>
  616. inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
  617. {
  618. meshopt_IndexAdapter<T> inout(indices, indices, index_count);
  619. return meshopt_optimizeVertexFetch(destination, inout.data, index_count, vertices, vertex_count, vertex_size);
  620. }
  621. template <typename T>
  622. inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count)
  623. {
  624. meshopt_IndexAdapter<T> in(0, indices, index_count);
  625. return meshopt_encodeIndexBuffer(buffer, buffer_size, in.data, index_count);
  626. }
  627. template <typename T>
  628. inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size)
  629. {
  630. char index_size_valid[sizeof(T) == 2 || sizeof(T) == 4 ? 1 : -1];
  631. (void)index_size_valid;
  632. return meshopt_decodeIndexBuffer(destination, index_count, sizeof(T), buffer, buffer_size);
  633. }
  634. template <typename T>
  635. inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count, float target_error)
  636. {
  637. meshopt_IndexAdapter<T> in(0, indices, index_count);
  638. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  639. return meshopt_simplify(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error);
  640. }
  641. template <typename T>
  642. inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t target_index_count)
  643. {
  644. meshopt_IndexAdapter<T> in(0, indices, index_count);
  645. meshopt_IndexAdapter<T> out(destination, 0, target_index_count);
  646. return meshopt_simplifySloppy(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count);
  647. }
  648. template <typename T>
  649. inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index)
  650. {
  651. meshopt_IndexAdapter<T> in(0, indices, index_count);
  652. meshopt_IndexAdapter<T> out(destination, 0, (index_count / 3) * 5);
  653. return meshopt_stripify(out.data, in.data, index_count, vertex_count, unsigned(restart_index));
  654. }
  655. template <typename T>
  656. inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index)
  657. {
  658. meshopt_IndexAdapter<T> in(0, indices, index_count);
  659. meshopt_IndexAdapter<T> out(destination, 0, (index_count - 2) * 3);
  660. return meshopt_unstripify(out.data, in.data, index_count, unsigned(restart_index));
  661. }
  662. template <typename T>
  663. inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int buffer_size)
  664. {
  665. meshopt_IndexAdapter<T> in(0, indices, index_count);
  666. return meshopt_analyzeVertexCache(in.data, index_count, vertex_count, cache_size, warp_size, buffer_size);
  667. }
  668. template <typename T>
  669. inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
  670. {
  671. meshopt_IndexAdapter<T> in(0, indices, index_count);
  672. return meshopt_analyzeOverdraw(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
  673. }
  674. template <typename T>
  675. inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size)
  676. {
  677. meshopt_IndexAdapter<T> in(0, indices, index_count);
  678. return meshopt_analyzeVertexFetch(in.data, index_count, vertex_count, vertex_size);
  679. }
  680. template <typename T>
  681. inline size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
  682. {
  683. meshopt_IndexAdapter<T> in(0, indices, index_count);
  684. return meshopt_buildMeshlets(destination, in.data, index_count, vertex_count, max_vertices, max_triangles);
  685. }
  686. template <typename T>
  687. inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
  688. {
  689. meshopt_IndexAdapter<T> in(0, indices, index_count);
  690. return meshopt_computeClusterBounds(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
  691. }
  692. template <typename T>
  693. inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
  694. {
  695. meshopt_IndexAdapter<T> in(0, indices, index_count);
  696. meshopt_IndexAdapter<T> out(destination, 0, index_count);
  697. meshopt_spatialSortTriangles(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
  698. }
  699. #endif
  700. /**
  701. * Copyright (c) 2016-2019 Arseny Kapoulkine
  702. *
  703. * Permission is hereby granted, free of charge, to any person
  704. * obtaining a copy of this software and associated documentation
  705. * files (the "Software"), to deal in the Software without
  706. * restriction, including without limitation the rights to use,
  707. * copy, modify, merge, publish, distribute, sublicense, and/or sell
  708. * copies of the Software, and to permit persons to whom the
  709. * Software is furnished to do so, subject to the following
  710. * conditions:
  711. *
  712. * The above copyright notice and this permission notice shall be
  713. * included in all copies or substantial portions of the Software.
  714. *
  715. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  716. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  717. * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  718. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  719. * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  720. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  721. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  722. * OTHER DEALINGS IN THE SOFTWARE.
  723. */