|
@@ -413,7 +413,168 @@ inline float meshopt_quantizeFloat(float v, int N);
|
|
|
* When the supplied type is the same size as that of unsigned int, the wrappers are zero-cost; when it's not,
|
|
* When the supplied type is the same size as that of unsigned int, the wrappers are zero-cost; when it's not,
|
|
|
* the wrappers end up allocating memory and copying index data to convert from one type to another.
|
|
* the wrappers end up allocating memory and copying index data to convert from one type to another.
|
|
|
*/
|
|
*/
|
|
|
|
|
+#if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS)
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+template <typename T>
|
|
|
|
|
+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);
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+/* Inline implementation */
|
|
|
#ifdef __cplusplus
|
|
#ifdef __cplusplus
|
|
|
|
|
+inline int meshopt_quantizeUnorm(float v, int N)
|
|
|
|
|
+{
|
|
|
|
|
+ const float scale = float((1 << N) - 1);
|
|
|
|
|
+
|
|
|
|
|
+ v = (v >= 0) ? v : 0;
|
|
|
|
|
+ v = (v <= 1) ? v : 1;
|
|
|
|
|
+
|
|
|
|
|
+ return int(v * scale + 0.5f);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline int meshopt_quantizeSnorm(float v, int N)
|
|
|
|
|
+{
|
|
|
|
|
+ const float scale = float((1 << (N - 1)) - 1);
|
|
|
|
|
+
|
|
|
|
|
+ float round = (v >= 0 ? 0.5f : -0.5f);
|
|
|
|
|
+
|
|
|
|
|
+ v = (v >= -1) ? v : -1;
|
|
|
|
|
+ v = (v <= +1) ? v : +1;
|
|
|
|
|
+
|
|
|
|
|
+ return int(v * scale + round);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline unsigned short meshopt_quantizeHalf(float v)
|
|
|
|
|
+{
|
|
|
|
|
+ union { float f; unsigned int ui; } u = {v};
|
|
|
|
|
+ unsigned int ui = u.ui;
|
|
|
|
|
+
|
|
|
|
|
+ int s = (ui >> 16) & 0x8000;
|
|
|
|
|
+ int em = ui & 0x7fffffff;
|
|
|
|
|
+
|
|
|
|
|
+ /* bias exponent and round to nearest; 112 is relative exponent bias (127-15) */
|
|
|
|
|
+ int h = (em - (112 << 23) + (1 << 12)) >> 13;
|
|
|
|
|
+
|
|
|
|
|
+ /* underflow: flush to zero; 113 encodes exponent -14 */
|
|
|
|
|
+ h = (em < (113 << 23)) ? 0 : h;
|
|
|
|
|
+
|
|
|
|
|
+ /* overflow: infinity; 143 encodes exponent 16 */
|
|
|
|
|
+ h = (em >= (143 << 23)) ? 0x7c00 : h;
|
|
|
|
|
+
|
|
|
|
|
+ /* NaN; note that we convert all types of NaN to qNaN */
|
|
|
|
|
+ h = (em > (255 << 23)) ? 0x7e00 : h;
|
|
|
|
|
+
|
|
|
|
|
+ return (unsigned short)(s | h);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+inline float meshopt_quantizeFloat(float v, int N)
|
|
|
|
|
+{
|
|
|
|
|
+ union { float f; unsigned int ui; } u = {v};
|
|
|
|
|
+ unsigned int ui = u.ui;
|
|
|
|
|
+
|
|
|
|
|
+ const int mask = (1 << (23 - N)) - 1;
|
|
|
|
|
+ const int round = (1 << (23 - N)) >> 1;
|
|
|
|
|
+
|
|
|
|
|
+ int e = ui & 0x7f800000;
|
|
|
|
|
+ unsigned int rui = (ui + round) & ~mask;
|
|
|
|
|
+
|
|
|
|
|
+ /* round all numbers except inf/nan; this is important to make sure nan doesn't overflow into -0 */
|
|
|
|
|
+ ui = e == 0x7f800000 ? ui : rui;
|
|
|
|
|
+
|
|
|
|
|
+ /* flush denormals to zero */
|
|
|
|
|
+ ui = e == 0 ? 0 : ui;
|
|
|
|
|
+
|
|
|
|
|
+ u.ui = ui;
|
|
|
|
|
+ return u.f;
|
|
|
|
|
+}
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+/* Internal implementation helpers */
|
|
|
|
|
+#ifdef __cplusplus
|
|
|
|
|
+class meshopt_Allocator
|
|
|
|
|
+{
|
|
|
|
|
+public:
|
|
|
|
|
+ template <typename T>
|
|
|
|
|
+ struct StorageT
|
|
|
|
|
+ {
|
|
|
|
|
+ static void* (*allocate)(size_t);
|
|
|
|
|
+ static void (*deallocate)(void*);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ typedef StorageT<void> Storage;
|
|
|
|
|
+
|
|
|
|
|
+ meshopt_Allocator()
|
|
|
|
|
+ : blocks()
|
|
|
|
|
+ , count(0)
|
|
|
|
|
+ {
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ ~meshopt_Allocator()
|
|
|
|
|
+ {
|
|
|
|
|
+ for (size_t i = count; i > 0; --i)
|
|
|
|
|
+ Storage::deallocate(blocks[i - 1]);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ template <typename T> T* allocate(size_t size)
|
|
|
|
|
+ {
|
|
|
|
|
+ assert(count < sizeof(blocks) / sizeof(blocks[0]));
|
|
|
|
|
+ T* result = static_cast<T*>(Storage::allocate(size > size_t(-1) / sizeof(T) ? size_t(-1) : size * sizeof(T)));
|
|
|
|
|
+ blocks[count++] = result;
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+private:
|
|
|
|
|
+ void* blocks[16];
|
|
|
|
|
+ size_t count;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// This makes sure that allocate/deallocate are lazily generated in translation units that need them and are deduplicated by the linker
|
|
|
|
|
+template <typename T> void* (*meshopt_Allocator::StorageT<T>::allocate)(size_t) = operator new;
|
|
|
|
|
+template <typename T> void (*meshopt_Allocator::StorageT<T>::deallocate)(void*) = operator delete;
|
|
|
|
|
+#endif
|
|
|
|
|
+
|
|
|
|
|
+/* Inline implementation for C++ templated wrappers */
|
|
|
|
|
+#if defined(__cplusplus) && !defined(MESHOPTIMIZER_NO_WRAPPERS)
|
|
|
template <typename T, bool ZeroCopy = sizeof(T) == sizeof(unsigned int)>
|
|
template <typename T, bool ZeroCopy = sizeof(T) == sizeof(unsigned int)>
|
|
|
struct meshopt_IndexAdapter;
|
|
struct meshopt_IndexAdapter;
|
|
|
|
|
|
|
@@ -429,7 +590,9 @@ struct meshopt_IndexAdapter<T, false>
|
|
|
, data(0)
|
|
, data(0)
|
|
|
, count(count_)
|
|
, count(count_)
|
|
|
{
|
|
{
|
|
|
- data = new unsigned int[count];
|
|
|
|
|
|
|
+ size_t size = count > size_t(-1) / sizeof(unsigned int) ? size_t(-1) : count * sizeof(unsigned int);
|
|
|
|
|
+
|
|
|
|
|
+ data = static_cast<unsigned int*>(meshopt_Allocator::Storage::allocate(size));
|
|
|
|
|
|
|
|
if (input)
|
|
if (input)
|
|
|
{
|
|
{
|
|
@@ -446,7 +609,7 @@ struct meshopt_IndexAdapter<T, false>
|
|
|
result[i] = T(data[i]);
|
|
result[i] = T(data[i]);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- delete[] data;
|
|
|
|
|
|
|
+ meshopt_Allocator::Storage::deallocate(data);
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -487,7 +650,7 @@ inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t in
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
template <typename T>
|
|
|
-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)
|
|
|
|
|
|
|
+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)
|
|
|
{
|
|
{
|
|
|
meshopt_IndexAdapter<T> in(0, indices, index_count);
|
|
meshopt_IndexAdapter<T> in(0, indices, index_count);
|
|
|
meshopt_IndexAdapter<T> out(destination, 0, index_count);
|
|
meshopt_IndexAdapter<T> out(destination, 0, index_count);
|
|
@@ -496,7 +659,7 @@ void meshopt_generateShadowIndexBuffer(T* destination, const T* indices, size_t
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
template <typename T>
|
|
|
-void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indices, size_t index_count, size_t vertex_count, const meshopt_Stream* streams, size_t stream_count)
|
|
|
|
|
|
|
+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)
|
|
|
{
|
|
{
|
|
|
meshopt_IndexAdapter<T> in(0, indices, index_count);
|
|
meshopt_IndexAdapter<T> in(0, indices, index_count);
|
|
|
meshopt_IndexAdapter<T> out(destination, 0, index_count);
|
|
meshopt_IndexAdapter<T> out(destination, 0, index_count);
|
|
@@ -650,119 +813,6 @@ inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_
|
|
|
}
|
|
}
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
-/* Inline implementation */
|
|
|
|
|
-#ifdef __cplusplus
|
|
|
|
|
-inline int meshopt_quantizeUnorm(float v, int N)
|
|
|
|
|
-{
|
|
|
|
|
- const float scale = float((1 << N) - 1);
|
|
|
|
|
-
|
|
|
|
|
- v = (v >= 0) ? v : 0;
|
|
|
|
|
- v = (v <= 1) ? v : 1;
|
|
|
|
|
-
|
|
|
|
|
- return int(v * scale + 0.5f);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline int meshopt_quantizeSnorm(float v, int N)
|
|
|
|
|
-{
|
|
|
|
|
- const float scale = float((1 << (N - 1)) - 1);
|
|
|
|
|
-
|
|
|
|
|
- float round = (v >= 0 ? 0.5f : -0.5f);
|
|
|
|
|
-
|
|
|
|
|
- v = (v >= -1) ? v : -1;
|
|
|
|
|
- v = (v <= +1) ? v : +1;
|
|
|
|
|
-
|
|
|
|
|
- return int(v * scale + round);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline unsigned short meshopt_quantizeHalf(float v)
|
|
|
|
|
-{
|
|
|
|
|
- union { float f; unsigned int ui; } u = {v};
|
|
|
|
|
- unsigned int ui = u.ui;
|
|
|
|
|
-
|
|
|
|
|
- int s = (ui >> 16) & 0x8000;
|
|
|
|
|
- int em = ui & 0x7fffffff;
|
|
|
|
|
-
|
|
|
|
|
- /* bias exponent and round to nearest; 112 is relative exponent bias (127-15) */
|
|
|
|
|
- int h = (em - (112 << 23) + (1 << 12)) >> 13;
|
|
|
|
|
-
|
|
|
|
|
- /* underflow: flush to zero; 113 encodes exponent -14 */
|
|
|
|
|
- h = (em < (113 << 23)) ? 0 : h;
|
|
|
|
|
-
|
|
|
|
|
- /* overflow: infinity; 143 encodes exponent 16 */
|
|
|
|
|
- h = (em >= (143 << 23)) ? 0x7c00 : h;
|
|
|
|
|
-
|
|
|
|
|
- /* NaN; note that we convert all types of NaN to qNaN */
|
|
|
|
|
- h = (em > (255 << 23)) ? 0x7e00 : h;
|
|
|
|
|
-
|
|
|
|
|
- return (unsigned short)(s | h);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-inline float meshopt_quantizeFloat(float v, int N)
|
|
|
|
|
-{
|
|
|
|
|
- union { float f; unsigned int ui; } u = {v};
|
|
|
|
|
- unsigned int ui = u.ui;
|
|
|
|
|
-
|
|
|
|
|
- const int mask = (1 << (23 - N)) - 1;
|
|
|
|
|
- const int round = (1 << (23 - N)) >> 1;
|
|
|
|
|
-
|
|
|
|
|
- int e = ui & 0x7f800000;
|
|
|
|
|
- unsigned int rui = (ui + round) & ~mask;
|
|
|
|
|
-
|
|
|
|
|
- /* round all numbers except inf/nan; this is important to make sure nan doesn't overflow into -0 */
|
|
|
|
|
- ui = e == 0x7f800000 ? ui : rui;
|
|
|
|
|
-
|
|
|
|
|
- /* flush denormals to zero */
|
|
|
|
|
- ui = e == 0 ? 0 : ui;
|
|
|
|
|
-
|
|
|
|
|
- u.ui = ui;
|
|
|
|
|
- return u.f;
|
|
|
|
|
-}
|
|
|
|
|
-#endif
|
|
|
|
|
-
|
|
|
|
|
-/* Internal implementation helpers */
|
|
|
|
|
-#ifdef __cplusplus
|
|
|
|
|
-class meshopt_Allocator
|
|
|
|
|
-{
|
|
|
|
|
-public:
|
|
|
|
|
- template <typename T>
|
|
|
|
|
- struct StorageT
|
|
|
|
|
- {
|
|
|
|
|
- static void* (*allocate)(size_t);
|
|
|
|
|
- static void (*deallocate)(void*);
|
|
|
|
|
- };
|
|
|
|
|
-
|
|
|
|
|
- typedef StorageT<void> Storage;
|
|
|
|
|
-
|
|
|
|
|
- meshopt_Allocator()
|
|
|
|
|
- : blocks()
|
|
|
|
|
- , count(0)
|
|
|
|
|
- {
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- ~meshopt_Allocator()
|
|
|
|
|
- {
|
|
|
|
|
- for (size_t i = count; i > 0; --i)
|
|
|
|
|
- Storage::deallocate(blocks[i - 1]);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- template <typename T> T* allocate(size_t size)
|
|
|
|
|
- {
|
|
|
|
|
- assert(count < sizeof(blocks) / sizeof(blocks[0]));
|
|
|
|
|
- T* result = static_cast<T*>(Storage::allocate(size > size_t(-1) / sizeof(T) ? size_t(-1) : size * sizeof(T)));
|
|
|
|
|
- blocks[count++] = result;
|
|
|
|
|
- return result;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-private:
|
|
|
|
|
- void* blocks[16];
|
|
|
|
|
- size_t count;
|
|
|
|
|
-};
|
|
|
|
|
-
|
|
|
|
|
-// This makes sure that allocate/deallocate are lazily generated in translation units that need them and are deduplicated by the linker
|
|
|
|
|
-template <typename T> void* (*meshopt_Allocator::StorageT<T>::allocate)(size_t) = operator new;
|
|
|
|
|
-template <typename T> void (*meshopt_Allocator::StorageT<T>::deallocate)(void*) = operator delete;
|
|
|
|
|
-#endif
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* Copyright (c) 2016-2019 Arseny Kapoulkine
|
|
* Copyright (c) 2016-2019 Arseny Kapoulkine
|
|
|
*
|
|
*
|