parent
0810ecaafd
commit
cf9df3b5d4
|
@ -288,7 +288,7 @@ License: Apache-2.0
|
||||||
|
|
||||||
Files: ./thirdparty/meshoptimizer/
|
Files: ./thirdparty/meshoptimizer/
|
||||||
Comment: meshoptimizer
|
Comment: meshoptimizer
|
||||||
Copyright: 2016-2021, Arseny Kapoulkine
|
Copyright: 2016-2022, Arseny Kapoulkine
|
||||||
License: Expat
|
License: Expat
|
||||||
|
|
||||||
Files: ./thirdparty/minimp3/
|
Files: ./thirdparty/minimp3/
|
||||||
|
|
|
@ -542,13 +542,14 @@ void OccluderInstance3D::_bake_surface(const Transform3D &p_transform, Array p_s
|
||||||
float error = -1.0f;
|
float error = -1.0f;
|
||||||
int target_index_count = MIN(indices.size(), 36);
|
int target_index_count = MIN(indices.size(), 36);
|
||||||
|
|
||||||
|
const int simplify_options = SurfaceTool::SIMPLIFY_LOCK_BORDER;
|
||||||
|
|
||||||
uint32_t index_count = SurfaceTool::simplify_func(
|
uint32_t index_count = SurfaceTool::simplify_func(
|
||||||
(unsigned int *)indices.ptrw(),
|
(unsigned int *)indices.ptrw(),
|
||||||
(unsigned int *)indices.ptr(),
|
(unsigned int *)indices.ptr(),
|
||||||
indices.size(),
|
indices.size(),
|
||||||
vertices_f32.ptr(), vertices.size(), sizeof(float) * 3,
|
vertices_f32.ptr(), vertices.size(), sizeof(float) * 3,
|
||||||
target_index_count, target_error, &error);
|
target_index_count, target_error, simplify_options, &error);
|
||||||
|
|
||||||
indices.resize(index_count);
|
indices.resize(index_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -452,6 +452,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
|
||||||
new_indices.resize(index_count);
|
new_indices.resize(index_count);
|
||||||
|
|
||||||
Vector<float> merged_normals_f32 = vector3_to_float32_array(merged_normals.ptr(), merged_normals.size());
|
Vector<float> merged_normals_f32 = vector3_to_float32_array(merged_normals.ptr(), merged_normals.size());
|
||||||
|
const int simplify_options = SurfaceTool::SIMPLIFY_LOCK_BORDER;
|
||||||
|
|
||||||
size_t new_index_count = SurfaceTool::simplify_with_attrib_func(
|
size_t new_index_count = SurfaceTool::simplify_with_attrib_func(
|
||||||
(unsigned int *)new_indices.ptrw(),
|
(unsigned int *)new_indices.ptrw(),
|
||||||
|
@ -460,6 +461,7 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
|
||||||
sizeof(float) * 3, // Vertex stride
|
sizeof(float) * 3, // Vertex stride
|
||||||
index_target,
|
index_target,
|
||||||
max_mesh_error,
|
max_mesh_error,
|
||||||
|
simplify_options,
|
||||||
&mesh_error,
|
&mesh_error,
|
||||||
merged_normals_f32.ptr(),
|
merged_normals_f32.ptr(),
|
||||||
normal_weights.ptr(), 3);
|
normal_weights.ptr(), 3);
|
||||||
|
|
|
@ -1307,7 +1307,8 @@ Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_coun
|
||||||
}
|
}
|
||||||
|
|
||||||
float error;
|
float error;
|
||||||
uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold, &error);
|
const int simplify_options = SIMPLIFY_LOCK_BORDER;
|
||||||
|
uint32_t index_count = simplify_func((unsigned int *)lod.ptrw(), (unsigned int *)index_array.ptr(), index_array.size(), vertices.ptr(), vertex_array.size(), sizeof(float) * 3, p_target_index_count, p_threshold, simplify_options, &error);
|
||||||
ERR_FAIL_COND_V(index_count == 0, lod);
|
ERR_FAIL_COND_V(index_count == 0, lod);
|
||||||
lod.resize(index_count);
|
lod.resize(index_count);
|
||||||
|
|
||||||
|
|
|
@ -74,11 +74,16 @@ public:
|
||||||
SKIN_8_WEIGHTS
|
SKIN_8_WEIGHTS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/* Do not move vertices that are located on the topological border (vertices on triangle edges that don't have a paired triangle). Useful for simplifying portions of the larger mesh. */
|
||||||
|
SIMPLIFY_LOCK_BORDER = 1 << 0, // From meshopt_SimplifyLockBorder
|
||||||
|
};
|
||||||
|
|
||||||
typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count);
|
typedef void (*OptimizeVertexCacheFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, size_t vertex_count);
|
||||||
static OptimizeVertexCacheFunc optimize_vertex_cache_func;
|
static OptimizeVertexCacheFunc optimize_vertex_cache_func;
|
||||||
typedef size_t (*SimplifyFunc)(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, float *r_error);
|
typedef size_t (*SimplifyFunc)(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, unsigned int options, float *r_error);
|
||||||
static SimplifyFunc simplify_func;
|
static SimplifyFunc simplify_func;
|
||||||
typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float *result_error, const float *attributes, const float *attribute_weights, size_t attribute_count);
|
typedef size_t (*SimplifyWithAttribFunc)(unsigned int *destination, const unsigned int *indices, size_t index_count, const float *vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float *result_error, const float *attributes, const float *attribute_weights, size_t attribute_count);
|
||||||
static SimplifyWithAttribFunc simplify_with_attrib_func;
|
static SimplifyWithAttribFunc simplify_with_attrib_func;
|
||||||
typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
typedef float (*SimplifyScaleFunc)(const float *vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
||||||
static SimplifyScaleFunc simplify_scale_func;
|
static SimplifyScaleFunc simplify_scale_func;
|
||||||
|
|
|
@ -376,7 +376,7 @@ File extracted from upstream release tarball:
|
||||||
## meshoptimizer
|
## meshoptimizer
|
||||||
|
|
||||||
- Upstream: https://github.com/zeux/meshoptimizer
|
- Upstream: https://github.com/zeux/meshoptimizer
|
||||||
- Version: git (ea4558d1c0f217f1d67ed7fe0b07896ece88ae18, 2022)
|
- Version: git (4a287848fd664ae1c3fc8e5e008560534ceeb526, 2022)
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|
||||||
Files extracted from upstream repository:
|
Files extracted from upstream repository:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2016-2021 Arseny Kapoulkine
|
Copyright (c) 2016-2022 Arseny Kapoulkine
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -283,6 +283,79 @@ static bool appendMeshlet(meshopt_Meshlet& meshlet, unsigned int a, unsigned int
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int getNeighborTriangle(const meshopt_Meshlet& meshlet, const Cone* meshlet_cone, unsigned int* meshlet_vertices, const unsigned int* indices, const TriangleAdjacency2& adjacency, const Cone* triangles, const unsigned int* live_triangles, const unsigned char* used, float meshlet_expected_radius, float cone_weight, unsigned int* out_extra)
|
||||||
|
{
|
||||||
|
unsigned int best_triangle = ~0u;
|
||||||
|
unsigned int best_extra = 5;
|
||||||
|
float best_score = FLT_MAX;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < meshlet.vertex_count; ++i)
|
||||||
|
{
|
||||||
|
unsigned int index = meshlet_vertices[meshlet.vertex_offset + i];
|
||||||
|
|
||||||
|
unsigned int* neighbors = &adjacency.data[0] + adjacency.offsets[index];
|
||||||
|
size_t neighbors_size = adjacency.counts[index];
|
||||||
|
|
||||||
|
for (size_t j = 0; j < neighbors_size; ++j)
|
||||||
|
{
|
||||||
|
unsigned int triangle = neighbors[j];
|
||||||
|
unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
|
||||||
|
|
||||||
|
unsigned int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
|
||||||
|
|
||||||
|
// triangles that don't add new vertices to meshlets are max. priority
|
||||||
|
if (extra != 0)
|
||||||
|
{
|
||||||
|
// artificially increase the priority of dangling triangles as they're expensive to add to new meshlets
|
||||||
|
if (live_triangles[a] == 1 || live_triangles[b] == 1 || live_triangles[c] == 1)
|
||||||
|
extra = 0;
|
||||||
|
|
||||||
|
extra++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// since topology-based priority is always more important than the score, we can skip scoring in some cases
|
||||||
|
if (extra > best_extra)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
float score = 0;
|
||||||
|
|
||||||
|
// caller selects one of two scoring functions: geometrical (based on meshlet cone) or topological (based on remaining triangles)
|
||||||
|
if (meshlet_cone)
|
||||||
|
{
|
||||||
|
const Cone& tri_cone = triangles[triangle];
|
||||||
|
|
||||||
|
float distance2 =
|
||||||
|
(tri_cone.px - meshlet_cone->px) * (tri_cone.px - meshlet_cone->px) +
|
||||||
|
(tri_cone.py - meshlet_cone->py) * (tri_cone.py - meshlet_cone->py) +
|
||||||
|
(tri_cone.pz - meshlet_cone->pz) * (tri_cone.pz - meshlet_cone->pz);
|
||||||
|
|
||||||
|
float spread = tri_cone.nx * meshlet_cone->nx + tri_cone.ny * meshlet_cone->ny + tri_cone.nz * meshlet_cone->nz;
|
||||||
|
|
||||||
|
score = getMeshletScore(distance2, spread, cone_weight, meshlet_expected_radius);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// each live_triangles entry is >= 1 since it includes the current triangle we're processing
|
||||||
|
score = float(live_triangles[a] + live_triangles[b] + live_triangles[c] - 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// note that topology-based priority is always more important than the score
|
||||||
|
// this helps maintain reasonable effectiveness of meshlet data and reduces scoring cost
|
||||||
|
if (extra < best_extra || score < best_score)
|
||||||
|
{
|
||||||
|
best_triangle = triangle;
|
||||||
|
best_extra = extra;
|
||||||
|
best_score = score;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out_extra)
|
||||||
|
*out_extra = best_extra;
|
||||||
|
|
||||||
|
return best_triangle;
|
||||||
|
}
|
||||||
|
|
||||||
struct KDNode
|
struct KDNode
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
|
@ -464,13 +537,15 @@ size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_ve
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_positions_stride > 0 && 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(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
|
assert(max_vertices >= 3 && max_vertices <= kMeshletMaxVertices);
|
||||||
assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
|
assert(max_triangles >= 1 && max_triangles <= kMeshletMaxTriangles);
|
||||||
assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
|
assert(max_triangles % 4 == 0); // ensures the caller will compute output space properly as index data is 4b aligned
|
||||||
|
|
||||||
|
assert(cone_weight >= 0 && cone_weight <= 1);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
|
||||||
TriangleAdjacency2 adjacency = {};
|
TriangleAdjacency2 adjacency = {};
|
||||||
|
@ -511,65 +586,18 @@ size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_ve
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
unsigned int best_triangle = ~0u;
|
|
||||||
unsigned int best_extra = 5;
|
|
||||||
float best_score = FLT_MAX;
|
|
||||||
|
|
||||||
Cone meshlet_cone = getMeshletCone(meshlet_cone_acc, meshlet.triangle_count);
|
Cone meshlet_cone = getMeshletCone(meshlet_cone_acc, meshlet.triangle_count);
|
||||||
|
|
||||||
for (size_t i = 0; i < meshlet.vertex_count; ++i)
|
unsigned int best_extra = 0;
|
||||||
|
unsigned int best_triangle = getNeighborTriangle(meshlet, &meshlet_cone, meshlet_vertices, indices, adjacency, triangles, live_triangles, used, meshlet_expected_radius, cone_weight, &best_extra);
|
||||||
|
|
||||||
|
// if the best triangle doesn't fit into current meshlet, the spatial scoring we've used is not very meaningful, so we re-select using topological scoring
|
||||||
|
if (best_triangle != ~0u && (meshlet.vertex_count + best_extra > max_vertices || meshlet.triangle_count >= max_triangles))
|
||||||
{
|
{
|
||||||
unsigned int index = meshlet_vertices[meshlet.vertex_offset + i];
|
best_triangle = getNeighborTriangle(meshlet, NULL, meshlet_vertices, indices, adjacency, triangles, live_triangles, used, meshlet_expected_radius, 0.f, NULL);
|
||||||
|
|
||||||
unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
|
|
||||||
size_t neighbours_size = adjacency.counts[index];
|
|
||||||
|
|
||||||
for (size_t j = 0; j < neighbours_size; ++j)
|
|
||||||
{
|
|
||||||
unsigned int triangle = neighbours[j];
|
|
||||||
assert(!emitted_flags[triangle]);
|
|
||||||
|
|
||||||
unsigned int a = indices[triangle * 3 + 0], b = indices[triangle * 3 + 1], c = indices[triangle * 3 + 2];
|
|
||||||
assert(a < vertex_count && b < vertex_count && c < vertex_count);
|
|
||||||
|
|
||||||
unsigned int extra = (used[a] == 0xff) + (used[b] == 0xff) + (used[c] == 0xff);
|
|
||||||
|
|
||||||
// triangles that don't add new vertices to meshlets are max. priority
|
|
||||||
if (extra != 0)
|
|
||||||
{
|
|
||||||
// artificially increase the priority of dangling triangles as they're expensive to add to new meshlets
|
|
||||||
if (live_triangles[a] == 1 || live_triangles[b] == 1 || live_triangles[c] == 1)
|
|
||||||
extra = 0;
|
|
||||||
|
|
||||||
extra++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// since topology-based priority is always more important than the score, we can skip scoring in some cases
|
|
||||||
if (extra > best_extra)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const Cone& tri_cone = triangles[triangle];
|
|
||||||
|
|
||||||
float distance2 =
|
|
||||||
(tri_cone.px - meshlet_cone.px) * (tri_cone.px - meshlet_cone.px) +
|
|
||||||
(tri_cone.py - meshlet_cone.py) * (tri_cone.py - meshlet_cone.py) +
|
|
||||||
(tri_cone.pz - meshlet_cone.pz) * (tri_cone.pz - meshlet_cone.pz);
|
|
||||||
|
|
||||||
float spread = tri_cone.nx * meshlet_cone.nx + tri_cone.ny * meshlet_cone.ny + tri_cone.nz * meshlet_cone.nz;
|
|
||||||
|
|
||||||
float score = getMeshletScore(distance2, spread, cone_weight, meshlet_expected_radius);
|
|
||||||
|
|
||||||
// note that topology-based priority is always more important than the score
|
|
||||||
// this helps maintain reasonable effectiveness of meshlet data and reduces scoring cost
|
|
||||||
if (extra < best_extra || score < best_score)
|
|
||||||
{
|
|
||||||
best_triangle = triangle;
|
|
||||||
best_extra = extra;
|
|
||||||
best_score = score;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when we run out of neighboring triangles we need to switch to spatial search; we currently just pick the closest triangle irrespective of connectivity
|
||||||
if (best_triangle == ~0u)
|
if (best_triangle == ~0u)
|
||||||
{
|
{
|
||||||
float position[3] = {meshlet_cone.px, meshlet_cone.py, meshlet_cone.pz};
|
float position[3] = {meshlet_cone.px, meshlet_cone.py, meshlet_cone.pz};
|
||||||
|
@ -604,16 +632,16 @@ size_t meshopt_buildMeshlets(meshopt_Meshlet* meshlets, unsigned int* meshlet_ve
|
||||||
{
|
{
|
||||||
unsigned int index = indices[best_triangle * 3 + k];
|
unsigned int index = indices[best_triangle * 3 + k];
|
||||||
|
|
||||||
unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
|
unsigned int* neighbors = &adjacency.data[0] + adjacency.offsets[index];
|
||||||
size_t neighbours_size = adjacency.counts[index];
|
size_t neighbors_size = adjacency.counts[index];
|
||||||
|
|
||||||
for (size_t i = 0; i < neighbours_size; ++i)
|
for (size_t i = 0; i < neighbors_size; ++i)
|
||||||
{
|
{
|
||||||
unsigned int tri = neighbours[i];
|
unsigned int tri = neighbors[i];
|
||||||
|
|
||||||
if (tri == best_triangle)
|
if (tri == best_triangle)
|
||||||
{
|
{
|
||||||
neighbours[i] = neighbours[neighbours_size - 1];
|
neighbors[i] = neighbors[neighbors_size - 1];
|
||||||
adjacency.counts[index]--;
|
adjacency.counts[index]--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -687,7 +715,7 @@ meshopt_Bounds meshopt_computeClusterBounds(const unsigned int* indices, size_t
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(index_count / 3 <= kMeshletMaxTriangles);
|
assert(index_count / 3 <= kMeshletMaxTriangles);
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
(void)vertex_count;
|
(void)vertex_count;
|
||||||
|
@ -839,7 +867,7 @@ meshopt_Bounds meshopt_computeMeshletBounds(const unsigned int* meshlet_vertices
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(triangle_count <= kMeshletMaxTriangles);
|
assert(triangle_count <= kMeshletMaxTriangles);
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
unsigned int indices[kMeshletMaxTriangles * 3];
|
unsigned int indices[kMeshletMaxTriangles * 3];
|
||||||
|
|
|
@ -187,7 +187,7 @@ size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(indices || index_count == vertex_count);
|
assert(indices || index_count == vertex_count);
|
||||||
assert(index_count % 3 == 0);
|
assert(!indices || index_count % 3 == 0);
|
||||||
assert(vertex_size > 0 && vertex_size <= 256);
|
assert(vertex_size > 0 && vertex_size <= 256);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
@ -412,7 +412,7 @@ void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsig
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
@ -483,7 +483,7 @@ void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const un
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* meshoptimizer - version 0.17
|
* meshoptimizer - version 0.18
|
||||||
*
|
*
|
||||||
* Copyright (C) 2016-2021, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
|
* Copyright (C) 2016-2022, 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
|
||||||
*
|
*
|
||||||
* This library is distributed under the MIT License. See notice at the end of this file.
|
* This library is distributed under the MIT License. See notice at the end of this file.
|
||||||
|
@ -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 170 /* 0.17 */
|
#define MESHOPTIMIZER_VERSION 180 /* 0.18 */
|
||||||
|
|
||||||
/* If no API is defined, assume default */
|
/* If no API is defined, assume default */
|
||||||
#ifndef MESHOPTIMIZER_API
|
#ifndef MESHOPTIMIZER_API
|
||||||
|
@ -37,8 +37,8 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vertex attribute stream, similar to glVertexPointer
|
* Vertex attribute stream
|
||||||
* Each element takes size bytes, with stride controlling the spacing between successive elements.
|
* Each element takes size bytes, beginning at data, with stride controlling the spacing between successive elements (stride >= size).
|
||||||
*/
|
*/
|
||||||
struct meshopt_Stream
|
struct meshopt_Stream
|
||||||
{
|
{
|
||||||
|
@ -115,7 +115,7 @@ MESHOPTIMIZER_API void meshopt_generateShadowIndexBufferMulti(unsigned int* dest
|
||||||
* This can be used to implement algorithms like silhouette detection/expansion and other forms of GS-driven rendering.
|
* This can be used to implement algorithms like silhouette detection/expansion and other forms of GS-driven rendering.
|
||||||
*
|
*
|
||||||
* destination must contain enough space for the resulting index buffer (index_count*2 elements)
|
* destination must contain enough space for the resulting index buffer (index_count*2 elements)
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
*/
|
*/
|
||||||
MESHOPTIMIZER_API void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
MESHOPTIMIZER_API void meshopt_generateAdjacencyIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
||||||
|
|
||||||
|
@ -131,7 +131,7 @@ MESHOPTIMIZER_API void meshopt_generateAdjacencyIndexBuffer(unsigned int* destin
|
||||||
* See "Tessellation on Any Budget" (John McDonald, GDC 2011) for implementation details.
|
* See "Tessellation on Any Budget" (John McDonald, GDC 2011) for implementation details.
|
||||||
*
|
*
|
||||||
* destination must contain enough space for the resulting index buffer (index_count*4 elements)
|
* destination must contain enough space for the resulting index buffer (index_count*4 elements)
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
*/
|
*/
|
||||||
MESHOPTIMIZER_API void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
MESHOPTIMIZER_API void meshopt_generateTessellationIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ MESHOPTIMIZER_API void meshopt_optimizeVertexCacheFifo(unsigned int* destination
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
* indices must contain index data that is the result of meshopt_optimizeVertexCache (*not* the original mesh indices!)
|
* indices must contain index data that is the result of meshopt_optimizeVertexCache (*not* the original mesh indices!)
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
* threshold indicates how much the overdraw optimizer can degrade vertex cache efficiency (1.05 = up to 5%) to reduce overdraw more efficiently
|
* threshold indicates how much the overdraw optimizer can degrade vertex cache efficiency (1.05 = up to 5%) to reduce overdraw more efficiently
|
||||||
*/
|
*/
|
||||||
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);
|
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);
|
||||||
|
@ -313,7 +313,21 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterQuat(void* destination, size
|
||||||
MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterExp(void* destination, size_t count, size_t stride, int bits, const float* data);
|
MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterExp(void* destination, size_t count, size_t stride, int bits, const float* data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Experimental: Mesh simplifier
|
* Simplification options
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
/* Do not move vertices that are located on the topological border (vertices on triangle edges that don't have a paired triangle). Useful for simplifying portions of the larger mesh. */
|
||||||
|
meshopt_SimplifyLockBorder = 1 << 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
|
||||||
|
*/
|
||||||
|
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mesh simplifier
|
||||||
* Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible
|
* Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible
|
||||||
* The algorithm tries to preserve mesh topology and can stop short of the target goal based on topology constraints or target error.
|
* The algorithm tries to preserve mesh topology and can stop short of the target goal based on topology constraints or target error.
|
||||||
* If not all attributes from the input mesh are required, it's recommended to reindex the mesh using meshopt_generateShadowIndexBuffer prior to simplification.
|
* If not all attributes from the input mesh are required, it's recommended to reindex the mesh using meshopt_generateShadowIndexBuffer prior to simplification.
|
||||||
|
@ -322,16 +336,12 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterExp(void* destination, size_
|
||||||
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
|
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
|
||||||
*
|
*
|
||||||
* destination must contain enough space for the target index buffer, worst case is index_count elements (*not* target_index_count)!
|
* destination must contain enough space for the target index buffer, worst case is index_count elements (*not* target_index_count)!
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
* target_error represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation
|
* target_error represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation; value range [0..1]
|
||||||
|
* options must be a bitmask composed of meshopt_SimplifyX options; 0 is a safe default
|
||||||
* result_error can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
|
* result_error can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
|
||||||
*/
|
*/
|
||||||
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, float* result_error);
|
MESHOPTIMIZER_API 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, unsigned int options, float* result_error);
|
||||||
|
|
||||||
/**
|
|
||||||
* Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
|
|
||||||
*/
|
|
||||||
MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Experimental: Mesh simplifier (sloppy)
|
* Experimental: Mesh simplifier (sloppy)
|
||||||
|
@ -342,8 +352,8 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* d
|
||||||
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
|
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
|
||||||
*
|
*
|
||||||
* destination must contain enough space for the target index buffer, worst case is index_count elements (*not* target_index_count)!
|
* destination must contain enough space for the target index buffer, worst case is index_count elements (*not* target_index_count)!
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
* target_error represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation
|
* target_error represents the error relative to mesh extents that can be tolerated, e.g. 0.01 = 1% deformation; value range [0..1]
|
||||||
* result_error can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
|
* result_error can be NULL; when it's not NULL, it will contain the resulting (relative) error after simplification
|
||||||
*/
|
*/
|
||||||
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, float target_error, float* result_error);
|
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, float target_error, float* result_error);
|
||||||
|
@ -356,17 +366,17 @@ MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifySloppy(unsigned int* destinati
|
||||||
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
|
* If the original vertex data isn't required, creating a compact vertex buffer using meshopt_optimizeVertexFetch is recommended.
|
||||||
*
|
*
|
||||||
* 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 - similar to glVertexPointer
|
* vertex_positions should have float3 position 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, size_t target_vertex_count);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Experimental: 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
|
||||||
*
|
*
|
||||||
* Absolute error must be *divided* by the scaling factor before passing it to meshopt_simplify as target_error
|
* Absolute error must be *divided* by the scaling factor before passing it to meshopt_simplify as target_error
|
||||||
* Relative error returned by meshopt_simplify via result_error must be *multiplied* by the scaling factor to get absolute error.
|
* Relative error returned by meshopt_simplify via result_error must be *multiplied* by the scaling factor to get absolute error.
|
||||||
*/
|
*/
|
||||||
MESHOPTIMIZER_EXPERIMENTAL float meshopt_simplifyScale(const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
MESHOPTIMIZER_API float meshopt_simplifyScale(const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mesh stripifier
|
* Mesh stripifier
|
||||||
|
@ -418,7 +428,7 @@ struct meshopt_OverdrawStatistics
|
||||||
* Returns overdraw statistics using a software rasterizer
|
* Returns overdraw statistics using a software rasterizer
|
||||||
* Results may not match actual GPU performance
|
* Results may not match actual GPU performance
|
||||||
*
|
*
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
*/
|
*/
|
||||||
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);
|
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);
|
||||||
|
|
||||||
|
@ -456,7 +466,7 @@ struct meshopt_Meshlet
|
||||||
* meshlets must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
|
* meshlets must contain enough space for all meshlets, worst case size can be computed with meshopt_buildMeshletsBound
|
||||||
* meshlet_vertices must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices
|
* meshlet_vertices must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_vertices
|
||||||
* meshlet_triangles must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3
|
* meshlet_triangles must contain enough space for all meshlets, worst case size is equal to max_meshlets * max_triangles * 3
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
* max_vertices and max_triangles must not exceed implementation limits (max_vertices <= 255 - not 256!, max_triangles <= 512)
|
* max_vertices and max_triangles must not exceed implementation limits (max_vertices <= 255 - not 256!, max_triangles <= 512)
|
||||||
* cone_weight should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency
|
* cone_weight should be set to 0 when cone culling is not used, and a value between 0 and 1 otherwise to balance between cluster size and cone culling efficiency
|
||||||
*/
|
*/
|
||||||
|
@ -498,7 +508,7 @@ struct meshopt_Bounds
|
||||||
* The formula that uses the apex is slightly more accurate but needs the apex; if you are already using bounding sphere
|
* The formula that uses the apex is slightly more accurate but needs the apex; if you are already using bounding sphere
|
||||||
* to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable.
|
* to do frustum/occlusion culling, the formula that doesn't use the apex may be preferable.
|
||||||
*
|
*
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
* index_count/3 should be less than or equal to 512 (the function assumes clusters of limited size)
|
* index_count/3 should be less than or equal to 512 (the function assumes clusters of limited size)
|
||||||
*/
|
*/
|
||||||
MESHOPTIMIZER_API 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);
|
MESHOPTIMIZER_API 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);
|
||||||
|
@ -518,7 +528,7 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_spatialSortRemap(unsigned int* destinati
|
||||||
* Reorders triangles for spatial locality, and generates a new index buffer. The resulting index buffer can be used with other functions like optimizeVertexCache.
|
* Reorders triangles for spatial locality, and generates a new index buffer. The resulting index buffer can be used with other functions like optimizeVertexCache.
|
||||||
*
|
*
|
||||||
* 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)
|
||||||
* vertex_positions should have float3 position in the first 12 bytes of each vertex - similar to glVertexPointer
|
* vertex_positions should have float3 position in the first 12 bytes of each vertex
|
||||||
*/
|
*/
|
||||||
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);
|
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);
|
||||||
|
|
||||||
|
@ -610,7 +620,7 @@ 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, 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 = 0);
|
||||||
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 = 0);
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -945,12 +955,12 @@ 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, 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(0, indices, index_count);
|
||||||
meshopt_IndexAdapter<T> out(destination, 0, index_count);
|
meshopt_IndexAdapter<T> out(destination, 0, index_count);
|
||||||
|
|
||||||
return meshopt_simplify(out.data, in.data, index_count, vertex_positions, vertex_count, vertex_positions_stride, target_index_count, target_error, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -1039,7 +1049,7 @@ inline void meshopt_spatialSortTriangles(T* destination, const T* indices, size_
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2016-2021 Arseny Kapoulkine
|
* Copyright (c) 2016-2022 Arseny Kapoulkine
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person
|
* Permission is hereby granted, free of charge, to any person
|
||||||
* obtaining a copy of this software and associated documentation
|
* obtaining a copy of this software and associated documentation
|
||||||
|
|
|
@ -147,7 +147,7 @@ meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices,
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
|
|
@ -272,7 +272,7 @@ void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* ind
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
|
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
|
||||||
index 5e92e2dc73..e40c141e76 100644
|
index d8d4a67391..3847afc736 100644
|
||||||
--- a/thirdparty/meshoptimizer/simplifier.cpp
|
--- a/thirdparty/meshoptimizer/simplifier.cpp
|
||||||
+++ b/thirdparty/meshoptimizer/simplifier.cpp
|
+++ b/thirdparty/meshoptimizer/simplifier.cpp
|
||||||
@@ -20,7 +20,7 @@
|
@@ -20,7 +20,7 @@
|
||||||
|
@ -11,7 +11,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
|
|
||||||
// This work is based on:
|
// This work is based on:
|
||||||
// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
|
// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
|
||||||
@@ -453,6 +453,7 @@ struct Collapse
|
@@ -458,6 +458,7 @@ struct Collapse
|
||||||
float error;
|
float error;
|
||||||
unsigned int errorui;
|
unsigned int errorui;
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
};
|
};
|
||||||
|
|
||||||
static float normalize(Vector3& v)
|
static float normalize(Vector3& v)
|
||||||
@@ -533,6 +534,34 @@ static float quadricError(const Quadric& Q, const Vector3& v)
|
@@ -538,6 +539,34 @@ static float quadricError(const Quadric& Q, const Vector3& v)
|
||||||
return fabsf(r) * s;
|
return fabsf(r) * s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, float w)
|
static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, float w)
|
||||||
{
|
{
|
||||||
float aw = a * w;
|
float aw = a * w;
|
||||||
@@ -688,7 +717,7 @@ static void quadricUpdateAttributes(Quadric& Q, const Vector3& p0, const Vector3
|
@@ -693,7 +722,7 @@ static void quadricUpdateAttributes(Quadric& Q, const Vector3& p0, const Vector3
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < index_count; i += 3)
|
for (size_t i = 0; i < index_count; i += 3)
|
||||||
{
|
{
|
||||||
@@ -698,6 +727,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
@@ -703,6 +732,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
||||||
|
|
||||||
Quadric Q;
|
Quadric Q;
|
||||||
quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
|
quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
|
||||||
|
@ -73,7 +73,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
|
|
||||||
#if ATTRIBUTES
|
#if ATTRIBUTES
|
||||||
quadricUpdateAttributes(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], Q.w);
|
quadricUpdateAttributes(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], Q.w);
|
||||||
@@ -708,7 +740,7 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
@@ -713,7 +745,7 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < index_count; i += 3)
|
for (size_t i = 0; i < index_count; i += 3)
|
||||||
{
|
{
|
||||||
@@ -752,6 +784,9 @@ static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
@@ -757,6 +789,9 @@ static void fillEdgeQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
||||||
|
|
||||||
quadricAdd(vertex_quadrics[remap[i0]], Q);
|
quadricAdd(vertex_quadrics[remap[i0]], Q);
|
||||||
quadricAdd(vertex_quadrics[remap[i1]], Q);
|
quadricAdd(vertex_quadrics[remap[i1]], Q);
|
||||||
|
@ -92,7 +92,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -856,7 +891,7 @@ static size_t pickEdgeCollapses(Collapse* collapses, const unsigned int* indices
|
@@ -861,7 +896,7 @@ static size_t pickEdgeCollapses(Collapse* collapses, const unsigned int* indices
|
||||||
return collapse_count;
|
return collapse_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < collapse_count; ++i)
|
for (size_t i = 0; i < collapse_count; ++i)
|
||||||
{
|
{
|
||||||
@@ -876,10 +911,14 @@ static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const
|
@@ -881,10 +916,14 @@ static void rankEdgeCollapses(Collapse* collapses, size_t collapse_count, const
|
||||||
float ei = quadricError(qi, vertex_positions[i1]);
|
float ei = quadricError(qi, vertex_positions[i1]);
|
||||||
float ej = quadricError(qj, vertex_positions[j1]);
|
float ej = quadricError(qj, vertex_positions[j1]);
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -976,7 +1015,7 @@ static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapse
|
@@ -981,7 +1020,7 @@ static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
{
|
{
|
||||||
size_t edge_collapses = 0;
|
size_t edge_collapses = 0;
|
||||||
size_t triangle_collapses = 0;
|
size_t triangle_collapses = 0;
|
||||||
@@ -1038,6 +1077,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
|
@@ -1043,6 +1082,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
|
||||||
assert(collapse_remap[r1] == r1);
|
assert(collapse_remap[r1] == r1);
|
||||||
|
|
||||||
quadricAdd(vertex_quadrics[r1], vertex_quadrics[r0]);
|
quadricAdd(vertex_quadrics[r1], vertex_quadrics[r0]);
|
||||||
|
@ -133,7 +133,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
|
|
||||||
if (vertex_kind[i0] == Kind_Complex)
|
if (vertex_kind[i0] == Kind_Complex)
|
||||||
{
|
{
|
||||||
@@ -1075,7 +1115,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
|
@@ -1080,7 +1120,7 @@ static size_t performEdgeCollapses(unsigned int* collapse_remap, unsigned char*
|
||||||
triangle_collapses += (vertex_kind[i0] == Kind_Border) ? 1 : 2;
|
triangle_collapses += (vertex_kind[i0] == Kind_Border) ? 1 : 2;
|
||||||
edge_collapses++;
|
edge_collapses++;
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TRACE
|
#if TRACE
|
||||||
@@ -1463,9 +1503,11 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
|
@@ -1469,9 +1509,11 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
|
||||||
|
|
||||||
Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
|
Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
|
||||||
memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
|
memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
|
||||||
|
@ -156,7 +156,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
|
|
||||||
if (result != indices)
|
if (result != indices)
|
||||||
memcpy(result, indices, index_count * sizeof(unsigned int));
|
memcpy(result, indices, index_count * sizeof(unsigned int));
|
||||||
@@ -1496,7 +1538,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
|
@@ -1502,7 +1544,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
|
||||||
if (edge_collapse_count == 0)
|
if (edge_collapse_count == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ index 5e92e2dc73..e40c141e76 100644
|
||||||
|
|
||||||
#if TRACE > 1
|
#if TRACE > 1
|
||||||
dumpEdgeCollapses(edge_collapses, edge_collapse_count, vertex_kind);
|
dumpEdgeCollapses(edge_collapses, edge_collapse_count, vertex_kind);
|
||||||
@@ -1515,7 +1557,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
|
@@ -1521,7 +1563,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
|
||||||
printf("pass %d: ", int(pass_count++));
|
printf("pass %d: ", int(pass_count++));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
|
diff --git a/thirdparty/meshoptimizer/meshoptimizer.h b/thirdparty/meshoptimizer/meshoptimizer.h
|
||||||
index be4b765d97..463fad29da 100644
|
index d95725dd71..46d28d3ea3 100644
|
||||||
--- a/thirdparty/meshoptimizer/meshoptimizer.h
|
--- a/thirdparty/meshoptimizer/meshoptimizer.h
|
||||||
+++ b/thirdparty/meshoptimizer/meshoptimizer.h
|
+++ b/thirdparty/meshoptimizer/meshoptimizer.h
|
||||||
@@ -328,6 +328,11 @@ MESHOPTIMIZER_EXPERIMENTAL void meshopt_encodeFilterExp(void* destination, size_
|
@@ -321,6 +321,11 @@ enum
|
||||||
*/
|
meshopt_SimplifyLockBorder = 1 << 0,
|
||||||
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, float* result_error);
|
};
|
||||||
|
|
||||||
+/**
|
+/**
|
||||||
+ * Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
|
+ * Experimental: Mesh simplifier with attribute metric; attributes follow xyz position data atm (vertex data must contain 3 + attribute_count floats per vertex)
|
||||||
+ */
|
+ */
|
||||||
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
|
+MESHOPTIMIZER_EXPERIMENTAL size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* result_error, const float* attributes, const float* attribute_weights, size_t attribute_count);
|
||||||
+
|
+
|
||||||
/**
|
/**
|
||||||
* Experimental: Mesh simplifier (sloppy)
|
* Mesh simplifier
|
||||||
* Reduces the number of triangles in the mesh, sacrificing mesh appearance for simplification performance
|
* Reduces the number of triangles in the mesh, attempting to preserve mesh appearance as much as possible
|
||||||
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
|
diff --git a/thirdparty/meshoptimizer/simplifier.cpp b/thirdparty/meshoptimizer/simplifier.cpp
|
||||||
index a74b08a97d..5e92e2dc73 100644
|
index 5f0e9bac31..797329b010 100644
|
||||||
--- a/thirdparty/meshoptimizer/simplifier.cpp
|
--- a/thirdparty/meshoptimizer/simplifier.cpp
|
||||||
+++ b/thirdparty/meshoptimizer/simplifier.cpp
|
+++ b/thirdparty/meshoptimizer/simplifier.cpp
|
||||||
@@ -20,6 +20,8 @@
|
@@ -20,6 +20,8 @@
|
||||||
|
@ -27,7 +27,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
// This work is based on:
|
// This work is based on:
|
||||||
// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
|
// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
|
||||||
// Michael Garland. Quadric-based polygonal surface simplification. 1999
|
// Michael Garland. Quadric-based polygonal surface simplification. 1999
|
||||||
@@ -371,6 +373,10 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
|
@@ -376,6 +378,10 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
|
||||||
struct Vector3
|
struct Vector3
|
||||||
{
|
{
|
||||||
float x, y, z;
|
float x, y, z;
|
||||||
|
@ -38,7 +38,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
};
|
};
|
||||||
|
|
||||||
static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
|
static float rescalePositions(Vector3* result, const float* vertex_positions_data, size_t vertex_count, size_t vertex_positions_stride)
|
||||||
@@ -427,6 +433,13 @@ struct Quadric
|
@@ -432,6 +438,13 @@ struct Quadric
|
||||||
float a10, a20, a21;
|
float a10, a20, a21;
|
||||||
float b0, b1, b2, c;
|
float b0, b1, b2, c;
|
||||||
float w;
|
float w;
|
||||||
|
@ -52,7 +52,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Collapse
|
struct Collapse
|
||||||
@@ -469,6 +482,16 @@ static void quadricAdd(Quadric& Q, const Quadric& R)
|
@@ -474,6 +487,16 @@ static void quadricAdd(Quadric& Q, const Quadric& R)
|
||||||
Q.b2 += R.b2;
|
Q.b2 += R.b2;
|
||||||
Q.c += R.c;
|
Q.c += R.c;
|
||||||
Q.w += R.w;
|
Q.w += R.w;
|
||||||
|
@ -69,7 +69,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
}
|
}
|
||||||
|
|
||||||
static float quadricError(const Quadric& Q, const Vector3& v)
|
static float quadricError(const Quadric& Q, const Vector3& v)
|
||||||
@@ -494,6 +517,17 @@ static float quadricError(const Quadric& Q, const Vector3& v)
|
@@ -499,6 +522,17 @@ static float quadricError(const Quadric& Q, const Vector3& v)
|
||||||
r += ry * v.y;
|
r += ry * v.y;
|
||||||
r += rz * v.z;
|
r += rz * v.z;
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
|
float s = Q.w == 0.f ? 0.f : 1.f / Q.w;
|
||||||
|
|
||||||
return fabsf(r) * s;
|
return fabsf(r) * s;
|
||||||
@@ -517,6 +551,13 @@ static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, flo
|
@@ -522,6 +556,13 @@ static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d, flo
|
||||||
Q.b2 = c * dw;
|
Q.b2 = c * dw;
|
||||||
Q.c = d * dw;
|
Q.c = d * dw;
|
||||||
Q.w = w;
|
Q.w = w;
|
||||||
|
@ -101,7 +101,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
}
|
}
|
||||||
|
|
||||||
static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
|
static void quadricFromPoint(Quadric& Q, float x, float y, float z, float w)
|
||||||
@@ -569,6 +610,84 @@ static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3
|
@@ -574,6 +615,84 @@ static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3
|
||||||
quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight);
|
quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance, length * weight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
|
static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indices, size_t index_count, const Vector3* vertex_positions, const unsigned int* remap)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < index_count; i += 3)
|
for (size_t i = 0; i < index_count; i += 3)
|
||||||
@@ -580,6 +699,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
@@ -585,6 +704,9 @@ static void fillFaceQuadrics(Quadric* vertex_quadrics, const unsigned int* indic
|
||||||
Quadric Q;
|
Quadric Q;
|
||||||
quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
|
quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], 1.f);
|
||||||
|
|
||||||
|
@ -196,29 +196,30 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
quadricAdd(vertex_quadrics[remap[i0]], Q);
|
quadricAdd(vertex_quadrics[remap[i0]], Q);
|
||||||
quadricAdd(vertex_quadrics[remap[i1]], Q);
|
quadricAdd(vertex_quadrics[remap[i1]], Q);
|
||||||
quadricAdd(vertex_quadrics[remap[i2]], Q);
|
quadricAdd(vertex_quadrics[remap[i2]], Q);
|
||||||
@@ -1273,13 +1395,19 @@ MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = 0;
|
@@ -1278,14 +1400,20 @@ MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t meshopt_simplify(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, size_t target_index_count, float target_error, float* out_result_error)
|
size_t meshopt_simplify(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, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
|
||||||
+{
|
+{
|
||||||
+ return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, out_result_error, 0, 0, 0);
|
+ return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, options, out_result_error, 0, 0, 0);
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
+size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
|
+size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
|
||||||
{
|
{
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
- assert(vertex_positions_stride > 0 && 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_stride > 0 && vertex_stride <= 256);
|
+ assert(vertex_stride >= 12 && vertex_stride <= 256);
|
||||||
+ assert(vertex_stride % sizeof(float) == 0);
|
+ assert(vertex_stride % sizeof(float) == 0);
|
||||||
assert(target_index_count <= index_count);
|
assert(target_index_count <= index_count);
|
||||||
|
assert((options & ~(meshopt_SimplifyLockBorder)) == 0);
|
||||||
+ assert(attribute_count <= ATTRIBUTES);
|
+ assert(attribute_count <= ATTRIBUTES);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
|
||||||
@@ -1293,7 +1421,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
|
@@ -1299,7 +1427,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
|
||||||
// build position remap that maps each vertex to the one with identical position
|
// build position remap that maps each vertex to the one with identical position
|
||||||
unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
|
unsigned int* remap = allocator.allocate<unsigned int>(vertex_count);
|
||||||
unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count);
|
unsigned int* wedge = allocator.allocate<unsigned int>(vertex_count);
|
||||||
|
@ -227,7 +228,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
|
|
||||||
// classify vertices; vertex kind determines collapse rules, see kCanCollapse
|
// classify vertices; vertex kind determines collapse rules, see kCanCollapse
|
||||||
unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
|
unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
|
||||||
@@ -1317,7 +1445,21 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
|
@@ -1323,7 +1451,21 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
|
Vector3* vertex_positions = allocator.allocate<Vector3>(vertex_count);
|
||||||
|
@ -250,7 +251,7 @@ index a74b08a97d..5e92e2dc73 100644
|
||||||
|
|
||||||
Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
|
Quadric* vertex_quadrics = allocator.allocate<Quadric>(vertex_count);
|
||||||
memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
|
memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
|
||||||
@@ -1409,7 +1551,9 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
|
@@ -1415,7 +1557,9 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
|
||||||
|
|
||||||
// result_error is quadratic; we need to remap it back to linear
|
// result_error is quadratic; we need to remap it back to linear
|
||||||
if (out_result_error)
|
if (out_result_error)
|
||||||
|
|
|
@ -254,7 +254,7 @@ static bool hasEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge)
|
static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned int* loopback, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* wedge, unsigned int options)
|
||||||
{
|
{
|
||||||
memset(loop, -1, vertex_count * sizeof(unsigned int));
|
memset(loop, -1, vertex_count * sizeof(unsigned int));
|
||||||
memset(loopback, -1, vertex_count * sizeof(unsigned int));
|
memset(loopback, -1, vertex_count * sizeof(unsigned int));
|
||||||
|
@ -364,6 +364,11 @@ static void classifyVertices(unsigned char* result, unsigned int* loop, unsigned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options & meshopt_SimplifyLockBorder)
|
||||||
|
for (size_t i = 0; i < vertex_count; ++i)
|
||||||
|
if (result[i] == Kind_Border)
|
||||||
|
result[i] = Kind_Locked;
|
||||||
|
|
||||||
#if TRACE
|
#if TRACE
|
||||||
printf("locked: many open edges %d, disconnected seam %d, many seam edges %d, many wedges %d\n",
|
printf("locked: many open edges %d, disconnected seam %d, many seam edges %d, many wedges %d\n",
|
||||||
int(stats[0]), int(stats[1]), int(stats[2]), int(stats[3]));
|
int(stats[0]), int(stats[1]), int(stats[2]), int(stats[3]));
|
||||||
|
@ -1434,19 +1439,20 @@ MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoop = 0;
|
||||||
MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = 0;
|
MESHOPTIMIZER_API unsigned int* meshopt_simplifyDebugLoopBack = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size_t meshopt_simplify(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, size_t target_index_count, float target_error, float* out_result_error)
|
size_t meshopt_simplify(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, size_t target_index_count, float target_error, unsigned int options, float* out_result_error)
|
||||||
{
|
{
|
||||||
return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, out_result_error, 0, 0, 0);
|
return meshopt_simplifyWithAttributes(destination, indices, index_count, vertex_positions_data, vertex_count, vertex_positions_stride, target_index_count, target_error, options, out_result_error, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
|
size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned int* indices, size_t index_count, const float* vertex_data, size_t vertex_count, size_t vertex_stride, size_t target_index_count, float target_error, unsigned int options, float* out_result_error, const float* attributes, const float* attribute_weights, size_t attribute_count)
|
||||||
{
|
{
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_stride > 0 && vertex_stride <= 256);
|
assert(vertex_stride >= 12 && vertex_stride <= 256);
|
||||||
assert(vertex_stride % sizeof(float) == 0);
|
assert(vertex_stride % sizeof(float) == 0);
|
||||||
assert(target_index_count <= index_count);
|
assert(target_index_count <= index_count);
|
||||||
|
assert((options & ~(meshopt_SimplifyLockBorder)) == 0);
|
||||||
assert(attribute_count <= ATTRIBUTES);
|
assert(attribute_count <= ATTRIBUTES);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
@ -1467,7 +1473,7 @@ size_t meshopt_simplifyWithAttributes(unsigned int* destination, const unsigned
|
||||||
unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
|
unsigned char* vertex_kind = allocator.allocate<unsigned char>(vertex_count);
|
||||||
unsigned int* loop = allocator.allocate<unsigned int>(vertex_count);
|
unsigned int* loop = allocator.allocate<unsigned int>(vertex_count);
|
||||||
unsigned int* loopback = allocator.allocate<unsigned int>(vertex_count);
|
unsigned int* loopback = allocator.allocate<unsigned int>(vertex_count);
|
||||||
classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge);
|
classifyVertices(vertex_kind, loop, loopback, vertex_count, adjacency, remap, wedge, options);
|
||||||
|
|
||||||
#if TRACE
|
#if TRACE
|
||||||
size_t unique_positions = 0;
|
size_t unique_positions = 0;
|
||||||
|
@ -1605,7 +1611,7 @@ size_t meshopt_simplifySloppy(unsigned int* destination, const unsigned int* ind
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_positions_stride > 0 && 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(target_index_count <= index_count);
|
assert(target_index_count <= index_count);
|
||||||
|
|
||||||
|
@ -1736,7 +1742,7 @@ size_t meshopt_simplifyPoints(unsigned int* destination, const float* vertex_pos
|
||||||
{
|
{
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(vertex_positions_stride > 0 && 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(target_vertex_count <= vertex_count);
|
assert(target_vertex_count <= vertex_count);
|
||||||
|
|
||||||
|
@ -1848,7 +1854,7 @@ float meshopt_simplifyScale(const float* vertex_positions, size_t vertex_count,
|
||||||
{
|
{
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
float extent = rescalePositions(NULL, vertex_positions, vertex_count, vertex_positions_stride);
|
float extent = rescalePositions(NULL, vertex_positions, vertex_count, vertex_positions_stride);
|
||||||
|
|
|
@ -113,7 +113,7 @@ void meshopt_spatialSortRemap(unsigned int* destination, const float* vertex_pos
|
||||||
{
|
{
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
meshopt_Allocator allocator;
|
meshopt_Allocator allocator;
|
||||||
|
@ -144,7 +144,7 @@ void meshopt_spatialSortTriangles(unsigned int* destination, const unsigned int*
|
||||||
using namespace meshopt;
|
using namespace meshopt;
|
||||||
|
|
||||||
assert(index_count % 3 == 0);
|
assert(index_count % 3 == 0);
|
||||||
assert(vertex_positions_stride > 0 && 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);
|
||||||
|
|
||||||
(void)vertex_count;
|
(void)vertex_count;
|
||||||
|
|
|
@ -110,7 +110,7 @@ static unsigned int getNextVertexDeadEnd(const unsigned int* dead_end, unsigned
|
||||||
return ~0u;
|
return ~0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int getNextVertexNeighbour(const unsigned int* next_candidates_begin, const unsigned int* next_candidates_end, const unsigned int* live_triangles, const unsigned int* cache_timestamps, unsigned int timestamp, unsigned int cache_size)
|
static unsigned int getNextVertexNeighbor(const unsigned int* next_candidates_begin, const unsigned int* next_candidates_end, const unsigned int* live_triangles, const unsigned int* cache_timestamps, unsigned int timestamp, unsigned int cache_size)
|
||||||
{
|
{
|
||||||
unsigned int best_candidate = ~0u;
|
unsigned int best_candidate = ~0u;
|
||||||
int best_priority = -1;
|
int best_priority = -1;
|
||||||
|
@ -281,16 +281,16 @@ void meshopt_optimizeVertexCacheTable(unsigned int* destination, const unsigned
|
||||||
{
|
{
|
||||||
unsigned int index = indices[current_triangle * 3 + k];
|
unsigned int index = indices[current_triangle * 3 + k];
|
||||||
|
|
||||||
unsigned int* neighbours = &adjacency.data[0] + adjacency.offsets[index];
|
unsigned int* neighbors = &adjacency.data[0] + adjacency.offsets[index];
|
||||||
size_t neighbours_size = adjacency.counts[index];
|
size_t neighbors_size = adjacency.counts[index];
|
||||||
|
|
||||||
for (size_t i = 0; i < neighbours_size; ++i)
|
for (size_t i = 0; i < neighbors_size; ++i)
|
||||||
{
|
{
|
||||||
unsigned int tri = neighbours[i];
|
unsigned int tri = neighbors[i];
|
||||||
|
|
||||||
if (tri == current_triangle)
|
if (tri == current_triangle)
|
||||||
{
|
{
|
||||||
neighbours[i] = neighbours[neighbours_size - 1];
|
neighbors[i] = neighbors[neighbors_size - 1];
|
||||||
adjacency.counts[index]--;
|
adjacency.counts[index]--;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -314,10 +314,10 @@ void meshopt_optimizeVertexCacheTable(unsigned int* destination, const unsigned
|
||||||
vertex_scores[index] = score;
|
vertex_scores[index] = score;
|
||||||
|
|
||||||
// update scores of vertex triangles
|
// update scores of vertex triangles
|
||||||
const unsigned int* neighbours_begin = &adjacency.data[0] + adjacency.offsets[index];
|
const unsigned int* neighbors_begin = &adjacency.data[0] + adjacency.offsets[index];
|
||||||
const unsigned int* neighbours_end = neighbours_begin + adjacency.counts[index];
|
const unsigned int* neighbors_end = neighbors_begin + adjacency.counts[index];
|
||||||
|
|
||||||
for (const unsigned int* it = neighbours_begin; it != neighbours_end; ++it)
|
for (const unsigned int* it = neighbors_begin; it != neighbors_end; ++it)
|
||||||
{
|
{
|
||||||
unsigned int tri = *it;
|
unsigned int tri = *it;
|
||||||
assert(!emitted_flags[tri]);
|
assert(!emitted_flags[tri]);
|
||||||
|
@ -412,11 +412,11 @@ void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned i
|
||||||
{
|
{
|
||||||
const unsigned int* next_candidates_begin = &dead_end[0] + dead_end_top;
|
const unsigned int* next_candidates_begin = &dead_end[0] + dead_end_top;
|
||||||
|
|
||||||
// emit all vertex neighbours
|
// emit all vertex neighbors
|
||||||
const unsigned int* neighbours_begin = &adjacency.data[0] + adjacency.offsets[current_vertex];
|
const unsigned int* neighbors_begin = &adjacency.data[0] + adjacency.offsets[current_vertex];
|
||||||
const unsigned int* neighbours_end = neighbours_begin + adjacency.counts[current_vertex];
|
const unsigned int* neighbors_end = neighbors_begin + adjacency.counts[current_vertex];
|
||||||
|
|
||||||
for (const unsigned int* it = neighbours_begin; it != neighbours_end; ++it)
|
for (const unsigned int* it = neighbors_begin; it != neighbors_end; ++it)
|
||||||
{
|
{
|
||||||
unsigned int triangle = *it;
|
unsigned int triangle = *it;
|
||||||
|
|
||||||
|
@ -461,7 +461,7 @@ void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned i
|
||||||
const unsigned int* next_candidates_end = &dead_end[0] + dead_end_top;
|
const unsigned int* next_candidates_end = &dead_end[0] + dead_end_top;
|
||||||
|
|
||||||
// get next vertex
|
// get next vertex
|
||||||
current_vertex = getNextVertexNeighbour(next_candidates_begin, next_candidates_end, &live_triangles[0], &cache_timestamps[0], timestamp, cache_size);
|
current_vertex = getNextVertexNeighbor(next_candidates_begin, next_candidates_end, &live_triangles[0], &cache_timestamps[0], timestamp, cache_size);
|
||||||
|
|
||||||
if (current_vertex == ~0u)
|
if (current_vertex == ~0u)
|
||||||
{
|
{
|
||||||
|
|
|
@ -50,6 +50,12 @@
|
||||||
#define SIMD_TARGET
|
#define SIMD_TARGET
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// When targeting AArch64/x64, optimize for latency to allow decoding of individual 16-byte groups to overlap
|
||||||
|
// We don't do this for 32-bit systems because we need 64-bit math for this and this will hurt in-order CPUs
|
||||||
|
#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64)
|
||||||
|
#define SIMD_LATENCYOPT
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif // !MESHOPTIMIZER_NO_SIMD
|
#endif // !MESHOPTIMIZER_NO_SIMD
|
||||||
|
|
||||||
#ifdef SIMD_SSE
|
#ifdef SIMD_SSE
|
||||||
|
@ -472,6 +478,18 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi
|
||||||
typedef int unaligned_int;
|
typedef int unaligned_int;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
unsigned int data32;
|
||||||
|
memcpy(&data32, data, 4);
|
||||||
|
data32 &= data32 >> 1;
|
||||||
|
|
||||||
|
// arrange bits such that low bits of nibbles of data64 contain all 2-bit elements of data32
|
||||||
|
unsigned long long data64 = ((unsigned long long)data32 << 30) | (data32 & 0x3fffffff);
|
||||||
|
|
||||||
|
// adds all 1-bit nibbles together; the sum fits in 4 bits because datacnt=16 would have used mode 3
|
||||||
|
int datacnt = int(((data64 & 0x1111111111111111ull) * 0x1111111111111111ull) >> 60);
|
||||||
|
#endif
|
||||||
|
|
||||||
__m128i sel2 = _mm_cvtsi32_si128(*reinterpret_cast<const unaligned_int*>(data));
|
__m128i sel2 = _mm_cvtsi32_si128(*reinterpret_cast<const unaligned_int*>(data));
|
||||||
__m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 4));
|
__m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 4));
|
||||||
|
|
||||||
|
@ -490,11 +508,25 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi
|
||||||
|
|
||||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
|
_mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
|
||||||
|
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
return data + 4 + datacnt;
|
||||||
|
#else
|
||||||
return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
unsigned long long data64;
|
||||||
|
memcpy(&data64, data, 8);
|
||||||
|
data64 &= data64 >> 1;
|
||||||
|
data64 &= data64 >> 2;
|
||||||
|
|
||||||
|
// adds all 1-bit nibbles together; the sum fits in 4 bits because datacnt=16 would have used mode 3
|
||||||
|
int datacnt = int(((data64 & 0x1111111111111111ull) * 0x1111111111111111ull) >> 60);
|
||||||
|
#endif
|
||||||
|
|
||||||
__m128i sel4 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(data));
|
__m128i sel4 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(data));
|
||||||
__m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 8));
|
__m128i rest = _mm_loadu_si128(reinterpret_cast<const __m128i*>(data + 8));
|
||||||
|
|
||||||
|
@ -512,7 +544,11 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi
|
||||||
|
|
||||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
|
_mm_storeu_si128(reinterpret_cast<__m128i*>(buffer), result);
|
||||||
|
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
return data + 8 + datacnt;
|
||||||
|
#else
|
||||||
return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -604,24 +640,13 @@ static uint8x16_t shuffleBytes(unsigned char mask0, unsigned char mask1, uint8x8
|
||||||
|
|
||||||
static void neonMoveMask(uint8x16_t mask, unsigned char& mask0, unsigned char& mask1)
|
static void neonMoveMask(uint8x16_t mask, unsigned char& mask0, unsigned char& mask1)
|
||||||
{
|
{
|
||||||
static const unsigned char byte_mask_data[16] = {1, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128};
|
// magic constant found using z3 SMT assuming mask has 8 groups of 0xff or 0x00
|
||||||
|
const uint64_t magic = 0x000103070f1f3f80ull;
|
||||||
|
|
||||||
uint8x16_t byte_mask = vld1q_u8(byte_mask_data);
|
uint64x2_t mask2 = vreinterpretq_u64_u8(mask);
|
||||||
uint8x16_t masked = vandq_u8(mask, byte_mask);
|
|
||||||
|
|
||||||
#ifdef __aarch64__
|
mask0 = uint8_t((vgetq_lane_u64(mask2, 0) * magic) >> 56);
|
||||||
// aarch64 has horizontal sums; MSVC doesn't expose this via arm64_neon.h so this path is exclusive to clang/gcc
|
mask1 = uint8_t((vgetq_lane_u64(mask2, 1) * magic) >> 56);
|
||||||
mask0 = vaddv_u8(vget_low_u8(masked));
|
|
||||||
mask1 = vaddv_u8(vget_high_u8(masked));
|
|
||||||
#else
|
|
||||||
// we need horizontal sums of each half of masked, which can be done in 3 steps (yielding sums of sizes 2, 4, 8)
|
|
||||||
uint8x8_t sum1 = vpadd_u8(vget_low_u8(masked), vget_high_u8(masked));
|
|
||||||
uint8x8_t sum2 = vpadd_u8(sum1, sum1);
|
|
||||||
uint8x8_t sum3 = vpadd_u8(sum2, sum2);
|
|
||||||
|
|
||||||
mask0 = vget_lane_u8(sum3, 0);
|
|
||||||
mask1 = vget_lane_u8(sum3, 1);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2)
|
static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2)
|
||||||
|
@ -639,6 +664,18 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
unsigned int data32;
|
||||||
|
memcpy(&data32, data, 4);
|
||||||
|
data32 &= data32 >> 1;
|
||||||
|
|
||||||
|
// arrange bits such that low bits of nibbles of data64 contain all 2-bit elements of data32
|
||||||
|
unsigned long long data64 = ((unsigned long long)data32 << 30) | (data32 & 0x3fffffff);
|
||||||
|
|
||||||
|
// adds all 1-bit nibbles together; the sum fits in 4 bits because datacnt=16 would have used mode 3
|
||||||
|
int datacnt = int(((data64 & 0x1111111111111111ull) * 0x1111111111111111ull) >> 60);
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8x8_t sel2 = vld1_u8(data);
|
uint8x8_t sel2 = vld1_u8(data);
|
||||||
uint8x8_t sel22 = vzip_u8(vshr_n_u8(sel2, 4), sel2).val[0];
|
uint8x8_t sel22 = vzip_u8(vshr_n_u8(sel2, 4), sel2).val[0];
|
||||||
uint8x8x2_t sel2222 = vzip_u8(vshr_n_u8(sel22, 2), sel22);
|
uint8x8x2_t sel2222 = vzip_u8(vshr_n_u8(sel22, 2), sel22);
|
||||||
|
@ -655,11 +692,25 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi
|
||||||
|
|
||||||
vst1q_u8(buffer, result);
|
vst1q_u8(buffer, result);
|
||||||
|
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
return data + 4 + datacnt;
|
||||||
|
#else
|
||||||
return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
return data + 4 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
unsigned long long data64;
|
||||||
|
memcpy(&data64, data, 8);
|
||||||
|
data64 &= data64 >> 1;
|
||||||
|
data64 &= data64 >> 2;
|
||||||
|
|
||||||
|
// adds all 1-bit nibbles together; the sum fits in 4 bits because datacnt=16 would have used mode 3
|
||||||
|
int datacnt = int(((data64 & 0x1111111111111111ull) * 0x1111111111111111ull) >> 60);
|
||||||
|
#endif
|
||||||
|
|
||||||
uint8x8_t sel4 = vld1_u8(data);
|
uint8x8_t sel4 = vld1_u8(data);
|
||||||
uint8x8x2_t sel44 = vzip_u8(vshr_n_u8(sel4, 4), vand_u8(sel4, vdup_n_u8(15)));
|
uint8x8x2_t sel44 = vzip_u8(vshr_n_u8(sel4, 4), vand_u8(sel4, vdup_n_u8(15)));
|
||||||
uint8x16_t sel = vcombine_u8(sel44.val[0], sel44.val[1]);
|
uint8x16_t sel = vcombine_u8(sel44.val[0], sel44.val[1]);
|
||||||
|
@ -675,7 +726,11 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi
|
||||||
|
|
||||||
vst1q_u8(buffer, result);
|
vst1q_u8(buffer, result);
|
||||||
|
|
||||||
|
#ifdef SIMD_LATENCYOPT
|
||||||
|
return data + 8 + datacnt;
|
||||||
|
#else
|
||||||
return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
return data + 8 + kDecodeBytesGroupCount[mask0] + kDecodeBytesGroupCount[mask1];
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
|
@ -715,7 +770,6 @@ static void wasmMoveMask(v128_t mask, unsigned char& mask0, unsigned char& mask1
|
||||||
// magic constant found using z3 SMT assuming mask has 8 groups of 0xff or 0x00
|
// magic constant found using z3 SMT assuming mask has 8 groups of 0xff or 0x00
|
||||||
const uint64_t magic = 0x000103070f1f3f80ull;
|
const uint64_t magic = 0x000103070f1f3f80ull;
|
||||||
|
|
||||||
// TODO: This can use v8x16_bitmask in the future
|
|
||||||
mask0 = uint8_t((wasm_i64x2_extract_lane(mask, 0) * magic) >> 56);
|
mask0 = uint8_t((wasm_i64x2_extract_lane(mask, 0) * magic) >> 56);
|
||||||
mask1 = uint8_t((wasm_i64x2_extract_lane(mask, 1) * magic) >> 56);
|
mask1 = uint8_t((wasm_i64x2_extract_lane(mask, 1) * magic) >> 56);
|
||||||
}
|
}
|
||||||
|
|
|
@ -931,7 +931,7 @@ void meshopt_encodeFilterExp(void* destination_, size_t count, size_t stride, in
|
||||||
const float* v = &data[i * stride_float];
|
const float* v = &data[i * stride_float];
|
||||||
unsigned int* d = &destination[i * stride_float];
|
unsigned int* d = &destination[i * stride_float];
|
||||||
|
|
||||||
// use maximum exponent to encode values; this guarantess that mantissa is [-1, 1]
|
// use maximum exponent to encode values; this guarantees that mantissa is [-1, 1]
|
||||||
int exp = -100;
|
int exp = -100;
|
||||||
|
|
||||||
for (size_t j = 0; j < stride_float; ++j)
|
for (size_t j = 0; j < stride_float; ++j)
|
||||||
|
|
Loading…
Reference in New Issue