Updated meshoptimizer.

This commit is contained in:
Бранимир Караџић 2023-11-03 17:49:42 -07:00
parent fe578a3323
commit 0d6d961680
5 changed files with 155 additions and 96 deletions

View File

@ -13,7 +13,7 @@ namespace meshopt
const unsigned char kIndexHeader = 0xe0; const unsigned char kIndexHeader = 0xe0;
const unsigned char kSequenceHeader = 0xd0; const unsigned char kSequenceHeader = 0xd0;
static int gEncodeIndexVersion = 0; static int gEncodeIndexVersion = 1;
typedef unsigned int VertexFifo[16]; typedef unsigned int VertexFifo[16];
typedef unsigned int EdgeFifo[16][2]; typedef unsigned int EdgeFifo[16][2];

View File

@ -157,7 +157,7 @@ static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, c
} }
assert(false && "Hash table is full"); // unreachable assert(false && "Hash table is full"); // unreachable
return 0; return NULL;
} }
static void buildPositionRemap(unsigned int* remap, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator) static void buildPositionRemap(unsigned int* remap, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator)

View File

@ -1,5 +1,5 @@
/** /**
* meshoptimizer - version 0.19 * meshoptimizer - version 0.20
* *
* Copyright (C) 2016-2023, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Copyright (C) 2016-2023, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at https://github.com/zeux/meshoptimizer * Report bugs and download new versions at https://github.com/zeux/meshoptimizer
@ -12,7 +12,7 @@
#include <stddef.h> #include <stddef.h>
/* Version macro; major * 1000 + minor * 10 + patch */ /* Version macro; major * 1000 + minor * 10 + patch */
#define MESHOPTIMIZER_VERSION 190 /* 0.19 */ #define MESHOPTIMIZER_VERSION 200 /* 0.20 */
/* If no API is defined, assume default */ /* If no API is defined, assume default */
#ifndef MESHOPTIMIZER_API #ifndef MESHOPTIMIZER_API
@ -67,6 +67,7 @@ MESHOPTIMIZER_API size_t meshopt_generateVertexRemap(unsigned int* destination,
* *
* destination must contain enough space for the resulting remap table (vertex_count elements) * destination must contain enough space for the resulting remap table (vertex_count elements)
* indices can be NULL if the input is unindexed * indices can be NULL if the input is unindexed
* stream_count must be <= 16
*/ */
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); 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);
@ -103,6 +104,7 @@ MESHOPTIMIZER_API void meshopt_generateShadowIndexBuffer(unsigned int* destinati
* Note that binary equivalence considers all size bytes in each stream, including padding which should be zero-initialized. * Note that binary equivalence considers all size bytes in each stream, including padding which should be zero-initialized.
* *
* destination must contain enough space for the resulting index buffer (index_count elements) * destination must contain enough space for the resulting index buffer (index_count elements)
* stream_count must be <= 16
*/ */
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); 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);
@ -354,6 +356,7 @@ MESHOPTIMIZER_API size_t meshopt_simplify(unsigned int* destination, const unsig
* *
* vertex_attributes should have attribute_count floats for each vertex * vertex_attributes should have attribute_count floats for each vertex
* attribute_weights should have attribute_count floats in total; the weights determine relative priority of attributes between each other and wrt position. The recommended weight range is [1e-3..1e-1], assuming attribute data is in [0..1] range. * attribute_weights should have attribute_count floats in total; the weights determine relative priority of attributes between each other and wrt position. The recommended weight range is [1e-3..1e-1], assuming attribute data is in [0..1] range.
* attribute_count must be <= 16
* TODO target_error/result_error currently use combined distance+attribute error; this may change in the future * TODO target_error/result_error currently use combined distance+attribute error; this may change in the future
*/ */
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* result_error); MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* result_error);
@ -382,8 +385,9 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destinati
* *
* destination must contain enough space for the target index buffer (target_vertex_count elements) * destination must contain enough space for the target index buffer (target_vertex_count elements)
* vertex_positions should have float3 position in the first 12 bytes of each vertex * vertex_positions should have float3 position in the first 12 bytes of each vertex
* vertex_colors should can be NULL; when it's not NULL, it should have float3 color in the first 12 bytes of each vertex
*/ */
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); MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_colors, size_t vertex_colors_stride, float color_weight, size_t target_vertex_count);
/** /**
* Returns the error scaling factor used by the simplifier to convert between absolute and relative extents * Returns the error scaling factor used by the simplifier to convert between absolute and relative extents
@ -531,13 +535,14 @@ MESHOPTIMIZER_API struct meshopt_Bounds meshopt_computeClusterBounds(const unsig
MESHOPTIMIZER_API struct meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); MESHOPTIMIZER_API struct meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices, const unsigned char* meshlet_triangles, size_t triangle_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
/** /**
* Experimental: Spatial sorter * Spatial sorter
* Generates a remap table that can be used to reorder points for spatial locality. * Generates a remap table that can be used to reorder points for spatial locality.
* Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer. * Resulting remap table maps old vertices to new vertices and can be used in meshopt_remapVertexBuffer.
* *
* destination must contain enough space for the resulting remap table (vertex_count elements) * destination must contain enough space for the resulting remap table (vertex_count elements)
* vertex_positions should have float3 position in the first 12 bytes of each vertex
*/ */
MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride); MESHOPTIMIZER_API void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
/** /**
* Experimental: Spatial sorter * Experimental: Spatial sorter
@ -642,11 +647,11 @@ inline size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_s
template <typename T> template <typename T>
inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size); inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const unsigned char* buffer, size_t buffer_size);
template <typename T> 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, unsigned int options = 0, float* result_error = 0); 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, unsigned int options = 0, float* result_error = NULL);
template <typename T> template <typename T>
inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options = 0, float* result_error = 0); inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options = 0, float* result_error = NULL);
template <typename T> 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, float target_error, float* result_error = 0); 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, float target_error, float* result_error = NULL);
template <typename T> template <typename T>
inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index); inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index);
template <typename T> template <typename T>
@ -757,7 +762,7 @@ struct meshopt_IndexAdapter<T, false>
meshopt_IndexAdapter(T* result_, const T* input, size_t count_) meshopt_IndexAdapter(T* result_, const T* input, size_t count_)
: result(result_) : result(result_)
, data(0) , data(NULL)
, count(count_) , count(count_)
{ {
size_t size = count > size_t(-1) / sizeof(unsigned int) ? size_t(-1) : count * sizeof(unsigned int); size_t size = count > size_t(-1) / sizeof(unsigned int) ? size_t(-1) : count * sizeof(unsigned int);
@ -797,33 +802,33 @@ struct meshopt_IndexAdapter<T, true>
template <typename T> 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) 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)
{ {
meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0); meshopt_IndexAdapter<T> in(NULL, indices, indices ? index_count : 0);
return meshopt_generateVertexRemap(destination, indices ? in.data : 0, index_count, vertices, vertex_count, vertex_size); return meshopt_generateVertexRemap(destination, indices ? in.data : NULL, index_count, vertices, vertex_count, vertex_size);
} }
template <typename T> 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) 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)
{ {
meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0); meshopt_IndexAdapter<T> in(NULL, indices, indices ? index_count : 0);
return meshopt_generateVertexRemapMulti(destination, indices ? in.data : 0, index_count, vertex_count, streams, stream_count); return meshopt_generateVertexRemapMulti(destination, indices ? in.data : NULL, index_count, vertex_count, streams, stream_count);
} }
template <typename T> template <typename T>
inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap) inline void meshopt_remapIndexBuffer(T* destination, const T* indices, size_t index_count, const unsigned int* remap)
{ {
meshopt_IndexAdapter<T> in(0, indices, indices ? index_count : 0); meshopt_IndexAdapter<T> in(NULL, indices, indices ? index_count : 0);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, 0, index_count);
meshopt_remapIndexBuffer(out.data, indices ? in.data : 0, index_count, remap); meshopt_remapIndexBuffer(out.data, indices ? in.data : NULL, index_count, remap);
} }
template <typename T> 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) 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(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
meshopt_generateShadowIndexBuffer(out.data, in.data, index_count, vertices, vertex_count, vertex_size, vertex_stride); meshopt_generateShadowIndexBuffer(out.data, in.data, index_count, vertices, vertex_count, vertex_size, vertex_stride);
} }
@ -831,8 +836,8 @@ inline void meshopt_generateShadowIndexBuffer(T* destination, const T* indices,
template <typename T> 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) 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(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
meshopt_generateShadowIndexBufferMulti(out.data, in.data, index_count, vertex_count, streams, stream_count); meshopt_generateShadowIndexBufferMulti(out.data, in.data, index_count, vertex_count, streams, stream_count);
} }
@ -840,8 +845,8 @@ inline void meshopt_generateShadowIndexBufferMulti(T* destination, const T* indi
template <typename T> template <typename T>
inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count * 2); meshopt_IndexAdapter<T> out(destination, NULL, index_count * 2);
meshopt_generateAdjacencyIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); meshopt_generateAdjacencyIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
} }
@ -849,8 +854,8 @@ inline void meshopt_generateAdjacencyIndexBuffer(T* destination, const T* indice
template <typename T> template <typename T>
inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride) inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count * 4); meshopt_IndexAdapter<T> out(destination, NULL, index_count * 4);
meshopt_generateTessellationIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); meshopt_generateTessellationIndexBuffer(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
} }
@ -858,8 +863,8 @@ inline void meshopt_generateTessellationIndexBuffer(T* destination, const T* ind
template <typename T> template <typename T>
inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count) inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t index_count, size_t vertex_count)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
meshopt_optimizeVertexCache(out.data, in.data, index_count, vertex_count); meshopt_optimizeVertexCache(out.data, in.data, index_count, vertex_count);
} }
@ -867,8 +872,8 @@ inline void meshopt_optimizeVertexCache(T* destination, const T* indices, size_t
template <typename T> template <typename T>
inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count) inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, size_t index_count, size_t vertex_count)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
meshopt_optimizeVertexCacheStrip(out.data, in.data, index_count, vertex_count); meshopt_optimizeVertexCacheStrip(out.data, in.data, index_count, vertex_count);
} }
@ -876,8 +881,8 @@ inline void meshopt_optimizeVertexCacheStrip(T* destination, const T* indices, s
template <typename T> template <typename T>
inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size) inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
meshopt_optimizeVertexCacheFifo(out.data, in.data, index_count, vertex_count, cache_size); meshopt_optimizeVertexCacheFifo(out.data, in.data, index_count, vertex_count, cache_size);
} }
@ -885,8 +890,8 @@ inline void meshopt_optimizeVertexCacheFifo(T* destination, const T* indices, si
template <typename T> 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) 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)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
meshopt_optimizeOverdraw(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, threshold); meshopt_optimizeOverdraw(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, threshold);
} }
@ -894,7 +899,7 @@ inline void meshopt_optimizeOverdraw(T* destination, const T* indices, size_t in
template <typename T> template <typename T>
inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count) inline size_t meshopt_optimizeVertexFetchRemap(unsigned int* destination, const T* indices, size_t index_count, size_t vertex_count)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_optimizeVertexFetchRemap(destination, in.data, index_count, vertex_count); return meshopt_optimizeVertexFetchRemap(destination, in.data, index_count, vertex_count);
} }
@ -910,7 +915,7 @@ inline size_t meshopt_optimizeVertexFetch(void* destination, T* indices, size_t
template <typename T> template <typename T>
inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count) inline size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_encodeIndexBuffer(buffer, buffer_size, in.data, index_count); return meshopt_encodeIndexBuffer(buffer, buffer_size, in.data, index_count);
} }
@ -927,7 +932,7 @@ inline int meshopt_decodeIndexBuffer(T* destination, size_t index_count, const u
template <typename T> template <typename T>
inline size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count) inline size_t meshopt_encodeIndexSequence(unsigned char* buffer, size_t buffer_size, const T* indices, size_t index_count)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_encodeIndexSequence(buffer, buffer_size, in.data, index_count); return meshopt_encodeIndexSequence(buffer, buffer_size, in.data, index_count);
} }
@ -944,8 +949,8 @@ inline int meshopt_decodeIndexSequence(T* destination, size_t index_count, const
template <typename T> 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, unsigned int options, float* result_error) 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, unsigned int options, float* result_error)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
return meshopt_simplify(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, options, result_error); return meshopt_simplify(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, options, result_error);
} }
@ -953,8 +958,8 @@ inline size_t meshopt_simplify(T* destination, const T* indices, size_t index_co
template <typename T> template <typename T>
inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* result_error) inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* result_error)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
return meshopt_simplifyWithAttributes(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, vertex_attributes, vertex_attributes_stride, attribute_weights, attribute_count, target_index_count, target_error, options, result_error); return meshopt_simplifyWithAttributes(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, vertex_attributes, vertex_attributes_stride, attribute_weights, attribute_count, target_index_count, target_error, options, result_error);
} }
@ -962,8 +967,8 @@ inline size_t meshopt_simplifyWithAttributes(T* destination, const T* indices, s
template <typename T> 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, float target_error, float* result_error) 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, float target_error, float* result_error)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
return meshopt_simplifySloppy(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, result_error); return meshopt_simplifySloppy(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, result_error);
} }
@ -971,8 +976,8 @@ inline size_t meshopt_simplifySloppy(T* destination, const T* indices, size_t in
template <typename T> template <typename T>
inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index) inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_count, size_t vertex_count, T restart_index)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, (index_count / 3) * 5); meshopt_IndexAdapter<T> out(destination, NULL, (index_count / 3) * 5);
return meshopt_stripify(out.data, in.data, index_count, vertex_count, unsigned(restart_index)); return meshopt_stripify(out.data, in.data, index_count, vertex_count, unsigned(restart_index));
} }
@ -980,8 +985,8 @@ inline size_t meshopt_stripify(T* destination, const T* indices, size_t index_co
template <typename T> template <typename T>
inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index) inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_count, T restart_index)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, (index_count - 2) * 3); meshopt_IndexAdapter<T> out(destination, NULL, (index_count - 2) * 3);
return meshopt_unstripify(out.data, in.data, index_count, unsigned(restart_index)); return meshopt_unstripify(out.data, in.data, index_count, unsigned(restart_index));
} }
@ -989,7 +994,7 @@ inline size_t meshopt_unstripify(T* destination, const T* indices, size_t index_
template <typename T> 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) 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)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_analyzeVertexCache(in.data, index_count, vertex_count, cache_size, warp_size, buffer_size); return meshopt_analyzeVertexCache(in.data, index_count, vertex_count, cache_size, warp_size, buffer_size);
} }
@ -997,7 +1002,7 @@ inline meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const T* indices
template <typename T> 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) 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)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_analyzeOverdraw(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); return meshopt_analyzeOverdraw(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
} }
@ -1005,7 +1010,7 @@ inline meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const T* indices, size
template <typename T> template <typename T>
inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size) inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices, size_t index_count, size_t vertex_count, size_t vertex_size)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_analyzeVertexFetch(in.data, index_count, vertex_count, vertex_size); return meshopt_analyzeVertexFetch(in.data, index_count, vertex_count, vertex_size);
} }
@ -1013,7 +1018,7 @@ inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices
template <typename T> template <typename T>
inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight) inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride, size_t max_vertices, size_t max_triangles, float cone_weight)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_buildMeshlets(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, max_vertices, max_triangles, cone_weight); return meshopt_buildMeshlets(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, max_vertices, max_triangles, cone_weight);
} }
@ -1021,7 +1026,7 @@ inline size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* mes
template <typename T> template <typename T>
inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles) inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int* meshlet_vertices, unsigned char* meshlet_triangles, const T* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_buildMeshletsScan(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_count, max_vertices, max_triangles); return meshopt_buildMeshletsScan(meshlets, meshlet_vertices, meshlet_triangles, in.data, index_count, vertex_count, max_vertices, max_triangles);
} }
@ -1029,7 +1034,7 @@ inline size_t meshopt_buildMeshletsScan(meshopt_Meshlet* meshlets, unsigned int*
template <typename T> 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) 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)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
return meshopt_computeClusterBounds(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); return meshopt_computeClusterBounds(in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
} }
@ -1037,8 +1042,8 @@ inline meshopt_Bounds meshopt_computeClusterBounds(const T* indices, size_t inde
template <typename T> 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) 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)
{ {
meshopt_IndexAdapter<T> in(0, indices, index_count); meshopt_IndexAdapter<T> in(NULL, indices, index_count);
meshopt_IndexAdapter<T> out(destination, 0, index_count); meshopt_IndexAdapter<T> out(destination, NULL, index_count);
meshopt_spatialSortTriangles(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride); meshopt_spatialSortTriangles(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride);
} }

View File

@ -164,7 +164,7 @@ static T* hashLookup2(T* table, size_t buckets, const Hash& hash, const T& key,
} }
assert(false && "Hash table is full"); // unreachable assert(false && "Hash table is full"); // unreachable
return 0; return NULL;
} }
static void buildPositionRemap(unsigned int* remap, unsigned int* wedge, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator) static void buildPositionRemap(unsigned int* remap, unsigned int* wedge, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, meshopt_Allocator& allocator)
@ -445,6 +445,7 @@ static const size_t kMaxAttributes = 16;
struct Quadric struct Quadric
{ {
// a00*x^2 + a11*y^2 + a22*z^2 + 2*(a10*xy + a20*xz + a21*yz) + b0*x + b1*y + b2*z + c
float a00, a11, a22; float a00, a11, a22;
float a10, a20, a21; float a10, a20, a21;
float b0, b1, b2, c; float b0, b1, b2, c;
@ -453,9 +454,17 @@ struct Quadric
struct QuadricGrad struct QuadricGrad
{ {
// gx*x + gy*y + gz*z + gw
float gx, gy, gz, gw; float gx, gy, gz, gw;
}; };
struct Reservoir
{
float x, y, z;
float r, g, b;
float w;
};
struct Collapse struct Collapse
{ {
unsigned int v0; unsigned int v0;
@ -596,22 +605,6 @@ static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, flo
Q.w = w; Q.w = w;
} }
static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
{
// we need to encode (x - X) ^ 2 + (y - Y)^2 + (z - Z)^2 into the quadric
Q.a00 = w;
Q.a11 = w;
Q.a22 = w;
Q.a10 = 0.f;
Q.a20 = 0.f;
Q.a21 = 0.f;
Q.b0 = -2.f * x * w;
Q.b1 = -2.f * y * w;
Q.b2 = -2.f * z * w;
Q.c = (x * x + y * y + z * z) * w;
Q.w = w;
}
static void quadricFromTriangle(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight) static void quadricFromTriangle(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight)
{ {
Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z}; Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
@ -1330,17 +1323,41 @@ static void fillCellQuadrics(Quadric* cell_quadrics, const unsigned int* indices
} }
} }
static void fillCellQuadrics(Quadric* cell_quadrics, const Vector3* vertex_positions, size_t vertex_count, const unsigned int* vertex_cells) static void fillCellReservoirs(Reservoir* cell_reservoirs, size_t cell_count, const Vector3* vertex_positions, const float* vertex_colors, size_t vertex_colors_stride, size_t vertex_count, const unsigned int* vertex_cells)
{ {
static const float dummy_color[] = { 0.f, 0.f, 0.f };
size_t vertex_colors_stride_float = vertex_colors_stride / sizeof(float);
for (size_t i = 0; i < vertex_count; ++i) for (size_t i = 0; i < vertex_count; ++i)
{ {
unsigned int c = vertex_cells[i]; unsigned int cell = vertex_cells[i];
const Vector3& v = vertex_positions[i]; const Vector3& v = vertex_positions[i];
Reservoir& r = cell_reservoirs[cell];
Quadric Q; const float* color = vertex_colors ? &vertex_colors[i * vertex_colors_stride_float] : dummy_color;
quadricFromPoint(Q, v.x, v.y, v.z, 1.f);
quadricAdd(cell_quadrics[c], Q); r.x += v.x;
r.y += v.y;
r.z += v.z;
r.r += color[0];
r.g += color[1];
r.b += color[2];
r.w += 1.f;
}
for (size_t i = 0; i < cell_count; ++i)
{
Reservoir& r = cell_reservoirs[i];
float iw = r.w == 0.f ? 0.f : 1.f / r.w;
r.x *= iw;
r.y *= iw;
r.z *= iw;
r.r *= iw;
r.g *= iw;
r.b *= iw;
} }
} }
@ -1361,6 +1378,34 @@ static void fillCellRemap(unsigned int* cell_remap, float* cell_errors, size_t c
} }
} }
static void fillCellRemap(unsigned int* cell_remap, float* cell_errors, size_t cell_count, const unsigned int* vertex_cells, const Reservoir* cell_reservoirs, const Vector3* vertex_positions, const float* vertex_colors, size_t vertex_colors_stride, float color_weight, size_t vertex_count)
{
static const float dummy_color[] = { 0.f, 0.f, 0.f };
size_t vertex_colors_stride_float = vertex_colors_stride / sizeof(float);
memset(cell_remap, -1, cell_count * sizeof(unsigned int));
for (size_t i = 0; i < vertex_count; ++i)
{
unsigned int cell = vertex_cells[i];
const Vector3& v = vertex_positions[i];
const Reservoir& r = cell_reservoirs[cell];
const float* color = vertex_colors ? &vertex_colors[i * vertex_colors_stride_float] : dummy_color;
float pos_error = (v.x - r.x) * (v.x - r.x) + (v.y - r.y) * (v.y - r.y) + (v.z - r.z) * (v.z - r.z);
float col_error = (color[0] - r.r) * (color[0] - r.r) + (color[1] - r.g) * (color[1] - r.g) + (color[2] - r.b) * (color[2] - r.b);
float error = pos_error + color_weight * col_error;
if (cell_remap[cell] == ~0u || cell_errors[cell] > error)
{
cell_remap[cell] = unsigned(i);
cell_errors[cell] = error;
}
}
}
static size_t filterTriangles(unsigned int* destination, unsigned int* tritable, size_t tritable_size, const unsigned int* indices, size_t index_count, const unsigned int* vertex_cells, const unsigned int* cell_remap) static size_t filterTriangles(unsigned int* destination, unsigned int* tritable, size_t tritable_size, const unsigned int* indices, size_t index_count, const unsigned int* vertex_cells, const unsigned int* cell_remap)
{ {
TriangleHasher hasher = {destination}; TriangleHasher hasher = {destination};
@ -1418,9 +1463,9 @@ static float interpolate(float y, float x0, float y0, float x1, float y1, float
#ifndef NDEBUG #ifndef NDEBUG
// Note: this is only exposed for debug visualization purposes; do *not* use these in debug builds // Note: this is only exposed for debug visualization purposes; do *not* use these in debug builds
MESHOPTIMIZER_API unsigned char* meshopt_simplifyDebugKind = 0; MESHOPTIMIZER_API unsigned char* meshopt_simplifyDebugKind = NULL;
MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoop = 0; MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoop = NULL;
MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = 0; MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = NULL;
#endif #endif
size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* out_result_error) size_t meshopt_simplifyEdge(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_attributes_data, size_t vertex_attributes_stride, const float* attribute_weights, size_t attribute_count, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
@ -1729,12 +1774,15 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind
return write; return write;
} }
size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, size_t target_vertex_count) size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride, const float* vertex_colors, size_t vertex_colors_stride, float color_weight, size_t target_vertex_count)
{ {
using namespace meshopt; using namespace meshopt;
assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256); assert(vertex_positions_stride >= 12 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0); assert(vertex_positions_stride % sizeof(float) == 0);
assert(vertex_colors_stride == 0 || (vertex_colors_stride >= 12 && vertex_colors_stride <= 256));
assert(vertex_colors_stride % sizeof(float) == 0);
assert(vertex_colors == NULL || vertex_colors_stride != 0);
assert(target_vertex_count <= vertex_count); assert(target_vertex_count <= vertex_count);
size_t target_cell_count = target_vertex_count; size_t target_cell_count = target_vertex_count;
@ -1818,24 +1866,30 @@ size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_pos
computeVertexIds(vertex_ids, vertex_positions, vertex_count, min_grid); computeVertexIds(vertex_ids, vertex_positions, vertex_count, min_grid);
size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count); size_t cell_count = fillVertexCells(table, table_size, vertex_cells, vertex_ids, vertex_count);
// build a quadric for each target cell // accumulate points into a reservoir for each target cell
Quadric* cell_quadrics = allocator.allocate<Quadric>(cell_count); Reservoir* cell_reservoirs = allocator.allocate<Reservoir>(cell_count);
memset(cell_quadrics, 0, cell_count * sizeof(Quadric)); memset(cell_reservoirs, 0, cell_count * sizeof(Reservoir));
fillCellQuadrics(cell_quadrics, vertex_positions, vertex_count, vertex_cells); fillCellReservoirs(cell_reservoirs, cell_count, vertex_positions, vertex_colors, vertex_colors_stride, vertex_count, vertex_cells);
// for each target cell, find the vertex with the minimal error // for each target cell, find the vertex with the minimal error
unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count); unsigned int* cell_remap = allocator.allocate<unsigned int>(cell_count);
float* cell_errors = allocator.allocate<float>(cell_count); float* cell_errors = allocator.allocate<float>(cell_count);
fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_quadrics, vertex_positions, vertex_count); fillCellRemap(cell_remap, cell_errors, cell_count, vertex_cells, cell_reservoirs, vertex_positions, vertex_colors, vertex_colors_stride, color_weight * color_weight, vertex_count);
// copy results to the output // copy results to the output
assert(cell_count <= target_vertex_count); assert(cell_count <= target_vertex_count);
memcpy(destination, cell_remap, sizeof(unsigned int) * cell_count); memcpy(destination, cell_remap, sizeof(unsigned int) * cell_count);
#if TRACE #if TRACE
printf("result: %d cells\n", int(cell_count)); // compute error
float result_error = 0.f;
for (size_t i = 0; i < cell_count; ++i)
result_error = result_error < cell_errors[i] ? cell_errors[i] : result_error;
printf("result: %d cells, %e error\n", int(cell_count), sqrtf(result_error));
#endif #endif
return cell_count; return cell_count;

View File

@ -220,7 +220,7 @@ static unsigned char* encodeBytes(unsigned char* data, unsigned char* data_end,
size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; size_t header_size = (buffer_size / kByteGroupSize + 3) / 4;
if (size_t(data_end - data) < header_size) if (size_t(data_end - data) < header_size)
return 0; return NULL;
data += header_size; data += header_size;
@ -229,7 +229,7 @@ static unsigned char* encodeBytes(unsigned char* data, unsigned char* data_end,
for (size_t i = 0; i < buffer_size; i += kByteGroupSize) for (size_t i = 0; i < buffer_size; i += kByteGroupSize)
{ {
if (size_t(data_end - data) < kByteGroupDecodeLimit) if (size_t(data_end - data) < kByteGroupDecodeLimit)
return 0; return NULL;
int best_bits = 8; int best_bits = 8;
size_t best_size = encodeBytesGroupMeasure(buffer + i, 8); size_t best_size = encodeBytesGroupMeasure(buffer + i, 8);
@ -288,7 +288,7 @@ static unsigned char* encodeVertexBlock(unsigned char* data, unsigned char* data
data = encodeBytes(data, data_end, buffer, (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1)); data = encodeBytes(data, data_end, buffer, (vertex_count + kByteGroupSize - 1) & ~(kByteGroupSize - 1));
if (!data) if (!data)
return 0; return NULL;
} }
memcpy(last_vertex, &vertex_data[vertex_size * (vertex_count - 1)], vertex_size); memcpy(last_vertex, &vertex_data[vertex_size * (vertex_count - 1)], vertex_size);
@ -356,14 +356,14 @@ static const unsigned char* decodeBytes(const unsigned char* data, const unsigne
size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; size_t header_size = (buffer_size / kByteGroupSize + 3) / 4;
if (size_t(data_end - data) < header_size) if (size_t(data_end - data) < header_size)
return 0; return NULL;
data += header_size; data += header_size;
for (size_t i = 0; i < buffer_size; i += kByteGroupSize) for (size_t i = 0; i < buffer_size; i += kByteGroupSize)
{ {
if (size_t(data_end - data) < kByteGroupDecodeLimit) if (size_t(data_end - data) < kByteGroupDecodeLimit)
return 0; return NULL;
size_t header_offset = i / kByteGroupSize; size_t header_offset = i / kByteGroupSize;
@ -388,7 +388,7 @@ static const unsigned char* decodeVertexBlock(const unsigned char* data, const u
{ {
data = decodeBytes(data, data_end, buffer, vertex_count_aligned); data = decodeBytes(data, data_end, buffer, vertex_count_aligned);
if (!data) if (!data)
return 0; return NULL;
size_t vertex_offset = k; size_t vertex_offset = k;
@ -938,7 +938,7 @@ static const unsigned char* decodeBytesSimd(const unsigned char* data, const uns
size_t header_size = (buffer_size / kByteGroupSize + 3) / 4; size_t header_size = (buffer_size / kByteGroupSize + 3) / 4;
if (size_t(data_end - data) < header_size) if (size_t(data_end - data) < header_size)
return 0; return NULL;
data += header_size; data += header_size;
@ -960,7 +960,7 @@ static const unsigned char* decodeBytesSimd(const unsigned char* data, const uns
for (; i < buffer_size; i += kByteGroupSize) for (; i < buffer_size; i += kByteGroupSize)
{ {
if (size_t(data_end - data) < kByteGroupDecodeLimit) if (size_t(data_end - data) < kByteGroupDecodeLimit)
return 0; return NULL;
size_t header_offset = i / kByteGroupSize; size_t header_offset = i / kByteGroupSize;
@ -988,7 +988,7 @@ static const unsigned char* decodeVertexBlockSimd(const unsigned char* data, con
{ {
data = decodeBytesSimd(data, data_end, buffer + j * vertex_count_aligned, vertex_count_aligned); data = decodeBytesSimd(data, data_end, buffer + j * vertex_count_aligned, vertex_count_aligned);
if (!data) if (!data)
return 0; return NULL;
} }
#if defined(SIMD_SSE) || defined(SIMD_AVX) #if defined(SIMD_SSE) || defined(SIMD_AVX)
@ -1182,7 +1182,7 @@ int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t ve
assert(vertex_size > 0 && vertex_size <= 256); assert(vertex_size > 0 && vertex_size <= 256);
assert(vertex_size % 4 == 0); assert(vertex_size % 4 == 0);
const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256]) = 0; const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256]) = NULL;
#if defined(SIMD_SSE) && defined(SIMD_FALLBACK) #if defined(SIMD_SSE) && defined(SIMD_FALLBACK)
decode = (cpuid & (1 << 9)) ? decodeVertexBlockSimd : decodeVertexBlock; decode = (cpuid & (1 << 9)) ? decodeVertexBlockSimd : decodeVertexBlock;