Created
June 19, 2018 14:02
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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], ×tamp); | |
// 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], ×tamp); | |
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], ×tamp); | |
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; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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