Skip to content

Instantly share code, notes, and snippets.

@zeux
Created June 19, 2018 14:02
Show Gist options
  • Save zeux/2f3ecc4ffb13e8d8b995fe0576243424 to your computer and use it in GitHub Desktop.
Save zeux/2f3ecc4ffb13e8d8b995fe0576243424 to your computer and use it in GitHub Desktop.
Experimental change to convert meshoptimizer code from C++03 to C99, to measure compile time & size impact of C++ on a largely-C-codebase.
diff --git a/src/indexcodec.cpp b/src/indexcodec.cpp
index 4ab92cb..18ccd43 100644
--- a/src/indexcodec.cpp
+++ b/src/indexcodec.cpp
@@ -7,9 +7,6 @@
// This work is based on:
// Fabian Giesen. Simple lossless index buffer compression & follow-up. 2013
// Conor Stokes. Vertex Cache Optimised Index Buffer Compression. 2014
-namespace meshopt
-{
-
const unsigned char kIndexHeader = 0xe0;
typedef unsigned int VertexFifo[16];
@@ -53,11 +50,11 @@ static int getEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, unsigned i
return -1;
}
-static void pushEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, size_t& offset)
+static void pushEdgeFifo(EdgeFifo fifo, unsigned int a, unsigned int b, size_t* offset)
{
- fifo[offset][0] = a;
- fifo[offset][1] = b;
- offset = (offset + 1) & 15;
+ fifo[*offset][0] = a;
+ fifo[*offset][1] = b;
+ *offset = (*offset + 1) & 15;
}
static int getVertexFifo(VertexFifo fifo, unsigned int v, size_t offset)
@@ -73,25 +70,25 @@ static int getVertexFifo(VertexFifo fifo, unsigned int v, size_t offset)
return -1;
}
-static void pushVertexFifo(VertexFifo fifo, unsigned int v, size_t& offset, int cond = 1)
+static void pushVertexFifo(VertexFifo fifo, unsigned int v, size_t* offset, int cond)
{
- fifo[offset] = v;
- offset = (offset + cond) & 15;
+ fifo[*offset] = v;
+ *offset = (*offset + cond) & 15;
}
-static void encodeVByte(unsigned char*& data, unsigned int v)
+static void encodeVByte(unsigned char** data, unsigned int v)
{
// encode 32-bit value in up to 5 7-bit groups
do
{
- *data++ = (v & 127) | (v > 127 ? 128 : 0);
+ *(*data)++ = (v & 127) | (v > 127 ? 128 : 0);
v >>= 7;
} while (v);
}
-static unsigned int decodeVByte(const unsigned char*& data)
+static unsigned int decodeVByte(const unsigned char** data)
{
- unsigned char lead = *data++;
+ unsigned char lead = *(*data)++;
// fast path: single byte
if (lead < 128)
@@ -104,7 +101,7 @@ static unsigned int decodeVByte(const unsigned char*& data)
for (int i = 0; i < 4; ++i)
{
- unsigned char group = *data++;
+ unsigned char group = *(*data)++;
result |= (group & 127) << shift;
shift += 7;
@@ -115,22 +112,22 @@ static unsigned int decodeVByte(const unsigned char*& data)
return result;
}
-static void encodeIndex(unsigned char*& data, unsigned int index, unsigned int next, unsigned int last)
+static void encodeIndex(unsigned char** data, unsigned int index, unsigned int next, unsigned int last)
{
(void)next;
unsigned int d = index - last;
- unsigned int v = (d << 1) ^ (int(d) >> 31);
+ unsigned int v = (d << 1) ^ ((int)(d) >> 31);
encodeVByte(data, v);
}
-static unsigned int decodeIndex(const unsigned char*& data, unsigned int next, unsigned int last)
+static unsigned int decodeIndex(const unsigned char** data, unsigned int next, unsigned int last)
{
(void)next;
unsigned int v = decodeVByte(data);
- unsigned int d = (v >> 1) ^ -int(v & 1);
+ unsigned int d = (v >> 1) ^ -(int)(v & 1);
return last + d;
}
@@ -148,24 +145,20 @@ static void writeTriangle(void* destination, size_t offset, size_t index_size, u
{
if (index_size == 2)
{
- static_cast<unsigned short*>(destination)[offset + 0] = static_cast<unsigned short>(a);
- static_cast<unsigned short*>(destination)[offset + 1] = static_cast<unsigned short>(b);
- static_cast<unsigned short*>(destination)[offset + 2] = static_cast<unsigned short>(c);
+ ((unsigned short*)destination)[offset + 0] = (unsigned short)(a);
+ ((unsigned short*)destination)[offset + 1] = (unsigned short)(b);
+ ((unsigned short*)destination)[offset + 2] = (unsigned short)(c);
}
else
{
- static_cast<unsigned int*>(destination)[offset + 0] = a;
- static_cast<unsigned int*>(destination)[offset + 1] = b;
- static_cast<unsigned int*>(destination)[offset + 2] = c;
+ ((unsigned int*)destination)[offset + 0] = a;
+ ((unsigned int*)destination)[offset + 1] = b;
+ ((unsigned int*)destination)[offset + 2] = c;
}
}
-} // namespace meshopt
-
size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, const unsigned int* indices, size_t index_count)
{
- using namespace meshopt;
-
assert(index_count % 3 == 0);
// the minimum valid encoding is header, 1 byte per triangle and a 16-byte codeaux table
@@ -216,19 +209,19 @@ size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, cons
int fec = (fc >= 1 && fc < 15) ? fc : (c == next) ? (next++, 0) : 15;
- *code++ = static_cast<unsigned char>((fe << 4) | fec);
+ *code++ = (unsigned char)((fe << 4) | fec);
// note that we need to update the last index since free indices are delta-encoded
if (fec == 15)
- encodeIndex(data, c, next, last), last = c;
+ encodeIndex(&data, c, next, last), last = c;
// we only need to push third vertex since first two are likely already in the vertex fifo
if (fec == 0 || fec == 15)
- pushVertexFifo(vertexfifo, c, vertexfifooffset);
+ pushVertexFifo(vertexfifo, c, &vertexfifooffset, 1);
// we only need to push two new edges to edge fifo since the third one is already there
- pushEdgeFifo(edgefifo, c, b, edgefifooffset);
- pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, &edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, &edgefifooffset);
}
else
{
@@ -246,44 +239,44 @@ size_t meshopt_encodeIndexBuffer(unsigned char* buffer, size_t buffer_size, cons
int fec = (fc >= 0 && fc < 14) ? (fc + 1) : (c == next) ? (next++, 0) : 15;
// we encode feb & fec in 4 bits using a table if possible, and as a full byte otherwise
- unsigned char codeaux = static_cast<unsigned char>((feb << 4) | fec);
+ unsigned char codeaux = (unsigned char)((feb << 4) | fec);
int codeauxindex = getCodeAuxIndex(codeaux, codeaux_table);
// <14 encodes an index into codeaux table, 14 encodes fea=0, 15 encodes fea=15
if (fea == 0 && codeauxindex >= 0 && codeauxindex < 14)
{
- *code++ = static_cast<unsigned char>((15 << 4) | codeauxindex);
+ *code++ = (unsigned char)((15 << 4) | codeauxindex);
}
else
{
- *code++ = static_cast<unsigned char>((15 << 4) | 14 | fea);
+ *code++ = (unsigned char)((15 << 4) | 14 | fea);
*data++ = codeaux;
}
// note that we need to update the last index since free indices are delta-encoded
if (fea == 15)
- encodeIndex(data, a, next, last), last = a;
+ encodeIndex(&data, a, next, last), last = a;
if (feb == 15)
- encodeIndex(data, b, next, last), last = b;
+ encodeIndex(&data, b, next, last), last = b;
if (fec == 15)
- encodeIndex(data, c, next, last), last = c;
+ encodeIndex(&data, c, next, last), last = c;
// only push vertices that weren't already in fifo
if (fea == 0 || fea == 15)
- pushVertexFifo(vertexfifo, a, vertexfifooffset);
+ pushVertexFifo(vertexfifo, a, &vertexfifooffset, 1);
if (feb == 0 || feb == 15)
- pushVertexFifo(vertexfifo, b, vertexfifooffset);
+ pushVertexFifo(vertexfifo, b, &vertexfifooffset, 1);
if (fec == 0 || fec == 15)
- pushVertexFifo(vertexfifo, c, vertexfifooffset);
+ pushVertexFifo(vertexfifo, c, &vertexfifooffset, 1);
// all three edges aren't in the fifo; pushing all of them is important so that we can match them for later triangles
- pushEdgeFifo(edgefifo, b, a, edgefifooffset);
- pushEdgeFifo(edgefifo, c, b, edgefifooffset);
- pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ pushEdgeFifo(edgefifo, b, a, &edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, &edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, &edgefifooffset);
}
}
@@ -315,7 +308,7 @@ size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count)
// compute number of bits required for each index
unsigned int vertex_bits = 1;
- while (vertex_bits < 32 && vertex_count > size_t(1) << vertex_bits)
+ while (vertex_bits < 32 && vertex_count > (size_t)(1) << vertex_bits)
vertex_bits++;
// worst-case encoding is 2 header bytes + 3 varint-7 encoded index deltas
@@ -326,8 +319,6 @@ size_t meshopt_encodeIndexBufferBound(size_t index_count, size_t vertex_count)
int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t index_size, const unsigned char* buffer, size_t buffer_size)
{
- using namespace meshopt;
-
assert(index_count % 3 == 0);
assert(index_size == 2 || index_size == 4);
@@ -392,26 +383,26 @@ int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t inde
writeTriangle(destination, i, index_size, a, b, c);
// push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
- pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0);
+ pushVertexFifo(vertexfifo, c, &vertexfifooffset, fec0);
- pushEdgeFifo(edgefifo, c, b, edgefifooffset);
- pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, &edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, &edgefifooffset);
}
else
{
unsigned int c = 0;
// note that we need to update the last index since free indices are delta-encoded
- last = c = decodeIndex(data, next, last);
+ last = c = decodeIndex(&data, next, last);
// output triangle
writeTriangle(destination, i, index_size, a, b, c);
// push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
- pushVertexFifo(vertexfifo, c, vertexfifooffset);
+ pushVertexFifo(vertexfifo, c, &vertexfifooffset, 1);
- pushEdgeFifo(edgefifo, c, b, edgefifooffset);
- pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, &edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, &edgefifooffset);
}
}
else
@@ -445,13 +436,13 @@ int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t inde
writeTriangle(destination, i, index_size, a, b, c);
// push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
- pushVertexFifo(vertexfifo, a, vertexfifooffset);
- pushVertexFifo(vertexfifo, b, vertexfifooffset, feb0);
- pushVertexFifo(vertexfifo, c, vertexfifooffset, fec0);
+ pushVertexFifo(vertexfifo, a, &vertexfifooffset, 1);
+ pushVertexFifo(vertexfifo, b, &vertexfifooffset, feb0);
+ pushVertexFifo(vertexfifo, c, &vertexfifooffset, fec0);
- pushEdgeFifo(edgefifo, b, a, edgefifooffset);
- pushEdgeFifo(edgefifo, c, b, edgefifooffset);
- pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ pushEdgeFifo(edgefifo, b, a, &edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, &edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, &edgefifooffset);
}
else
{
@@ -470,25 +461,25 @@ int meshopt_decodeIndexBuffer(void* destination, size_t index_count, size_t inde
// note that we need to update the last index since free indices are delta-encoded
if (fea == 15)
- last = a = decodeIndex(data, next, last);
+ last = a = decodeIndex(&data, next, last);
if (feb == 15)
- last = b = decodeIndex(data, next, last);
+ last = b = decodeIndex(&data, next, last);
if (fec == 15)
- last = c = decodeIndex(data, next, last);
+ last = c = decodeIndex(&data, next, last);
// output triangle
writeTriangle(destination, i, index_size, a, b, c);
// push vertex/edge fifo must match the encoding step *exactly* otherwise the data will not be decoded correctly
- pushVertexFifo(vertexfifo, a, vertexfifooffset);
- pushVertexFifo(vertexfifo, b, vertexfifooffset, (feb == 0) | (feb == 15));
- pushVertexFifo(vertexfifo, c, vertexfifooffset, (fec == 0) | (fec == 15));
+ pushVertexFifo(vertexfifo, a, &vertexfifooffset, 1);
+ pushVertexFifo(vertexfifo, b, &vertexfifooffset, (feb == 0) | (feb == 15));
+ pushVertexFifo(vertexfifo, c, &vertexfifooffset, (fec == 0) | (fec == 15));
- pushEdgeFifo(edgefifo, b, a, edgefifooffset);
- pushEdgeFifo(edgefifo, c, b, edgefifooffset);
- pushEdgeFifo(edgefifo, a, c, edgefifooffset);
+ pushEdgeFifo(edgefifo, b, a, &edgefifooffset);
+ pushEdgeFifo(edgefifo, c, b, &edgefifooffset);
+ pushEdgeFifo(edgefifo, a, c, &edgefifooffset);
}
}
}
diff --git a/src/indexgenerator.cpp b/src/indexgenerator.cpp
index 066b15e..c5eb706 100644
--- a/src/indexgenerator.cpp
+++ b/src/indexgenerator.cpp
@@ -2,49 +2,48 @@
#include "meshoptimizer.h"
#include <assert.h>
+#include <stdbool.h>
+#include <stdlib.h>
#include <string.h>
-namespace meshopt
-{
-
-struct VertexHasher
+typedef struct VertexHasher
{
const char* vertices;
size_t vertex_size;
+} VertexHasher;
- size_t hash(unsigned int index) const
- {
- // MurmurHash2
- const unsigned int m = 0x5bd1e995;
- const int r = 24;
+static size_t hash(const VertexHasher* hasher, unsigned int index)
+{
+ // MurmurHash2
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
- unsigned int h = 0;
- const char* key = vertices + index * vertex_size;
- size_t len = vertex_size;
+ unsigned int h = 0;
+ const char* key = hasher->vertices + index * hasher->vertex_size;
+ size_t len = hasher->vertex_size;
- while (len >= 4)
- {
- unsigned int k = *reinterpret_cast<const unsigned int*>(key);
-
- k *= m;
- k ^= k >> r;
- k *= m;
+ while (len >= 4)
+ {
+ unsigned int k = *(const unsigned int*)(key);
- h *= m;
- h ^= k;
+ k *= m;
+ k ^= k >> r;
+ k *= m;
- key += 4;
- len -= 4;
- }
+ h *= m;
+ h ^= k;
- return h;
+ key += 4;
+ len -= 4;
}
- bool equal(unsigned int lhs, unsigned int rhs) const
- {
- return memcmp(vertices + lhs * vertex_size, vertices + rhs * vertex_size, vertex_size) == 0;
- }
-};
+ return h;
+}
+
+static bool equal(const VertexHasher* hasher, unsigned int lhs, unsigned int rhs)
+{
+ return memcmp(hasher->vertices + lhs * hasher->vertex_size, hasher->vertices + rhs * hasher->vertex_size, hasher->vertex_size) == 0;
+}
static size_t hashBuckets(size_t count)
{
@@ -55,24 +54,23 @@ static size_t hashBuckets(size_t count)
return buckets;
}
-template <typename T, typename Hash>
-static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty)
+static unsigned int* hashLookup(unsigned int* table, size_t buckets, const VertexHasher* hasher, unsigned int key, unsigned int empty)
{
assert(buckets > 0);
assert((buckets & (buckets - 1)) == 0);
size_t hashmod = buckets - 1;
- size_t bucket = hash.hash(key) & hashmod;
+ size_t bucket = hash(hasher, key) & hashmod;
for (size_t probe = 0; probe <= hashmod; ++probe)
{
- T& item = table[bucket];
+ unsigned int* item = &table[bucket];
- if (item == empty)
- return &item;
+ if (*item == empty)
+ return item;
- if (hash.equal(item, key))
- return &item;
+ if (equal(hasher, *item, key))
+ return item;
// hash collision, quadratic probing
bucket = (bucket + probe + 1) & hashmod;
@@ -82,33 +80,30 @@ static T* hashLookup(T* table, size_t buckets, const Hash& hash, const T& key, c
return 0;
}
-} // namespace meshopt
-
size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int* indices, size_t index_count, const void* vertices, size_t vertex_count, size_t vertex_size)
{
- using namespace meshopt;
-
assert(indices || index_count == vertex_count);
assert(index_count % 3 == 0);
assert(vertex_size > 0 && vertex_size <= 256);
memset(destination, -1, vertex_count * sizeof(unsigned int));
- VertexHasher hasher = {static_cast<const char*>(vertices), vertex_size};
+ VertexHasher hasher = {(const char*)(vertices), vertex_size};
- meshopt_Buffer<unsigned int> table(hashBuckets(vertex_count));
- memset(table.data, -1, table.size * sizeof(unsigned int));
+ size_t buckets = hashBuckets(vertex_count);
+ unsigned int* table = malloc(buckets * sizeof(unsigned int));
+ memset(table, -1, buckets * sizeof(unsigned int));
unsigned int next_vertex = 0;
for (size_t i = 0; i < index_count; ++i)
{
- unsigned int index = indices ? indices[i] : unsigned(i);
+ unsigned int index = indices ? indices[i] : (unsigned)(i);
assert(index < vertex_count);
if (destination[index] == ~0u)
{
- unsigned int* entry = hashLookup(table.data, table.size, hasher, index, ~0u);
+ unsigned int* entry = hashLookup(table, buckets, &hasher, index, ~0u);
if (*entry == ~0u)
{
@@ -125,6 +120,8 @@ size_t meshopt_generateVertexRemap(unsigned int* destination, const unsigned int
}
}
+ free(table);
+
assert(next_vertex <= vertex_count);
return next_vertex;
@@ -135,13 +132,13 @@ void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t v
assert(vertex_size > 0 && vertex_size <= 256);
// support in-place remap
- meshopt_Buffer<char> vertices_copy;
+ char* vertices_copy = 0;
if (destination == vertices)
{
- vertices_copy.allocate(vertex_count * vertex_size);
- memcpy(vertices_copy.data, vertices, vertex_count * vertex_size);
- vertices = vertices_copy.data;
+ vertices_copy = malloc(vertex_count * vertex_size);
+ memcpy(vertices_copy, vertices, vertex_count * vertex_size);
+ vertices = vertices_copy;
}
for (size_t i = 0; i < vertex_count; ++i)
@@ -150,9 +147,11 @@ void meshopt_remapVertexBuffer(void* destination, const void* vertices, size_t v
{
assert(remap[i] < vertex_count);
- memcpy(static_cast<char*>(destination) + remap[i] * vertex_size, static_cast<const char*>(vertices) + i * vertex_size, vertex_size);
+ memcpy((char*)(destination) + remap[i] * vertex_size, (const char*)(vertices) + i * vertex_size, vertex_size);
}
}
+
+ free(vertices_copy);
}
void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* indices, size_t index_count, const unsigned int* remap)
@@ -161,7 +160,7 @@ void meshopt_remapIndexBuffer(unsigned int* destination, const unsigned int* ind
for (size_t i = 0; i < index_count; ++i)
{
- unsigned int index = indices ? indices[i] : unsigned(i);
+ unsigned int index = indices ? indices[i] : (unsigned)(i);
assert(remap[index] != ~0u);
destination[i] = remap[index];
diff --git a/src/meshoptimizer.h b/src/meshoptimizer.h
index a9850bd..6219397 100644
--- a/src/meshoptimizer.h
+++ b/src/meshoptimizer.h
@@ -212,7 +212,7 @@ MESHOPTIMIZER_API struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetc
#endif
/* Quantization into commonly supported data formats */
-#ifdef __cplusplus
+#if 1 // todo: c99?
/**
* Quantize a float in [0..1] range into an N-bit fixed point unorm value
* Assumes reconstruction function (q / (2^N-1)), which is the case for fixed-function normalized fixed point conversion
@@ -429,27 +429,27 @@ inline meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const T* indices
#endif
/* Inline implementation */
-#ifdef __cplusplus
+#if 1 // todo: C99?
inline int meshopt_quantizeUnorm(float v, int N)
{
- const float scale = float((1 << N) - 1);
+ const float scale = (float)((1 << N) - 1);
v = (v >= 0) ? v : 0;
v = (v <= 1) ? v : 1;
- return int(v * scale + 0.5f);
+ return (int)(v * scale + 0.5f);
}
inline int meshopt_quantizeSnorm(float v, int N)
{
- const float scale = float((1 << (N - 1)) - 1);
+ const float scale = (float)((1 << (N - 1)) - 1);
float round = (v >= 0 ? 0.5f : -0.5f);
v = (v >= -1) ? v : -1;
v = (v <= +1) ? v : +1;
- return int(v * scale + round);
+ return (int)(v * scale + round);
}
inline unsigned short meshopt_quantizeHalf(float v)
diff --git a/src/overdrawanalyzer.cpp b/src/overdrawanalyzer.cpp
index aad88b9..0cbde43 100644
--- a/src/overdrawanalyzer.cpp
+++ b/src/overdrawanalyzer.cpp
@@ -7,25 +7,30 @@
// This work is based on:
// Nicolas Capens. Advanced Rasterization. 2004
-namespace meshopt
-{
-
-const int kViewport = 256;
+enum { kViewport = 256 };
-struct OverdrawBuffer
+typedef struct OverdrawBuffer
{
float z[kViewport][kViewport][2];
unsigned int overdraw[kViewport][kViewport][2];
-};
+} OverdrawBuffer;
-template <typename T>
-static T min(T a, T b)
+static float minf(float a, float b)
{
return a < b ? a : b;
}
-template <typename T>
-static T max(T a, T b)
+static int mini(int a, int b)
+{
+ return a < b ? a : b;
+}
+
+static float maxf(float a, float b)
+{
+ return a > b ? a : b;
+}
+
+static int maxi(int a, int b)
{
return a > b ? a : b;
}
@@ -37,7 +42,7 @@ static float det2x2(float a, float b, float c, float d)
return a * d - b * c;
}
-static float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
+static float computeDepthGradients(float* dzdx, float* dzdy, float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3)
{
// z2 = z1 + dzdx * (x2 - x1) + dzdy * (y2 - y1)
// z3 = z1 + dzdx * (x3 - x1) + dzdy * (y3 - y1)
@@ -47,8 +52,8 @@ static float computeDepthGradients(float& dzdx, float& dzdy, float x1, float y1,
float det = det2x2(x2 - x1, y2 - y1, x3 - x1, y3 - y1);
float invdet = (det == 0) ? 0 : 1 / det;
- dzdx = det2x2(z2 - z1, y2 - y1, z3 - z1, y3 - y1) * invdet;
- dzdy = det2x2(x2 - x1, z2 - z1, x3 - x1, z3 - z1) * invdet;
+ *dzdx = det2x2(z2 - z1, y2 - y1, z3 - z1, y3 - y1) * invdet;
+ *dzdy = det2x2(x2 - x1, z2 - z1, x3 - x1, z3 - z1) * invdet;
return det;
}
@@ -58,7 +63,7 @@ static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, f
{
// compute depth gradients
float DZx, DZy;
- float det = computeDepthGradients(DZx, DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
+ float det = computeDepthGradients(&DZx, &DZy, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
int sign = det > 0;
// flip backfacing triangles to simplify rasterization logic
@@ -77,22 +82,22 @@ static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, f
}
// coordinates, 28.4 fixed point
- int X1 = int(16.0f * v1x + 0.5f);
- int X2 = int(16.0f * v2x + 0.5f);
- int X3 = int(16.0f * v3x + 0.5f);
+ int X1 = (int)(16.0f * v1x + 0.5f);
+ int X2 = (int)(16.0f * v2x + 0.5f);
+ int X3 = (int)(16.0f * v3x + 0.5f);
- int Y1 = int(16.0f * v1y + 0.5f);
- int Y2 = int(16.0f * v2y + 0.5f);
- int Y3 = int(16.0f * v3y + 0.5f);
+ int Y1 = (int)(16.0f * v1y + 0.5f);
+ int Y2 = (int)(16.0f * v2y + 0.5f);
+ int Y3 = (int)(16.0f * v3y + 0.5f);
// bounding rectangle, clipped against viewport
// since we rasterize pixels with covered centers, min >0.5 should round up
// as for max, due to top-left filling convention we will never rasterize right/bottom edges
// so max >= 0.5 should round down
- int minx = max((min(X1, min(X2, X3)) + 7) >> 4, 0);
- int maxx = min((max(X1, max(X2, X3)) + 7) >> 4, kViewport);
- int miny = max((min(Y1, min(Y2, Y3)) + 7) >> 4, 0);
- int maxy = min((max(Y1, max(Y2, Y3)) + 7) >> 4, kViewport);
+ int minx = maxi((mini(X1, mini(X2, X3)) + 7) >> 4, 0);
+ int maxx = mini((maxi(X1, maxi(X2, X3)) + 7) >> 4, kViewport);
+ int miny = maxi((mini(Y1, mini(Y2, Y3)) + 7) >> 4, 0);
+ int maxy = mini((maxi(Y1, maxi(Y2, Y3)) + 7) >> 4, kViewport);
// deltas, 28.4 fixed point
int DX12 = X1 - X2;
@@ -115,7 +120,7 @@ static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, f
int CY1 = DX12 * (FY - Y1) - DY12 * (FX - X1) + TL1 - 1;
int CY2 = DX23 * (FY - Y2) - DY23 * (FX - X2) + TL2 - 1;
int CY3 = DX31 * (FY - Y3) - DY31 * (FX - X3) + TL3 - 1;
- float ZY = v1z + (DZx * float(FX - X1) + DZy * float(FY - Y1)) * (1 / 16.f);
+ float ZY = v1z + (DZx * (float)(FX - X1) + DZy * (float)(FY - Y1)) * (1 / 16.f);
for (int y = miny; y < maxy; y++)
{
@@ -149,19 +154,15 @@ static void rasterize(OverdrawBuffer* buffer, float v1x, float v1y, float v1z, f
}
}
-} // namespace meshopt
-
-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)
+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)
{
- using namespace meshopt;
-
assert(index_count % 3 == 0);
assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0);
size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
- meshopt_OverdrawStatistics result = {};
+ struct meshopt_OverdrawStatistics result = {};
float minv[3] = {FLT_MAX, FLT_MAX, FLT_MAX};
float maxv[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX};
@@ -172,15 +173,15 @@ meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices,
for (int j = 0; j < 3; ++j)
{
- minv[j] = min(minv[j], v[j]);
- maxv[j] = max(maxv[j], v[j]);
+ minv[j] = minf(minv[j], v[j]);
+ maxv[j] = maxf(maxv[j], v[j]);
}
}
- float extent = max(maxv[0] - minv[0], max(maxv[1] - minv[1], maxv[2] - minv[2]));
+ float extent = maxf(maxv[0] - minv[0], maxf(maxv[1] - minv[1], maxv[2] - minv[2]));
float scale = kViewport / extent;
- meshopt_Buffer<float> triangles(index_count * 3);
+ float* triangles = malloc(index_count * 3 * sizeof(float));
for (size_t i = 0; i < index_count; ++i)
{
@@ -194,8 +195,7 @@ meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices,
triangles[i * 3 + 2] = (v[2] - minv[2]) * scale;
}
- meshopt_Buffer<OverdrawBuffer> buffer_storage(1);
- OverdrawBuffer* buffer = buffer_storage.data;
+ OverdrawBuffer* buffer = malloc(sizeof(OverdrawBuffer));
for (int axis = 0; axis < 3; ++axis)
{
@@ -232,7 +232,10 @@ meshopt_OverdrawStatistics meshopt_analyzeOverdraw(const unsigned int* indices,
}
}
- result.overdraw = result.pixels_covered ? float(result.pixels_shaded) / float(result.pixels_covered) : 0.f;
+ free(buffer);
+ free(triangles);
+
+ result.overdraw = result.pixels_covered ? (float)(result.pixels_shaded) / (float)(result.pixels_covered) : 0.f;
return result;
}
diff --git a/src/overdrawoptimizer.cpp b/src/overdrawoptimizer.cpp
index c3d7724..216001e 100644
--- a/src/overdrawoptimizer.cpp
+++ b/src/overdrawoptimizer.cpp
@@ -7,8 +7,6 @@
// This work is based on:
// Pedro Sander, Diego Nehab and Joshua Barczak. Fast Triangle Reordering for Vertex Locality and Reduced Overdraw. 2007
-namespace meshopt
-{
static void calculateSortData(float* sort_data, const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_positions_stride, const unsigned int* clusters, size_t cluster_count)
{
@@ -119,7 +117,7 @@ static void calculateSortOrderRadix(unsigned int* sort_order, const float* sort_
for (size_t i = 0; i < 1 << sort_bits; ++i)
{
size_t count = histogram[i];
- histogram[i] = unsigned(histogram_sum);
+ histogram[i] = (unsigned)(histogram_sum);
histogram_sum += count;
}
@@ -128,30 +126,30 @@ static void calculateSortOrderRadix(unsigned int* sort_order, const float* sort_
// compute sort order based on offsets
for (size_t i = 0; i < cluster_count; ++i)
{
- sort_order[histogram[sort_keys[i]]++] = unsigned(i);
+ sort_order[histogram[sort_keys[i]]++] = (unsigned)(i);
}
}
-static unsigned int updateCache(unsigned int a, unsigned int b, unsigned int c, unsigned int cache_size, unsigned int* cache_timestamps, unsigned int& timestamp)
+static unsigned int updateCache(unsigned int a, unsigned int b, unsigned int c, unsigned int cache_size, unsigned int* cache_timestamps, unsigned int* timestamp)
{
unsigned int cache_misses = 0;
// if vertex is not in cache, put it in cache
- if (timestamp - cache_timestamps[a] > cache_size)
+ if (*timestamp - cache_timestamps[a] > cache_size)
{
- cache_timestamps[a] = timestamp++;
+ cache_timestamps[a] = *timestamp++;
cache_misses++;
}
- if (timestamp - cache_timestamps[b] > cache_size)
+ if (*timestamp - cache_timestamps[b] > cache_size)
{
- cache_timestamps[b] = timestamp++;
+ cache_timestamps[b] = *timestamp++;
cache_misses++;
}
- if (timestamp - cache_timestamps[c] > cache_size)
+ if (*timestamp - cache_timestamps[c] > cache_size)
{
- cache_timestamps[c] = timestamp++;
+ cache_timestamps[c] = *timestamp++;
cache_misses++;
}
@@ -160,8 +158,8 @@ static unsigned int updateCache(unsigned int a, unsigned int b, unsigned int c,
static size_t generateHardBoundaries(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
{
- meshopt_Buffer<unsigned int> cache_timestamps(vertex_count);
- memset(cache_timestamps.data, 0, vertex_count * sizeof(unsigned int));
+ unsigned int* cache_timestamps = malloc(vertex_count * sizeof(unsigned int));
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
unsigned int timestamp = cache_size + 1;
@@ -171,7 +169,7 @@ static size_t generateHardBoundaries(unsigned int* destination, const unsigned i
for (size_t i = 0; i < face_count; ++i)
{
- unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp);
+ unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], &timestamp);
// when all three vertices are not in the cache it's usually relatively safe to assume that this is a new patch in the mesh
// that is disjoint from previous vertices; sometimes it might come back to reference existing vertices but that frequently
@@ -179,10 +177,12 @@ static size_t generateHardBoundaries(unsigned int* destination, const unsigned i
// usually the first triangle has 3 misses unless it's degenerate - thus we make sure the first cluster always starts with 0
if (i == 0 || m == 3)
{
- destination[result++] = unsigned(i);
+ destination[result++] = (unsigned)(i);
}
}
+ free(cache_timestamps);
+
assert(result <= index_count / 3);
return result;
@@ -190,8 +190,8 @@ static size_t generateHardBoundaries(unsigned int* destination, const unsigned i
static size_t generateSoftBoundaries(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, const unsigned int* clusters, size_t cluster_count, unsigned int cache_size, float threshold)
{
- meshopt_Buffer<unsigned int> cache_timestamps(vertex_count);
- memset(cache_timestamps.data, 0, vertex_count * sizeof(unsigned int));
+ unsigned int* cache_timestamps = malloc(vertex_count * sizeof(unsigned int));
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
unsigned int timestamp = 0;
@@ -211,15 +211,15 @@ static size_t generateSoftBoundaries(unsigned int* destination, const unsigned i
for (size_t i = start; i < end; ++i)
{
- unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp);
+ unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], &timestamp);
cluster_misses += m;
}
- float cluster_threshold = threshold * (float(cluster_misses) / float(end - start));
+ float cluster_threshold = threshold * ((float)(cluster_misses) / (float)(end - start));
// first cluster always starts from the hard cluster boundary
- destination[result++] = unsigned(start);
+ destination[result++] = (unsigned)(start);
// reset cache
timestamp += cache_size + 1;
@@ -229,17 +229,17 @@ static size_t generateSoftBoundaries(unsigned int* destination, const unsigned i
for (size_t i = start; i < end; ++i)
{
- unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], timestamp);
+ unsigned int m = updateCache(indices[i * 3 + 0], indices[i * 3 + 1], indices[i * 3 + 2], cache_size, &cache_timestamps[0], &timestamp);
running_misses += m;
running_faces += 1;
- if (float(running_misses) / float(running_faces) <= cluster_threshold)
+ if ((float)(running_misses) / (float)(running_faces) <= cluster_threshold)
{
// we have reached the target ACMR with the current triangle so we need to start a new cluster on the next one
// note that this may mean that we add 'end` to destination for the last triangle, which will imply that the last
// cluster is empty; however, the 'pop_back' after the loop will clean it up
- destination[result++] = unsigned(i + 1);
+ destination[result++] = (unsigned)(i + 1);
// reset cache
timestamp += cache_size + 1;
@@ -261,18 +261,16 @@ static size_t generateSoftBoundaries(unsigned int* destination, const unsigned i
}
}
+ free(cache_timestamps);
+
assert(result >= cluster_count);
assert(result <= index_count / 3);
return result;
}
-} // namespace meshopt
-
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)
{
- using namespace meshopt;
-
assert(index_count % 3 == 0);
assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0);
@@ -282,35 +280,35 @@ void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* ind
return;
// support in-place optimization
- meshopt_Buffer<unsigned int> indices_copy;
+ unsigned int* indices_copy = 0;
if (destination == indices)
{
- indices_copy.allocate(index_count);
- memcpy(indices_copy.data, indices, index_count * sizeof(unsigned int));
- indices = indices_copy.data;
+ indices_copy = malloc(index_count * sizeof(unsigned int));
+ memcpy(indices_copy, indices, index_count * sizeof(unsigned int));
+ indices = indices_copy;
}
unsigned int cache_size = 16;
// generate hard boundaries from full-triangle cache misses
- meshopt_Buffer<unsigned int> hard_clusters(index_count / 3);
+ unsigned int* hard_clusters = malloc((index_count / 3) * sizeof(unsigned int));
size_t hard_cluster_count = generateHardBoundaries(&hard_clusters[0], indices, index_count, vertex_count, cache_size);
// generate soft boundaries
- meshopt_Buffer<unsigned int> soft_clusters(index_count / 3 + 1);
+ unsigned int* soft_clusters = malloc((index_count / 3 + 1) * sizeof(unsigned int));
size_t soft_cluster_count = generateSoftBoundaries(&soft_clusters[0], indices, index_count, vertex_count, &hard_clusters[0], hard_cluster_count, cache_size, threshold);
const unsigned int* clusters = &soft_clusters[0];
size_t cluster_count = soft_cluster_count;
// fill sort data
- meshopt_Buffer<float> sort_data(cluster_count);
+ float* sort_data = malloc(cluster_count * sizeof(float));
calculateSortData(&sort_data[0], indices, index_count, vertex_positions, vertex_positions_stride, clusters, cluster_count);
// sort clusters using sort data
- meshopt_Buffer<unsigned short> sort_keys(cluster_count);
- meshopt_Buffer<unsigned int> sort_order(cluster_count);
+ unsigned short* sort_keys = malloc(cluster_count * sizeof(unsigned short));
+ unsigned int* sort_order = malloc(cluster_count * sizeof(unsigned int));
calculateSortOrderRadix(&sort_order[0], &sort_data[0], &sort_keys[0], cluster_count);
// fill output buffer
@@ -330,4 +328,11 @@ void meshopt_optimizeOverdraw(unsigned int* destination, const unsigned int* ind
}
assert(offset == index_count);
+
+ free(sort_order);
+ free(sort_keys);
+ free(sort_data);
+ free(soft_clusters);
+ free(hard_clusters);
+ free(indices_copy);
}
diff --git a/src/simplifier.cpp b/src/simplifier.cpp
index cfc4880..2ba40f4 100644
--- a/src/simplifier.cpp
+++ b/src/simplifier.cpp
@@ -13,35 +13,26 @@
// This work is based on:
// Michael Garland and Paul S. Heckbert. Surface simplification using quadric error metrics. 1997
-namespace meshopt
-{
-struct EdgeAdjacency
+typedef struct EdgeAdjacency
{
- meshopt_Buffer<unsigned int> counts;
- meshopt_Buffer<unsigned int> offsets;
- meshopt_Buffer<unsigned int> data;
-
- EdgeAdjacency(size_t index_count, size_t vertex_count)
- : counts(vertex_count)
- , offsets(vertex_count)
- , data(index_count)
- {
- }
-};
+ unsigned int* counts;
+ unsigned int* offsets;
+ unsigned int* data;
+} EdgeAdjacency;
-static void buildEdgeAdjacency(EdgeAdjacency& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count)
+static void buildEdgeAdjacency(EdgeAdjacency* adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count)
{
size_t face_count = index_count / 3;
// fill edge counts
- memset(adjacency.counts.data, 0, vertex_count * sizeof(unsigned int));
+ memset(adjacency->counts, 0, vertex_count * sizeof(unsigned int));
for (size_t i = 0; i < index_count; ++i)
{
assert(indices[i] < vertex_count);
- adjacency.counts[indices[i]]++;
+ adjacency->counts[indices[i]]++;
}
// fill offset table
@@ -49,8 +40,8 @@ static void buildEdgeAdjacency(EdgeAdjacency& adjacency, const unsigned int* ind
for (size_t i = 0; i < vertex_count; ++i)
{
- adjacency.offsets[i] = offset;
- offset += adjacency.counts[i];
+ adjacency->offsets[i] = offset;
+ offset += adjacency->counts[i];
}
assert(offset == index_count);
@@ -60,24 +51,24 @@ static void buildEdgeAdjacency(EdgeAdjacency& adjacency, const unsigned int* ind
{
unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
- adjacency.data[adjacency.offsets[a]++] = b;
- adjacency.data[adjacency.offsets[b]++] = c;
- adjacency.data[adjacency.offsets[c]++] = a;
+ adjacency->data[adjacency->offsets[a]++] = b;
+ adjacency->data[adjacency->offsets[b]++] = c;
+ adjacency->data[adjacency->offsets[c]++] = a;
}
// fix offsets that have been disturbed by the previous pass
for (size_t i = 0; i < vertex_count; ++i)
{
- assert(adjacency.offsets[i] >= adjacency.counts[i]);
+ assert(adjacency->offsets[i] >= adjacency->counts[i]);
- adjacency.offsets[i] -= adjacency.counts[i];
+ adjacency->offsets[i] -= adjacency->counts[i];
}
}
-static bool findEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned int b)
+static bool findEdge(const EdgeAdjacency* adjacency, unsigned int a, unsigned int b)
{
- unsigned int count = adjacency.counts[a];
- const unsigned int* data = adjacency.data.data + adjacency.offsets[a];
+ unsigned int count = adjacency->counts[a];
+ const unsigned int* data = adjacency->data + adjacency->offsets[a];
for (size_t i = 0; i < count; ++i)
if (data[i] == b)
@@ -86,40 +77,40 @@ static bool findEdge(const EdgeAdjacency& adjacency, unsigned int a, unsigned in
return false;
}
-struct PositionHasher
+typedef struct PositionHasher
{
const float* vertex_positions;
size_t vertex_stride_float;
+} PositionHasher;
- size_t hash(unsigned int index) const
- {
- // MurmurHash2
- const unsigned int m = 0x5bd1e995;
- const int r = 24;
+static size_t hash2(const PositionHasher* hasher, unsigned int index)
+{
+ // MurmurHash2
+ const unsigned int m = 0x5bd1e995;
+ const int r = 24;
- unsigned int h = 0;
- const unsigned int* key = reinterpret_cast<const unsigned int*>(vertex_positions + index * vertex_stride_float);
+ unsigned int h = 0;
+ const unsigned int* key = (const unsigned int*)(hasher->vertex_positions + index * hasher->vertex_stride_float);
- for (size_t i = 0; i < 3; ++i)
- {
- unsigned int k = key[i];
-
- k *= m;
- k ^= k >> r;
- k *= m;
+ for (size_t i = 0; i < 3; ++i)
+ {
+ unsigned int k = key[i];
- h *= m;
- h ^= k;
- }
+ k *= m;
+ k ^= k >> r;
+ k *= m;
- return h;
+ h *= m;
+ h ^= k;
}
- bool equal(unsigned int lhs, unsigned int rhs) const
- {
- return memcmp(vertex_positions + lhs * vertex_stride_float, vertex_positions + rhs * vertex_stride_float, 12) == 0;
- }
-};
+ return h;
+}
+
+static bool equal2(const PositionHasher* hasher, unsigned int lhs, unsigned int rhs)
+{
+ return memcmp(hasher->vertex_positions + lhs * hasher->vertex_stride_float, hasher->vertex_positions + rhs * hasher->vertex_stride_float, 12) == 0;
+}
// TODO: is there a better way to resolve naming conflicts with indexgenerator.cpp?
static size_t hashBuckets2(size_t count)
@@ -132,24 +123,23 @@ static size_t hashBuckets2(size_t count)
}
// TODO: is there a better way to resolve naming conflicts with indexgenerator.cpp?
-template <typename T, typename Hash>
-static T* hashLookup2(T* table, size_t buckets, const Hash& hash, const T& key, const T& empty)
+static unsigned int* hashLookup2(unsigned int* table, size_t buckets, const PositionHasher* hasher, unsigned int key, unsigned int empty)
{
assert(buckets > 0);
assert((buckets & (buckets - 1)) == 0);
size_t hashmod = buckets - 1;
- size_t bucket = hash.hash(key) & hashmod;
+ size_t bucket = hash2(hasher, key) & hashmod;
for (size_t probe = 0; probe <= hashmod; ++probe)
{
- T& item = table[bucket];
+ unsigned int* item = &table[bucket];
- if (item == empty)
- return &item;
+ if (*item == empty)
+ return item;
- if (hash.equal(item, key))
- return &item;
+ if (equal2(hasher, *item, key))
+ return item;
// hash collision, quadratic probing
bucket = (bucket + probe + 1) & hashmod;
@@ -163,15 +153,16 @@ static void buildPositionRemap(unsigned int* remap, unsigned int* reverse_remap,
{
PositionHasher hasher = {vertex_positions_data, vertex_positions_stride / sizeof(float)};
- meshopt_Buffer<unsigned int> table(hashBuckets2(vertex_count));
- memset(table.data, -1, table.size * sizeof(unsigned int));
+ size_t buckets = hashBuckets2(vertex_count);
+ unsigned int* table = malloc(buckets * sizeof(unsigned int));
+ memset(table, -1, buckets * sizeof(unsigned int));
// build forward remap: for each vertex, which other (canonical) vertex does it map to?
// we use position equivalence for this, and remap vertices to other existing vertices
for (size_t i = 0; i < vertex_count; ++i)
{
- unsigned int index = unsigned(i);
- unsigned int* entry = hashLookup2(table.data, table.size, hasher, index, ~0u);
+ unsigned int index = (unsigned)(i);
+ unsigned int* entry = hashLookup2(table, buckets, &hasher, index, ~0u);
if (*entry == ~0u)
{
@@ -190,18 +181,20 @@ static void buildPositionRemap(unsigned int* remap, unsigned int* reverse_remap,
// build reverse remap table: for each vertex, which other vertex remaps to this one?
// this is a many-to-one relationship, but we only identify vertices for which it's 2-1 (so a pair of vertices)
for (size_t i = 0; i < vertex_count; ++i)
- reverse_remap[i] = unsigned(i);
+ reverse_remap[i] = (unsigned)(i);
for (size_t i = 0; i < vertex_count; ++i)
if (remap[i] != i)
{
// first vertex to remap to remap[i]: keep
if (reverse_remap[remap[i]] == remap[i])
- reverse_remap[remap[i]] = unsigned(i);
+ reverse_remap[remap[i]] = (unsigned)(i);
// more than one vertex, invalidate entry
else
reverse_remap[remap[i]] = ~0u;
}
+
+ free(table);
}
enum VertexKind
@@ -224,12 +217,12 @@ const char kCanCollapse[Kind_Count][Kind_Count] = {
{0, 0, 0, 0},
};
-static size_t countOpenEdges(const EdgeAdjacency& adjacency, unsigned int vertex, unsigned int* last = 0)
+static size_t countOpenEdges(const EdgeAdjacency* adjacency, unsigned int vertex, unsigned int* last)
{
size_t result = 0;
- unsigned int count = adjacency.counts[vertex];
- const unsigned int* data = adjacency.data.data + adjacency.offsets[vertex];
+ unsigned int count = adjacency->counts[vertex];
+ const unsigned int* data = adjacency->data + adjacency->offsets[vertex];
for (size_t i = 0; i < count; ++i)
if (!findEdge(adjacency, data[i], vertex))
@@ -243,7 +236,7 @@ static size_t countOpenEdges(const EdgeAdjacency& adjacency, unsigned int vertex
return result;
}
-static void classifyVertices(unsigned char* result, size_t vertex_count, const EdgeAdjacency& adjacency, const unsigned int* remap, const unsigned int* reverse_remap, size_t lockedstats[4])
+static void classifyVertices(unsigned char* result, size_t vertex_count, const EdgeAdjacency* adjacency, const unsigned int* remap, const unsigned int* reverse_remap, size_t lockedstats[4])
{
for (size_t i = 0; i < vertex_count; ++i)
{
@@ -252,7 +245,8 @@ static void classifyVertices(unsigned char* result, size_t vertex_count, const E
if (reverse_remap[i] == i)
{
// no attribute seam, need to check if it's manifold
- size_t edges = countOpenEdges(adjacency, unsigned(i));
+ unsigned int dummy;
+ size_t edges = countOpenEdges(adjacency, (unsigned)(i), &dummy);
// note: we classify any vertices with no open edges as manifold
// this is technically incorrect - if 4 triangles share an edge, we'll classify vertices as manifold
@@ -270,7 +264,7 @@ static void classifyVertices(unsigned char* result, size_t vertex_count, const E
{
// attribute seam; need to distinguish between Seam and Locked
unsigned int a = 0;
- size_t a_count = countOpenEdges(adjacency, unsigned(i), &a);
+ size_t a_count = countOpenEdges(adjacency, (unsigned)(i), &a);
unsigned int b = 0;
size_t b_count = countOpenEdges(adjacency, reverse_remap[i], &b);
@@ -282,7 +276,7 @@ static void classifyVertices(unsigned char* result, size_t vertex_count, const E
unsigned int bf = (remap[b] == b) ? reverse_remap[b] : remap[b];
if (af != ~0u && findEdge(adjacency, af, reverse_remap[i]) &&
- bf != ~0u && findEdge(adjacency, bf, unsigned(i)))
+ bf != ~0u && findEdge(adjacency, bf, (unsigned)(i)))
result[i] = Kind_Seam;
else
result[i] = Kind_Locked, lockedstats[1]++;
@@ -307,20 +301,20 @@ static void classifyVertices(unsigned char* result, size_t vertex_count, const E
}
}
-struct Vector3
+typedef struct Vector3
{
float x, y, z;
-};
+} Vector3;
-struct Quadric
+typedef struct Quadric
{
float a00;
float a10, a11;
float a20, a21, a22;
float b0, b1, b2, c;
-};
+} Quadric;
-struct Collapse
+typedef struct Collapse
{
unsigned int v0;
unsigned int v1;
@@ -329,87 +323,87 @@ struct Collapse
float error;
unsigned int errorui;
};
-};
+} Collapse;
-static float normalize(Vector3& v)
+static float normalize(Vector3* v)
{
- float length = sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
+ float length = sqrtf(v->x * v->x + v->y * v->y + v->z * v->z);
if (length > 0)
{
- v.x /= length;
- v.y /= length;
- v.z /= length;
+ v->x /= length;
+ v->y /= length;
+ v->z /= length;
}
return length;
}
-static void quadricAdd(Quadric& Q, const Quadric& R)
+static void quadricAdd(Quadric* Q, const Quadric* R)
{
- Q.a00 += R.a00;
- Q.a10 += R.a10;
- Q.a11 += R.a11;
- Q.a20 += R.a20;
- Q.a21 += R.a21;
- Q.a22 += R.a22;
- Q.b0 += R.b0;
- Q.b1 += R.b1;
- Q.b2 += R.b2;
- Q.c += R.c;
+ Q->a00 += R->a00;
+ Q->a10 += R->a10;
+ Q->a11 += R->a11;
+ Q->a20 += R->a20;
+ Q->a21 += R->a21;
+ Q->a22 += R->a22;
+ Q->b0 += R->b0;
+ Q->b1 += R->b1;
+ Q->b2 += R->b2;
+ Q->c += R->c;
}
-static void quadricMul(Quadric& Q, float s)
+static void quadricMul(Quadric* Q, float s)
{
- Q.a00 *= s;
- Q.a10 *= s;
- Q.a11 *= s;
- Q.a20 *= s;
- Q.a21 *= s;
- Q.a22 *= s;
- Q.b0 *= s;
- Q.b1 *= s;
- Q.b2 *= s;
- Q.c *= s;
+ Q->a00 *= s;
+ Q->a10 *= s;
+ Q->a11 *= s;
+ Q->a20 *= s;
+ Q->a21 *= s;
+ Q->a22 *= s;
+ Q->b0 *= s;
+ Q->b1 *= s;
+ Q->b2 *= s;
+ Q->c *= s;
}
-static float quadricError(Quadric& Q, const Vector3& v)
+static float quadricError(Quadric* Q, const Vector3* v)
{
- float xx = v.x * v.x;
- float xy = v.x * v.y;
- float xz = v.x * v.z;
- float yy = v.y * v.y;
- float yz = v.y * v.z;
- float zz = v.z * v.z;
+ float xx = v->x * v->x;
+ float xy = v->x * v->y;
+ float xz = v->x * v->z;
+ float yy = v->y * v->y;
+ float yz = v->y * v->z;
+ float zz = v->z * v->z;
- float vTQv = Q.a00 * xx + Q.a10 * xy * 2 + Q.a11 * yy + Q.a20 * xz * 2 + Q.a21 * yz * 2 + Q.a22 * zz + Q.b0 * v.x * 2 + Q.b1 * v.y * 2 + Q.b2 * v.z * 2 + Q.c;
+ float vTQv = Q->a00 * xx + Q->a10 * xy * 2 + Q->a11 * yy + Q->a20 * xz * 2 + Q->a21 * yz * 2 + Q->a22 * zz + Q->b0 * v->x * 2 + Q->b1 * v->y * 2 + Q->b2 * v->z * 2 + Q->c;
return fabsf(vTQv);
}
-static void quadricFromPlane(Quadric& Q, float a, float b, float c, float d)
+static void quadricFromPlane(Quadric* Q, float a, float b, float c, float d)
{
- Q.a00 = a * a;
- Q.a10 = b * a;
- Q.a11 = b * b;
- Q.a20 = c * a;
- Q.a21 = c * b;
- Q.a22 = c * c;
- Q.b0 = d * a;
- Q.b1 = d * b;
- Q.b2 = d * c;
- Q.c = d * d;
+ Q->a00 = a * a;
+ Q->a10 = b * a;
+ Q->a11 = b * b;
+ Q->a20 = c * a;
+ Q->a21 = c * b;
+ Q->a22 = c * c;
+ Q->b0 = d * a;
+ Q->b1 = d * b;
+ Q->b2 = d * c;
+ Q->c = d * d;
}
-static void quadricFromTriangle(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2)
+static void quadricFromTriangle(Quadric* Q, const Vector3* p0, const Vector3* p1, const Vector3* p2)
{
- Vector3 p10 = {p1.x - p0.x, p1.y - p0.y, p1.z - p0.z};
- Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
+ Vector3 p10 = {p1->x - p0->x, p1->y - p0->y, p1->z - p0->z};
+ Vector3 p20 = {p2->x - p0->x, p2->y - p0->y, p2->z - p0->z};
Vector3 normal = {p10.y * p20.z - p10.z * p20.y, p10.z * p20.x - p10.x * p20.z, p10.x * p20.y - p10.y * p20.x};
- float area = normalize(normal);
+ float area = normalize(&normal);
- float distance = normal.x * p0.x + normal.y * p0.y + normal.z * p0.z;
+ float distance = normal.x * p0->x + normal.y * p0->y + normal.z * p0->z;
quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance);
@@ -419,18 +413,18 @@ static void quadricFromTriangle(Quadric& Q, const Vector3& p0, const Vector3& p1
quadricMul(Q, area);
}
-static void quadricFromTriangleEdge(Quadric& Q, const Vector3& p0, const Vector3& p1, const Vector3& p2, float weight)
+static void quadricFromTriangleEdge(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};
- float length = normalize(p10);
+ Vector3 p10 = {p1->x - p0->x, p1->y - p0->y, p1->z - p0->z};
+ float length = normalize(&p10);
- Vector3 p20 = {p2.x - p0.x, p2.y - p0.y, p2.z - p0.z};
+ Vector3 p20 = {p2->x - p0->x, p2->y - p0->y, p2->z - p0->z};
float p20p = p20.x * p10.x + p20.y * p10.y + p20.z * p10.z;
Vector3 normal = {p20.x - p10.x * p20p, p20.y - p10.y * p20p, p20.z - p10.z * p20p};
- normalize(normal);
+ normalize(&normal);
- float distance = normal.x * p0.x + normal.y * p0.y + normal.z * p0.z;
+ float distance = normal.x * p0->x + normal.y * p0->y + normal.z * p0->z;
// TODO: We should be able to encode squared distance to the edge here?
quadricFromPlane(Q, normal.x, normal.y, normal.z, -distance);
@@ -459,7 +453,7 @@ static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapse
for (size_t i = 0; i < 1 << sort_bits; ++i)
{
size_t count = histogram[i];
- histogram[i] = unsigned(histogram_sum);
+ histogram[i] = (unsigned)(histogram_sum);
histogram_sum += count;
}
@@ -470,19 +464,15 @@ static void sortEdgeCollapses(unsigned int* sort_order, const Collapse* collapse
{
unsigned int key = (collapses[i].errorui << 1) >> (32 - sort_bits);
- sort_order[histogram[key]++] = unsigned(i);
+ sort_order[histogram[key]++] = (unsigned)(i);
}
}
-} // namespace meshopt
-
// TODO: this is necessary for lodviewer but will go away at some point
unsigned char* meshopt_simplifyDebugKind = 0;
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)
{
- using namespace meshopt;
-
assert(index_count % 3 == 0);
assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
assert(vertex_positions_stride % sizeof(float) == 0);
@@ -491,13 +481,17 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
unsigned int* result = destination;
// build adjacency information
- EdgeAdjacency adjacency(index_count, vertex_count);
- buildEdgeAdjacency(adjacency, indices, index_count, vertex_count);
+ EdgeAdjacency adjacency = {};
+ adjacency.counts = malloc(vertex_count * sizeof(unsigned int));
+ adjacency.offsets = malloc(vertex_count * sizeof(unsigned int));
+ adjacency.data = malloc(index_count * sizeof(unsigned int));
+
+ buildEdgeAdjacency(&adjacency, indices, index_count, vertex_count);
// build position remap that maps each vertex to the one with identical position
- meshopt_Buffer<unsigned int> remap(vertex_count);
- meshopt_Buffer<unsigned int> reverse_remap(vertex_count);
- buildPositionRemap(remap.data, reverse_remap.data, vertex_positions_data, vertex_count, vertex_positions_stride);
+ unsigned int* remap = malloc(vertex_count * sizeof(unsigned int));
+ unsigned int* reverse_remap = malloc(vertex_count * sizeof(unsigned int));
+ buildPositionRemap(remap, reverse_remap, vertex_positions_data, vertex_count, vertex_positions_stride);
// TODO: maybe make this an option? this disables seam awareness
// for (size_t i = 0; i < vertex_count; ++i) remap[i] = reverse_remap[i] = unsigned(i);
@@ -505,11 +499,11 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
size_t lockedstats[4] = {};
// classify vertices; vertex kind determines collapse rules, see kCanCollapse
- meshopt_Buffer<unsigned char> vertex_kind(vertex_count);
- classifyVertices(vertex_kind.data, vertex_count, adjacency, remap.data, reverse_remap.data, lockedstats);
+ unsigned char* vertex_kind = malloc(vertex_count);
+ classifyVertices(vertex_kind, vertex_count, &adjacency, remap, reverse_remap, lockedstats);
if (meshopt_simplifyDebugKind)
- memcpy(meshopt_simplifyDebugKind, vertex_kind.data, vertex_count);
+ memcpy(meshopt_simplifyDebugKind, vertex_kind, vertex_count);
#if TRACE
size_t unique_positions = 0;
@@ -530,7 +524,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
size_t vertex_stride_float = vertex_positions_stride / sizeof(float);
- meshopt_Buffer<Vector3> vertex_positions(vertex_count);
+ Vector3* vertex_positions = malloc(vertex_count * sizeof(Vector3));
// copy positions to make code slightly simpler and improve cache efficiency
for (size_t i = 0; i < vertex_count; ++i)
@@ -542,8 +536,8 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
vertex_positions[i].z = v[2];
}
- meshopt_Buffer<Quadric> vertex_quadrics(vertex_count);
- memset(vertex_quadrics.data, 0, vertex_count * sizeof(Quadric));
+ Quadric* vertex_quadrics = malloc(vertex_count * sizeof(Quadric));
+ memset(vertex_quadrics, 0, vertex_count * sizeof(Quadric));
// face quadrics
for (size_t i = 0; i < index_count; i += 3)
@@ -556,11 +550,11 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
// assert(i0 != i1 && i0 != i2 && i1 != i2);
Quadric Q;
- quadricFromTriangle(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2]);
+ quadricFromTriangle(&Q, &vertex_positions[i0], &vertex_positions[i1], &vertex_positions[i2]);
- quadricAdd(vertex_quadrics[remap[i0]], Q);
- quadricAdd(vertex_quadrics[remap[i1]], Q);
- quadricAdd(vertex_quadrics[remap[i2]], Q);
+ quadricAdd(&vertex_quadrics[remap[i0]], &Q);
+ quadricAdd(&vertex_quadrics[remap[i1]], &Q);
+ quadricAdd(&vertex_quadrics[remap[i2]], &Q);
}
// edge quadrics for boundary edges
@@ -578,7 +572,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
if (vertex_kind[i0] != Kind_Border && vertex_kind[i0] != Kind_Seam)
continue;
- if (findEdge(adjacency, i1, i0))
+ if (findEdge(&adjacency, i1, i0))
continue;
unsigned int i2 = indices[i + next[next[e]]];
@@ -589,10 +583,10 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
float edgeWeight = vertex_kind[i0] == Kind_Seam ? 1.f : 10.f;
Quadric Q;
- quadricFromTriangleEdge(Q, vertex_positions[i0], vertex_positions[i1], vertex_positions[i2], edgeWeight);
+ quadricFromTriangleEdge(&Q, &vertex_positions[i0], &vertex_positions[i1], &vertex_positions[i2], edgeWeight);
- quadricAdd(vertex_quadrics[remap[i0]], Q);
- quadricAdd(vertex_quadrics[remap[i1]], Q);
+ quadricAdd(&vertex_quadrics[remap[i0]], &Q);
+ quadricAdd(&vertex_quadrics[remap[i1]], &Q);
boundary++;
}
@@ -610,10 +604,10 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
size_t pass_count = 0;
float worst_error = 0;
- meshopt_Buffer<Collapse> edge_collapses(index_count);
- meshopt_Buffer<unsigned int> collapse_order(index_count);
- meshopt_Buffer<unsigned int> collapse_remap(vertex_count);
- meshopt_Buffer<char> collapse_locked(vertex_count);
+ Collapse* edge_collapses = malloc(index_count * sizeof(unsigned int));
+ unsigned int* collapse_order = malloc(index_count * sizeof(unsigned int));
+ unsigned int* collapse_remap = malloc(vertex_count * sizeof(unsigned int));
+ char* collapse_locked = malloc(vertex_count);
while (index_count > target_index_count)
{
@@ -640,8 +634,8 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
if (vertex_kind[i0] == vertex_kind[i1])
{
// TODO: Garland97 uses Q1+Q2 for error estimation; here we asssume that V1 produces zero error for Q1 but it actually gets larger with more collapses
- Collapse c01 = {i0, i1, {quadricError(vertex_quadrics[remap[i0]], vertex_positions[i1])}};
- Collapse c10 = {i1, i0, {quadricError(vertex_quadrics[remap[i1]], vertex_positions[i0])}};
+ Collapse c01 = {i0, i1, {quadricError(&vertex_quadrics[remap[i0]], &vertex_positions[i1])}};
+ Collapse c10 = {i1, i0, {quadricError(&vertex_quadrics[remap[i1]], &vertex_positions[i0])}};
Collapse c = c01.error <= c10.error ? c01 : c10;
assert(c.error >= 0);
@@ -649,7 +643,7 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
}
else
{
- Collapse c = {i0, i1, {quadricError(vertex_quadrics[remap[i0]], vertex_positions[i1])}};
+ Collapse c = {i0, i1, {quadricError(&vertex_quadrics[remap[i0]], &vertex_positions[i1])}};
assert(c.error >= 0);
edge_collapses[edge_collapse_count++] = c;
@@ -661,14 +655,14 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
if (edge_collapse_count == 0)
break;
- sortEdgeCollapses(collapse_order.data, edge_collapses.data, edge_collapse_count);
+ sortEdgeCollapses(collapse_order, edge_collapses, edge_collapse_count);
for (size_t i = 0; i < vertex_count; ++i)
{
- collapse_remap[i] = unsigned(i);
+ collapse_remap[i] = (unsigned)(i);
}
- memset(collapse_locked.data, 0, vertex_count);
+ memset(collapse_locked, 0, vertex_count);
// each collapse removes 2 triangles
size_t edge_collapse_goal = (index_count - target_index_count) / 6 + 1;
@@ -681,15 +675,15 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
for (size_t i = 0; i < edge_collapse_count; ++i)
{
- const Collapse& c = edge_collapses[collapse_order[i]];
+ const Collapse* c = &edge_collapses[collapse_order[i]];
- unsigned int r0 = remap[c.v0];
- unsigned int r1 = remap[c.v1];
+ unsigned int r0 = remap[c->v0];
+ unsigned int r1 = remap[c->v1];
if (collapse_locked[r0] || collapse_locked[r1])
continue;
- if (c.error > error_limit)
+ if (c->error > error_limit)
break;
#if TRACE > 1
@@ -702,32 +696,32 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
assert(collapse_remap[r0] == r0);
assert(collapse_remap[r1] == r1);
- quadricAdd(vertex_quadrics[r1], vertex_quadrics[r0]);
+ quadricAdd(&vertex_quadrics[r1], &vertex_quadrics[r0]);
- if (vertex_kind[c.v0] == Kind_Seam)
+ if (vertex_kind[c->v0] == Kind_Seam)
{
// remap v0 to v1 and seam pair of v0 to seam pair of v1
- unsigned int s0 = c.v0 == r0 ? reverse_remap[r0] : r0;
- unsigned int s1 = c.v1 == r1 ? reverse_remap[r1] : r1;
+ unsigned int s0 = c->v0 == r0 ? reverse_remap[r0] : r0;
+ unsigned int s1 = c->v1 == r1 ? reverse_remap[r1] : r1;
- assert(s0 != ~0u && s0 != c.v0);
- assert(s1 != ~0u && s1 != c.v1);
+ assert(s0 != ~0u && s0 != c->v0);
+ assert(s1 != ~0u && s1 != c->v1);
- collapse_remap[c.v0] = c.v1;
+ collapse_remap[c->v0] = c->v1;
collapse_remap[s0] = s1;
}
else
{
- assert(c.v0 == r0 && reverse_remap[r0] == r0);
+ assert(c->v0 == r0 && reverse_remap[r0] == r0);
- collapse_remap[c.v0] = c.v1;
+ collapse_remap[c->v0] = c->v1;
}
collapse_locked[r0] = 1;
collapse_locked[r1] = 1;
collapses++;
- pass_error = c.error;
+ pass_error = c->error;
if (collapses >= edge_collapse_goal)
break;
@@ -796,5 +790,18 @@ size_t meshopt_simplify(unsigned int* destination, const unsigned int* indices,
printf("locked collapses %d -> %d: %d\n", k0, k1, int(locked_collapses[k0][k1]));
#endif
+ free(collapse_locked);
+ free(collapse_remap);
+ free(collapse_order);
+ free(edge_collapses);
+ free(vertex_quadrics);
+ free(vertex_positions);
+ free(vertex_kind);
+ free(reverse_remap);
+ free(remap);
+ free(adjacency.data);
+ free(adjacency.offsets);
+ free(adjacency.counts);
+
return index_count;
}
diff --git a/src/stripifier.cpp b/src/stripifier.cpp
index e08189d..8493e7c 100644
--- a/src/stripifier.cpp
+++ b/src/stripifier.cpp
@@ -4,9 +4,6 @@
#include <limits.h>
#include <string.h>
-namespace meshopt
-{
-
static unsigned int findStripFirst(const unsigned int buffer[][3], unsigned int buffer_size, const unsigned int* valence)
{
unsigned int index = 0;
@@ -19,7 +16,7 @@ static unsigned int findStripFirst(const unsigned int buffer[][3], unsigned int
if (v < iv)
{
- index = unsigned(i);
+ index = (unsigned)(i);
iv = v;
}
}
@@ -34,26 +31,22 @@ static int findStripNext(const unsigned int buffer[][3], unsigned int buffer_siz
unsigned int a = buffer[i][0], b = buffer[i][1], c = buffer[i][2];
if (e0 == a && e1 == b)
- return (int(i) << 2) | 2;
+ return ((int)(i) << 2) | 2;
else if (e0 == b && e1 == c)
- return (int(i) << 2) | 0;
+ return ((int)(i) << 2) | 0;
else if (e0 == c && e1 == a)
- return (int(i) << 2) | 1;
+ return ((int)(i) << 2) | 1;
}
return -1;
}
-} // namespace meshopt
-
size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count)
{
assert(destination != indices);
assert(index_count % 3 == 0);
- using namespace meshopt;
-
- const size_t buffer_capacity = 8;
+ enum { buffer_capacity = 8 };
unsigned int buffer[buffer_capacity][3] = {};
unsigned int buffer_size = 0;
@@ -66,8 +59,8 @@ size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices,
size_t strip_size = 0;
// compute vertex valence; this is used to prioritize starting triangle for strips
- meshopt_Buffer<unsigned int> valence(vertex_count);
- memset(valence.data, 0, vertex_count * sizeof(unsigned int));
+ unsigned int* valence = malloc(vertex_count * sizeof(unsigned int));
+ memset(valence, 0, vertex_count * sizeof(unsigned int));
for (size_t i = 0; i < index_count; ++i)
{
@@ -81,7 +74,7 @@ size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices,
while (buffer_size > 0 || index_offset < index_count)
{
- assert(next < 0 || (size_t(next >> 2) < buffer_size && (next & 3) < 3));
+ assert(next < 0 || ((size_t)(next >> 2) < buffer_size && (next & 3) < 3));
// fill triangle buffer
while (buffer_size < buffer_capacity && index_offset < index_count)
@@ -208,6 +201,8 @@ size_t meshopt_stripify(unsigned int* destination, const unsigned int* indices,
}
}
+ free(valence);
+
return strip_size;
}
diff --git a/src/vcacheanalyzer.cpp b/src/vcacheanalyzer.cpp
index c673352..d7712d9 100644
--- a/src/vcacheanalyzer.cpp
+++ b/src/vcacheanalyzer.cpp
@@ -4,19 +4,19 @@
#include <assert.h>
#include <string.h>
-meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size)
+struct meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size, unsigned int warp_size, unsigned int primgroup_size)
{
assert(index_count % 3 == 0);
assert(cache_size >= 3);
assert(warp_size == 0 || warp_size >= 3);
- meshopt_VertexCacheStatistics result = {};
+ struct meshopt_VertexCacheStatistics result = {};
unsigned int warp_offset = 0;
unsigned int primgroup_offset = 0;
- meshopt_Buffer<unsigned int> cache_timestamps(vertex_count);
- memset(cache_timestamps.data, 0, vertex_count * sizeof(unsigned int));
+ unsigned int* cache_timestamps = malloc(vertex_count * sizeof(unsigned int));
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
unsigned int timestamp = cache_size + 1;
@@ -64,8 +64,10 @@ meshopt_VertexCacheStatistics meshopt_analyzeVertexCache(const unsigned int* ind
result.warps_executed += warp_offset > 0;
- result.acmr = index_count == 0 ? 0 : float(result.vertices_transformed) / float(index_count / 3);
- result.atvr = unique_vertex_count == 0 ? 0 : float(result.vertices_transformed) / float(unique_vertex_count);
+ result.acmr = index_count == 0 ? 0 : (float)(result.vertices_transformed) / (float)(index_count / 3);
+ result.atvr = unique_vertex_count == 0 ? 0 : (float)(result.vertices_transformed) / (float)(unique_vertex_count);
+
+ free(cache_timestamps);
return result;
}
diff --git a/src/vcacheoptimizer.cpp b/src/vcacheoptimizer.cpp
index 865d5a2..ac1aacc 100644
--- a/src/vcacheoptimizer.cpp
+++ b/src/vcacheoptimizer.cpp
@@ -8,11 +8,9 @@
// This work is based on:
// Tom Forsyth. Linear-Speed Vertex Cache Optimisation. 2006
// Pedro Sander, Diego Nehab and Joshua Barczak. Fast Triangle Reordering for Vertex Locality and Reduced Overdraw. 2007
-namespace meshopt
-{
-const size_t max_cache_size = 16;
-const size_t max_valence = 8;
+enum { max_cache_size = 16 };
+enum { max_valence = 8 };
static const float vertex_score_table_cache[1 + max_cache_size] = {
0.f,
@@ -22,32 +20,25 @@ static const float vertex_score_table_live[1 + max_valence] = {
0.f,
0.994f, 0.721f, 0.479f, 0.423f, 0.174f, 0.080f, 0.249f, 0.056f};
-struct TriangleAdjacency
+typedef struct TriangleAdjacency
{
- meshopt_Buffer<unsigned int> counts;
- meshopt_Buffer<unsigned int> offsets;
- meshopt_Buffer<unsigned int> data;
-
- TriangleAdjacency(size_t index_count, size_t vertex_count)
- : counts(vertex_count)
- , offsets(vertex_count)
- , data(index_count)
- {
- }
-};
+ unsigned int* counts;
+ unsigned int* offsets;
+ unsigned int* data;
+} TriangleAdjacency;
-static void buildTriangleAdjacency(TriangleAdjacency& adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count)
+static void buildTriangleAdjacency(TriangleAdjacency* adjacency, const unsigned int* indices, size_t index_count, size_t vertex_count)
{
size_t face_count = index_count / 3;
// fill triangle counts
- memset(adjacency.counts.data, 0, vertex_count * sizeof(unsigned int));
+ memset(adjacency->counts, 0, vertex_count * sizeof(unsigned int));
for (size_t i = 0; i < index_count; ++i)
{
assert(indices[i] < vertex_count);
- adjacency.counts[indices[i]]++;
+ adjacency->counts[indices[i]]++;
}
// fill offset table
@@ -55,8 +46,8 @@ static void buildTriangleAdjacency(TriangleAdjacency& adjacency, const unsigned
for (size_t i = 0; i < vertex_count; ++i)
{
- adjacency.offsets[i] = offset;
- offset += adjacency.counts[i];
+ adjacency->offsets[i] = offset;
+ offset += adjacency->counts[i];
}
assert(offset == index_count);
@@ -66,38 +57,38 @@ static void buildTriangleAdjacency(TriangleAdjacency& adjacency, const unsigned
{
unsigned int a = indices[i * 3 + 0], b = indices[i * 3 + 1], c = indices[i * 3 + 2];
- adjacency.data[adjacency.offsets[a]++] = unsigned(i);
- adjacency.data[adjacency.offsets[b]++] = unsigned(i);
- adjacency.data[adjacency.offsets[c]++] = unsigned(i);
+ adjacency->data[adjacency->offsets[a]++] = (unsigned)(i);
+ adjacency->data[adjacency->offsets[b]++] = (unsigned)(i);
+ adjacency->data[adjacency->offsets[c]++] = (unsigned)(i);
}
// fix offsets that have been disturbed by the previous pass
for (size_t i = 0; i < vertex_count; ++i)
{
- assert(adjacency.offsets[i] >= adjacency.counts[i]);
+ assert(adjacency->offsets[i] >= adjacency->counts[i]);
- adjacency.offsets[i] -= adjacency.counts[i];
+ adjacency->offsets[i] -= adjacency->counts[i];
}
}
-static unsigned int getNextVertexDeadEnd(const unsigned int* dead_end, unsigned int& dead_end_top, unsigned int& input_cursor, const unsigned int* live_triangles, size_t vertex_count)
+static unsigned int getNextVertexDeadEnd(const unsigned int* dead_end, unsigned int* dead_end_top, unsigned int* input_cursor, const unsigned int* live_triangles, size_t vertex_count)
{
// check dead-end stack
- while (dead_end_top)
+ while (*dead_end_top)
{
- unsigned int vertex = dead_end[--dead_end_top];
+ unsigned int vertex = dead_end[--*dead_end_top];
if (live_triangles[vertex] > 0)
return vertex;
}
// input order
- while (input_cursor < vertex_count)
+ while (*input_cursor < vertex_count)
{
- if (live_triangles[input_cursor] > 0)
- return input_cursor;
+ if (live_triangles[*input_cursor] > 0)
+ return *input_cursor;
- ++input_cursor;
+ ++*input_cursor;
}
return ~0u;
@@ -136,33 +127,29 @@ static unsigned int getNextVertexNeighbour(const unsigned int* next_candidates_b
static float vertexScore(int cache_position, unsigned int live_triangles)
{
- assert(cache_position >= -1 && cache_position < int(max_cache_size));
+ assert(cache_position >= -1 && cache_position < (int)(max_cache_size));
unsigned int live_triangles_clamped = live_triangles < max_valence ? live_triangles : max_valence;
return vertex_score_table_cache[1 + cache_position] + vertex_score_table_live[live_triangles_clamped];
}
-static unsigned int getNextTriangleDeadEnd(unsigned int& input_cursor, const char* emitted_flags, size_t face_count)
+static unsigned int getNextTriangleDeadEnd(unsigned int* input_cursor, const char* emitted_flags, size_t face_count)
{
// input order
- while (input_cursor < face_count)
+ while (*input_cursor < face_count)
{
- if (!emitted_flags[input_cursor])
- return input_cursor;
+ if (!emitted_flags[*input_cursor])
+ return *input_cursor;
- ++input_cursor;
+ ++*input_cursor;
}
return ~0u;
}
-} // namespace meshopt
-
void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count)
{
- using namespace meshopt;
-
assert(index_count % 3 == 0);
// guard for empty meshes
@@ -170,13 +157,13 @@ void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int*
return;
// support in-place optimization
- meshopt_Buffer<unsigned int> indices_copy;
+ unsigned int* indices_copy = 0;
if (destination == indices)
{
- indices_copy.allocate(index_count);
- memcpy(indices_copy.data, indices, index_count * sizeof(unsigned int));
- indices = indices_copy.data;
+ indices_copy = malloc(index_count * sizeof(unsigned int));
+ memcpy(indices_copy, indices, index_count * sizeof(unsigned int));
+ indices = indices_copy;
}
unsigned int cache_size = 16;
@@ -185,19 +172,22 @@ void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int*
size_t face_count = index_count / 3;
// build adjacency information
- TriangleAdjacency adjacency(index_count, vertex_count);
- buildTriangleAdjacency(adjacency, indices, index_count, vertex_count);
+ TriangleAdjacency adjacency = {};
+ adjacency.counts = malloc(vertex_count * sizeof(unsigned int));
+ adjacency.offsets = malloc(vertex_count * sizeof(unsigned int));
+ adjacency.data = malloc(index_count * sizeof(unsigned int));
+ buildTriangleAdjacency(&adjacency, indices, index_count, vertex_count);
// live triangle counts
- meshopt_Buffer<unsigned int> live_triangles(vertex_count);
- memcpy(live_triangles.data, adjacency.counts.data, vertex_count * sizeof(unsigned int));
+ unsigned int* live_triangles = malloc(vertex_count * sizeof(unsigned int));
+ memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int));
// emitted flags
- meshopt_Buffer<char> emitted_flags(face_count);
- memset(emitted_flags.data, 0, face_count);
+ char* emitted_flags = malloc(face_count);
+ memset(emitted_flags, 0, face_count);
// compute initial vertex scores
- meshopt_Buffer<float> vertex_scores(vertex_count);
+ float* vertex_scores = malloc(vertex_count * sizeof(float));
for (size_t i = 0; i < vertex_count; ++i)
{
@@ -205,7 +195,7 @@ void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int*
}
// compute triangle scores
- meshopt_Buffer<float> triangle_scores(face_count);
+ float* triangle_scores = malloc(face_count * sizeof(float));
for (size_t i = 0; i < face_count; ++i)
{
@@ -300,7 +290,7 @@ void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int*
{
unsigned int index = cache[i];
- int cache_position = i >= cache_size ? -1 : int(i);
+ int cache_position = i >= cache_size ? -1 : (int)(i);
// update vertex score
float score = vertexScore(cache_position, live_triangles[index]);
@@ -335,18 +325,25 @@ void meshopt_optimizeVertexCache(unsigned int* destination, const unsigned int*
if (current_triangle == ~0u)
{
- current_triangle = getNextTriangleDeadEnd(input_cursor, &emitted_flags[0], face_count);
+ current_triangle = getNextTriangleDeadEnd(&input_cursor, &emitted_flags[0], face_count);
}
}
assert(input_cursor == face_count);
assert(output_triangle == face_count);
+
+ free(triangle_scores);
+ free(vertex_scores);
+ free(emitted_flags);
+ free(live_triangles);
+ free(adjacency.data);
+ free(adjacency.offsets);
+ free(adjacency.counts);
+ free(indices_copy);
}
void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, unsigned int cache_size)
{
- using namespace meshopt;
-
assert(index_count % 3 == 0);
assert(cache_size >= 3);
@@ -355,36 +352,39 @@ void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned i
return;
// support in-place optimization
- meshopt_Buffer<unsigned int> indices_copy;
+ unsigned int* indices_copy = 0;
if (destination == indices)
{
- indices_copy.allocate(index_count);
- memcpy(indices_copy.data, indices, index_count * sizeof(unsigned int));
- indices = indices_copy.data;
+ indices_copy = malloc(index_count * sizeof(unsigned int));
+ memcpy(indices_copy, indices, index_count * sizeof(unsigned int));
+ indices = indices_copy;
}
size_t face_count = index_count / 3;
// build adjacency information
- TriangleAdjacency adjacency(index_count, vertex_count);
- buildTriangleAdjacency(adjacency, indices, index_count, vertex_count);
+ TriangleAdjacency adjacency = {};
+ adjacency.counts = malloc(vertex_count * sizeof(unsigned int));
+ adjacency.offsets = malloc(vertex_count * sizeof(unsigned int));
+ adjacency.data = malloc(index_count * sizeof(unsigned int));
+ buildTriangleAdjacency(&adjacency, indices, index_count, vertex_count);
// live triangle counts
- meshopt_Buffer<unsigned int> live_triangles(vertex_count);
- memcpy(live_triangles.data, adjacency.counts.data, vertex_count * sizeof(unsigned int));
+ unsigned int* live_triangles = malloc(vertex_count * sizeof(unsigned int));
+ memcpy(live_triangles, adjacency.counts, vertex_count * sizeof(unsigned int));
// cache time stamps
- meshopt_Buffer<unsigned int> cache_timestamps(vertex_count);
- memset(cache_timestamps.data, 0, vertex_count * sizeof(unsigned int));
+ unsigned int* cache_timestamps = malloc(vertex_count * sizeof(unsigned int));
+ memset(cache_timestamps, 0, vertex_count * sizeof(unsigned int));
// dead-end stack
- meshopt_Buffer<unsigned int> dead_end(index_count);
+ unsigned int* dead_end = malloc(index_count * sizeof(unsigned int));
unsigned int dead_end_top = 0;
// emitted flags
- meshopt_Buffer<char> emitted_flags(face_count);
- memset(emitted_flags.data, 0, face_count);
+ char* emitted_flags = malloc(face_count);
+ memset(emitted_flags, 0, face_count);
unsigned int current_vertex = 0;
@@ -450,9 +450,18 @@ void meshopt_optimizeVertexCacheFifo(unsigned int* destination, const unsigned i
if (current_vertex == ~0u)
{
- current_vertex = getNextVertexDeadEnd(&dead_end[0], dead_end_top, input_cursor, &live_triangles[0], vertex_count);
+ current_vertex = getNextVertexDeadEnd(&dead_end[0], &dead_end_top, &input_cursor, &live_triangles[0], vertex_count);
}
}
assert(output_triangle == face_count);
+
+ free(emitted_flags);
+ free(dead_end);
+ free(cache_timestamps);
+ free(live_triangles);
+ free(adjacency.data);
+ free(adjacency.offsets);
+ free(adjacency.counts);
+ free(indices_copy);
}
diff --git a/src/vertexcodec.cpp b/src/vertexcodec.cpp
index ba9d546..28d8391 100644
--- a/src/vertexcodec.cpp
+++ b/src/vertexcodec.cpp
@@ -26,9 +26,6 @@
#include <arm_neon.h>
#endif
-namespace meshopt
-{
-
const unsigned char kVertexHeader = 0xa0;
const size_t kVertexBlockSizeBytes = 8192;
@@ -72,7 +69,7 @@ static size_t encodeBytesGroupMeasure(const unsigned char* buffer, int bits)
assert(bits >= 1 && bits <= 8);
if (bits == 1)
- return encodeBytesGroupZero(buffer) ? 0 : size_t(-1);
+ return encodeBytesGroupZero(buffer) ? 0 : (size_t)(-1);
if (bits == 8)
return kByteGroupSize;
@@ -142,7 +139,7 @@ static unsigned char* encodeBytes(unsigned char* data, unsigned char* data_end,
// round number of groups to 4 to get number of header bytes
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;
data += header_size;
@@ -151,7 +148,7 @@ static unsigned char* encodeBytes(unsigned char* data, unsigned char* data_end,
for (size_t i = 0; i < buffer_size; i += kByteGroupSize)
{
- if (size_t(data_end - data) < kTailMaxSize)
+ if ((size_t)(data_end - data) < kTailMaxSize)
return 0;
int best_bits = 8;
@@ -278,14 +275,14 @@ static const unsigned char* decodeBytes(const unsigned char* data, const unsigne
// round number of groups to 4 to get number of header bytes
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;
data += header_size;
for (size_t i = 0; i < buffer_size; i += kByteGroupSize)
{
- if (size_t(data_end - data) < kTailMaxSize)
+ if ((size_t)(data_end - data) < kTailMaxSize)
return 0;
size_t header_offset = i / kByteGroupSize;
@@ -609,7 +606,7 @@ static const unsigned char* decodeBytesSimd(const unsigned char* data, const uns
// round number of groups to 4 to get number of header bytes
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;
data += header_size;
@@ -617,7 +614,7 @@ static const unsigned char* decodeBytesSimd(const unsigned char* data, const uns
size_t i = 0;
// fast-path: process 4 groups at a time, do a shared bounds check - each group reads <=32b
- for (; i + kByteGroupSize * 4 <= buffer_size && size_t(data_end - data) >= kTailMaxSize * 4; i += kByteGroupSize * 4)
+ for (; i + kByteGroupSize * 4 <= buffer_size && (size_t)(data_end - data) >= kTailMaxSize * 4; i += kByteGroupSize * 4)
{
size_t header_offset = i / kByteGroupSize;
unsigned char header_byte = header[header_offset / 4];
@@ -631,7 +628,7 @@ static const unsigned char* decodeBytesSimd(const unsigned char* data, const uns
// slow-path: process remaining groups
for (; i < buffer_size; i += kByteGroupSize)
{
- if (size_t(data_end - data) < kTailMaxSize)
+ if ((size_t)(data_end - data) < kTailMaxSize)
return 0;
size_t header_offset = i / kByteGroupSize;
@@ -735,21 +732,17 @@ static const unsigned char* decodeVertexBlockSimd(const unsigned char* data, con
}
#endif
-} // namespace meshopt
-
size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, const void* vertices, size_t vertex_count, size_t vertex_size)
{
- using namespace meshopt;
-
assert(vertex_size > 0 && vertex_size <= 256);
assert(vertex_size % 4 == 0);
- const unsigned char* vertex_data = static_cast<const unsigned char*>(vertices);
+ const unsigned char* vertex_data = (const unsigned char*)(vertices);
unsigned char* data = buffer;
unsigned char* data_end = buffer + buffer_size;
- if (size_t(data_end - data) < 1 + vertex_size)
+ if ((size_t)(data_end - data) < 1 + vertex_size)
return 0;
*data++ = kVertexHeader;
@@ -775,7 +768,7 @@ size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, con
size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size;
- if (size_t(data_end - data) < tail_size)
+ if ((size_t)(data_end - data) < tail_size)
return 0;
// write first vertex to the end of the stream and pad it to 32 bytes; this is important to simplify bounds checks in decoder
@@ -796,8 +789,6 @@ size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, con
size_t meshopt_encodeVertexBufferBound(size_t vertex_count, size_t vertex_size)
{
- using namespace meshopt;
-
assert(vertex_size > 0 && vertex_size <= 256);
assert(vertex_size % 4 == 0);
@@ -814,8 +805,6 @@ size_t meshopt_encodeVertexBufferBound(size_t vertex_count, size_t vertex_size)
int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t vertex_size, const unsigned char* buffer, size_t buffer_size)
{
- using namespace meshopt;
-
assert(vertex_size > 0 && vertex_size <= 256);
assert(vertex_size % 4 == 0);
@@ -835,12 +824,12 @@ int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t ve
assert(gDecodeBytesGroupInitialized);
#endif
- unsigned char* vertex_data = static_cast<unsigned char*>(destination);
+ unsigned char* vertex_data = (unsigned char*)(destination);
const unsigned char* data = buffer;
const unsigned char* data_end = buffer + buffer_size;
- if (size_t(data_end - data) < 1 + vertex_size)
+ if ((size_t)(data_end - data) < 1 + vertex_size)
return -2;
if (*data++ != kVertexHeader)
@@ -866,7 +855,7 @@ int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t ve
size_t tail_size = vertex_size < kTailMaxSize ? kTailMaxSize : vertex_size;
- if (size_t(data_end - data) != tail_size)
+ if ((size_t)(data_end - data) != tail_size)
return -3;
return 0;
diff --git a/src/vfetchanalyzer.cpp b/src/vfetchanalyzer.cpp
index 8a96c0b..dc0d17e 100644
--- a/src/vfetchanalyzer.cpp
+++ b/src/vfetchanalyzer.cpp
@@ -4,18 +4,18 @@
#include <assert.h>
#include <string.h>
-meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size)
+struct meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* indices, size_t index_count, size_t vertex_count, size_t vertex_size)
{
assert(index_count % 3 == 0);
assert(vertex_size > 0 && vertex_size <= 256);
- meshopt_VertexFetchStatistics result = {};
+ struct meshopt_VertexFetchStatistics result = {};
- meshopt_Buffer<char> vertex_visited(vertex_count);
- memset(vertex_visited.data, 0, vertex_count);
+ char* vertex_visited = malloc(vertex_count);
+ memset(vertex_visited, 0, vertex_count);
- const size_t kCacheLine = 64;
- const size_t kCacheSize = 128 * 1024;
+ enum { kCacheLine = 64 };
+ enum { kCacheSize = 128 * 1024 };
// simple direct mapped cache; on typical mesh data this is close to 4-way cache, and this model is a gross approximation anyway
size_t cache[kCacheSize / kCacheLine] = {};
@@ -50,7 +50,9 @@ meshopt_VertexFetchStatistics meshopt_analyzeVertexFetch(const unsigned int* ind
for (size_t i = 0; i < vertex_count; ++i)
unique_vertex_count += vertex_visited[i];
- result.overfetch = unique_vertex_count == 0 ? 0 : float(result.bytes_fetched) / float(unique_vertex_count * vertex_size);
+ result.overfetch = unique_vertex_count == 0 ? 0 : (float)(result.bytes_fetched) / (float)(unique_vertex_count * vertex_size);
+
+ free(vertex_visited);
return result;
}
diff --git a/src/vfetchoptimizer.cpp b/src/vfetchoptimizer.cpp
index 55825a4..b9c6cb7 100644
--- a/src/vfetchoptimizer.cpp
+++ b/src/vfetchoptimizer.cpp
@@ -34,18 +34,18 @@ size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, siz
assert(vertex_size > 0 && vertex_size <= 256);
// support in-place optimization
- meshopt_Buffer<char> vertices_copy;
+ char* vertices_copy = 0;
if (destination == vertices)
{
- vertices_copy.allocate(vertex_count * vertex_size);
- memcpy(vertices_copy.data, vertices, vertex_count * vertex_size);
- vertices = vertices_copy.data;
+ vertices_copy = malloc(vertex_count * vertex_size);
+ memcpy(vertices_copy, vertices, vertex_count * vertex_size);
+ vertices = vertices_copy;
}
// build vertex remap table
- meshopt_Buffer<unsigned int> vertex_remap(vertex_count);
- memset(vertex_remap.data, -1, vertex_remap.size * sizeof(unsigned int));
+ unsigned int* vertex_remap = malloc(vertex_count * sizeof(unsigned int));
+ memset(vertex_remap, -1, vertex_count * sizeof(unsigned int));
unsigned int next_vertex = 0;
@@ -54,21 +54,24 @@ size_t meshopt_optimizeVertexFetch(void* destination, unsigned int* indices, siz
unsigned int index = indices[i];
assert(index < vertex_count);
- unsigned int& remap = vertex_remap[index];
+ unsigned int* remap = &vertex_remap[index];
- if (remap == ~0u) // vertex was not added to destination VB
+ if (*remap == ~0u) // vertex was not added to destination VB
{
// add vertex
- memcpy(static_cast<char*>(destination) + next_vertex * vertex_size, static_cast<const char*>(vertices) + index * vertex_size, vertex_size);
+ memcpy((char*)(destination) + next_vertex * vertex_size, (const char*)(vertices) + index * vertex_size, vertex_size);
- remap = next_vertex++;
+ *remap = next_vertex++;
}
// modify indices in place
- indices[i] = remap;
+ indices[i] = *remap;
}
assert(next_vertex <= vertex_count);
+ free(vertex_remap);
+ free(vertices_copy);
+
return next_vertex;
}
@zeux
Copy link
Author

zeux commented Jun 19, 2018

Compile time of all sources in one compilation unit in seconds:
gcc
c++ O0: 0.891
c99 O0: 0.626
c++ 03: 2.915
c99 O3: 2.406

clang
c++ O0: 0.665
c99 O0: 0.442
c++ O3: 2.453
c99 O3: 2.089

Binary size of a complete .so library:
gcc
c++ Os: 34968
c99 Os: 30712
c++ O3: 47200
c99 O3: 43000

clang
c++ Os: 30766
c99 Os: 30656
c++ O3: 47144
c99 O3: 42944

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment