summaryrefslogtreecommitdiff
path: root/thirdparty/xatlas
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/xatlas')
-rw-r--r--thirdparty/xatlas/xatlas.cpp2108
-rw-r--r--thirdparty/xatlas/xatlas.h36
2 files changed, 1298 insertions, 846 deletions
diff --git a/thirdparty/xatlas/xatlas.cpp b/thirdparty/xatlas/xatlas.cpp
index 9f66ae0067..d92ef1a83a 100644
--- a/thirdparty/xatlas/xatlas.cpp
+++ b/thirdparty/xatlas/xatlas.cpp
@@ -40,14 +40,14 @@ Copyright (c) 2012 Brandon Pelfrey
#if XATLAS_C_API
#include "xatlas_c.h"
#endif
-#include <assert.h>
-#include <float.h> // FLT_MAX
-#include <limits.h>
-#include <math.h>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
+#include <assert.h>
+#include <float.h> // FLT_MAX
+#include <limits.h>
+#include <math.h>
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <stdio.h>
@@ -76,10 +76,7 @@ Copyright (c) 2012 Brandon Pelfrey
#define XA_XSTR(x) XA_STR(x)
#ifndef XA_ASSERT
-#define XA_ASSERT(exp) \
- if (!(exp)) { \
- XA_PRINT_WARNING("\rASSERT: %s %s %d\n", XA_XSTR(exp), __FILE__, __LINE__); \
- }
+#define XA_ASSERT(exp) if (!(exp)) { XA_PRINT_WARNING("\rASSERT: %s %s %d\n", XA_XSTR(exp), __FILE__, __LINE__); }
#endif
#ifndef XA_DEBUG_ASSERT
@@ -87,13 +84,13 @@ Copyright (c) 2012 Brandon Pelfrey
#endif
#ifndef XA_PRINT
-#define XA_PRINT(...) \
+#define XA_PRINT(...) \
if (xatlas::internal::s_print && xatlas::internal::s_printVerbose) \
xatlas::internal::s_print(__VA_ARGS__);
#endif
#ifndef XA_PRINT_WARNING
-#define XA_PRINT_WARNING(...) \
+#define XA_PRINT_WARNING(...) \
if (xatlas::internal::s_print) \
xatlas::internal::s_print(__VA_ARGS__);
#endif
@@ -145,14 +142,18 @@ Copyright (c) 2012 Brandon Pelfrey
#define XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION 0
#define XA_DEBUG_EXPORT_OBJ_RECOMPUTED_CHARTS 0
-#define XA_DEBUG_EXPORT_OBJ (0 || XA_DEBUG_EXPORT_OBJ_FACE_GROUPS || XA_DEBUG_EXPORT_OBJ_CHART_GROUPS || XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS || XA_DEBUG_EXPORT_OBJ_CHARTS || XA_DEBUG_EXPORT_OBJ_TJUNCTION || XA_DEBUG_EXPORT_OBJ_CHARTS_AFTER_PARAMETERIZATION || XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION || XA_DEBUG_EXPORT_OBJ_RECOMPUTED_CHARTS)
+#define XA_DEBUG_EXPORT_OBJ (0 \
+ || XA_DEBUG_EXPORT_OBJ_FACE_GROUPS \
+ || XA_DEBUG_EXPORT_OBJ_CHART_GROUPS \
+ || XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS \
+ || XA_DEBUG_EXPORT_OBJ_CHARTS \
+ || XA_DEBUG_EXPORT_OBJ_TJUNCTION \
+ || XA_DEBUG_EXPORT_OBJ_CHARTS_AFTER_PARAMETERIZATION \
+ || XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION \
+ || XA_DEBUG_EXPORT_OBJ_RECOMPUTED_CHARTS)
#ifdef _MSC_VER
-#define XA_FOPEN(_file, _filename, _mode) \
- { \
- if (fopen_s(&_file, _filename, _mode) != 0) \
- _file = NULL; \
- }
+#define XA_FOPEN(_file, _filename, _mode) { if (fopen_s(&_file, _filename, _mode) != 0) _file = NULL; }
#define XA_SPRINTF(_buffer, _size, _format, ...) sprintf_s(_buffer, _size, _format, __VA_ARGS__)
#else
#define XA_FOPEN(_file, _filename, _mode) _file = fopen(_filename, _mode)
@@ -172,12 +173,11 @@ typedef uint64_t Duration;
#define XA_PROFILE_START(var) const std::chrono::time_point<std::chrono::high_resolution_clock> var##Start = std::chrono::high_resolution_clock::now();
#define XA_PROFILE_END(var) internal::s_profile.var += uint64_t(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - var##Start).count());
-#define XA_PROFILE_PRINT_AND_RESET(label, var) \
- XA_PRINT("%s%.2f seconds (%g ms)\n", label, internal::durationToSeconds(internal::s_profile.var), internal::durationToMs(internal::s_profile.var)); \
- internal::s_profile.var = 0u;
+#define XA_PROFILE_PRINT_AND_RESET(label, var) XA_PRINT("%s%.2f seconds (%g ms)\n", label, internal::durationToSeconds(internal::s_profile.var), internal::durationToMs(internal::s_profile.var)); internal::s_profile.var = 0u;
#define XA_PROFILE_ALLOC 0
-struct ProfileData {
+struct ProfileData
+{
#if XA_PROFILE_ALLOC
std::atomic<Duration> alloc;
#endif
@@ -232,11 +232,13 @@ struct ProfileData {
static ProfileData s_profile;
-static double durationToMs(Duration c) {
+static double durationToMs(Duration c)
+{
return (double)c * 0.001;
}
-static double durationToSeconds(Duration c) {
+static double durationToSeconds(Duration c)
+{
return (double)c * 0.000001;
}
#else
@@ -246,8 +248,10 @@ static double durationToSeconds(Duration c) {
#define XA_PROFILE_ALLOC 0
#endif
-struct MemTag {
- enum {
+struct MemTag
+{
+ enum
+ {
Default,
BitImage,
BVH,
@@ -270,7 +274,8 @@ struct MemTag {
};
#if XA_DEBUG_HEAP
-struct AllocHeader {
+struct AllocHeader
+{
size_t size;
const char *file;
int line;
@@ -283,10 +288,11 @@ struct AllocHeader {
static std::mutex s_allocMutex;
static AllocHeader *s_allocRoot = nullptr;
static size_t s_allocTotalCount = 0, s_allocTotalSize = 0, s_allocPeakSize = 0, s_allocCount[MemTag::Count] = { 0 }, s_allocTotalTagSize[MemTag::Count] = { 0 }, s_allocPeakTagSize[MemTag::Count] = { 0 };
-static uint32_t s_allocId = 0;
+static uint32_t s_allocId =0 ;
static constexpr uint32_t kAllocRedzone = 0x12345678;
-static void *Realloc(void *ptr, size_t size, int tag, const char *file, int line) {
+static void *Realloc(void *ptr, size_t size, int tag, const char *file, int line)
+{
std::unique_lock<std::mutex> lock(s_allocMutex);
if (!size && !ptr)
return nullptr;
@@ -347,7 +353,8 @@ static void *Realloc(void *ptr, size_t size, int tag, const char *file, int line
return newPtr + sizeof(AllocHeader);
}
-static void ReportLeaks() {
+static void ReportLeaks()
+{
printf("Checking for memory leaks...\n");
bool anyLeaks = false;
AllocHeader *header = s_allocRoot;
@@ -375,7 +382,8 @@ static void ReportLeaks() {
s_allocTotalTagSize[i] = s_allocPeakTagSize[i] = 0;
}
-static void PrintMemoryUsage() {
+static void PrintMemoryUsage()
+{
XA_PRINT("Total allocations: %zu\n", s_allocTotalCount);
XA_PRINT("Memory usage: %0.2fMB current, %0.2fMB peak\n", internal::s_allocTotalSize / 1024.0f / 1024.0f, internal::s_allocPeakSize / 1024.0f / 1024.0f);
static const char *labels[] = { // Sync with MemTag
@@ -404,7 +412,8 @@ static void PrintMemoryUsage() {
#define XA_PRINT_MEM_USAGE internal::PrintMemoryUsage();
#else
-static void *Realloc(void *ptr, size_t size, int /*tag*/, const char * /*file*/, int /*line*/) {
+static void *Realloc(void *ptr, size_t size, int /*tag*/, const char * /*file*/, int /*line*/)
+{
if (size == 0 && !ptr)
return nullptr;
if (size == 0 && s_free) {
@@ -430,75 +439,89 @@ static constexpr float kEpsilon = 0.0001f;
static constexpr float kAreaEpsilon = FLT_EPSILON;
static constexpr float kNormalEpsilon = 0.001f;
-static int align(int x, int a) {
+static int align(int x, int a)
+{
return (x + a - 1) & ~(a - 1);
}
template <typename T>
-static T max(const T &a, const T &b) {
+static T max(const T &a, const T &b)
+{
return a > b ? a : b;
}
template <typename T>
-static T min(const T &a, const T &b) {
+static T min(const T &a, const T &b)
+{
return a < b ? a : b;
}
template <typename T>
-static T max3(const T &a, const T &b, const T &c) {
+static T max3(const T &a, const T &b, const T &c)
+{
return max(a, max(b, c));
}
/// Return the maximum of the three arguments.
template <typename T>
-static T min3(const T &a, const T &b, const T &c) {
+static T min3(const T &a, const T &b, const T &c)
+{
return min(a, min(b, c));
}
/// Clamp between two values.
template <typename T>
-static T clamp(const T &x, const T &a, const T &b) {
+static T clamp(const T &x, const T &a, const T &b)
+{
return min(max(x, a), b);
}
template <typename T>
-static void swap(T &a, T &b) {
+static void swap(T &a, T &b)
+{
T temp = a;
a = b;
b = temp;
}
-union FloatUint32 {
+union FloatUint32
+{
float f;
uint32_t u;
};
-static bool isFinite(float f) {
+static bool isFinite(float f)
+{
FloatUint32 fu;
fu.f = f;
return fu.u != 0x7F800000u && fu.u != 0x7F800001u;
}
-static bool isNan(float f) {
+static bool isNan(float f)
+{
return f != f;
}
// Robust floating point comparisons:
// http://realtimecollisiondetection.net/blog/?p=89
-static bool equal(const float f0, const float f1, const float epsilon) {
+static bool equal(const float f0, const float f1, const float epsilon)
+{
//return fabs(f0-f1) <= epsilon;
return fabs(f0 - f1) <= epsilon * max3(1.0f, fabsf(f0), fabsf(f1));
}
-static int ftoi_ceil(float val) {
+static int ftoi_ceil(float val)
+{
return (int)ceilf(val);
}
-static bool isZero(const float f, const float epsilon) {
+static bool isZero(const float f, const float epsilon)
+{
return fabs(f) <= epsilon;
}
-static float square(float f) {
+static float square(float f)
+{
return f * f;
}
@@ -508,8 +531,9 @@ static float square(float f) {
* @note isPowerOfTwo(x) == true -> nextPowerOfTwo(x) == x
* @note nextPowerOfTwo(x) = 2 << log2(x-1)
*/
-static uint32_t nextPowerOfTwo(uint32_t x) {
- XA_DEBUG_ASSERT(x != 0);
+static uint32_t nextPowerOfTwo(uint32_t x)
+{
+ XA_DEBUG_ASSERT( x != 0 );
// On modern CPUs this is supposed to be as fast as using the bsr instruction.
x--;
x |= x >> 1;
@@ -520,34 +544,38 @@ static uint32_t nextPowerOfTwo(uint32_t x) {
return x + 1;
}
-class Vector2 {
+class Vector2
+{
public:
Vector2() {}
- explicit Vector2(float f) :
- x(f), y(f) {}
- Vector2(float _x, float _y) :
- x(_x), y(_y) {}
+ explicit Vector2(float f) : x(f), y(f) {}
+ Vector2(float _x, float _y): x(_x), y(_y) {}
- Vector2 operator-() const {
+ Vector2 operator-() const
+ {
return Vector2(-x, -y);
}
- void operator+=(const Vector2 &v) {
+ void operator+=(const Vector2 &v)
+ {
x += v.x;
y += v.y;
}
- void operator-=(const Vector2 &v) {
+ void operator-=(const Vector2 &v)
+ {
x -= v.x;
y -= v.y;
}
- void operator*=(float s) {
+ void operator*=(float s)
+ {
x *= s;
y *= s;
}
- void operator*=(const Vector2 &v) {
+ void operator*=(const Vector2 &v)
+ {
x *= v.x;
y *= v.y;
}
@@ -555,11 +583,13 @@ public:
float x, y;
};
-static bool operator==(const Vector2 &a, const Vector2 &b) {
+static bool operator==(const Vector2 &a, const Vector2 &b)
+{
return a.x == b.x && a.y == b.y;
}
-static bool operator!=(const Vector2 &a, const Vector2 &b) {
+static bool operator!=(const Vector2 &a, const Vector2 &b)
+{
return a.x != b.x || a.y != b.y;
}
@@ -568,33 +598,40 @@ static bool operator!=(const Vector2 &a, const Vector2 &b) {
return Vector2(a.x + b.x, a.y + b.y);
}*/
-static Vector2 operator-(const Vector2 &a, const Vector2 &b) {
+static Vector2 operator-(const Vector2 &a, const Vector2 &b)
+{
return Vector2(a.x - b.x, a.y - b.y);
}
-static Vector2 operator*(const Vector2 &v, float s) {
+static Vector2 operator*(const Vector2 &v, float s)
+{
return Vector2(v.x * s, v.y * s);
}
-static float dot(const Vector2 &a, const Vector2 &b) {
+static float dot(const Vector2 &a, const Vector2 &b)
+{
return a.x * b.x + a.y * b.y;
}
-static float lengthSquared(const Vector2 &v) {
+static float lengthSquared(const Vector2 &v)
+{
return v.x * v.x + v.y * v.y;
}
-static float length(const Vector2 &v) {
+static float length(const Vector2 &v)
+{
return sqrtf(lengthSquared(v));
}
#if XA_DEBUG
-static bool isNormalized(const Vector2 &v, float epsilon = kNormalEpsilon) {
+static bool isNormalized(const Vector2 &v, float epsilon = kNormalEpsilon)
+{
return equal(length(v), 1, epsilon);
}
#endif
-static Vector2 normalize(const Vector2 &v) {
+static Vector2 normalize(const Vector2 &v)
+{
const float l = length(v);
XA_DEBUG_ASSERT(l > 0.0f); // Never negative.
const Vector2 n = v * (1.0f / l);
@@ -602,30 +639,36 @@ static Vector2 normalize(const Vector2 &v) {
return n;
}
-static Vector2 normalizeSafe(const Vector2 &v, const Vector2 &fallback) {
+static Vector2 normalizeSafe(const Vector2 &v, const Vector2 &fallback)
+{
const float l = length(v);
if (l > 0.0f) // Never negative.
return v * (1.0f / l);
return fallback;
}
-static bool equal(const Vector2 &v1, const Vector2 &v2, float epsilon) {
+static bool equal(const Vector2 &v1, const Vector2 &v2, float epsilon)
+{
return equal(v1.x, v2.x, epsilon) && equal(v1.y, v2.y, epsilon);
}
-static Vector2 min(const Vector2 &a, const Vector2 &b) {
+static Vector2 min(const Vector2 &a, const Vector2 &b)
+{
return Vector2(min(a.x, b.x), min(a.y, b.y));
}
-static Vector2 max(const Vector2 &a, const Vector2 &b) {
+static Vector2 max(const Vector2 &a, const Vector2 &b)
+{
return Vector2(max(a.x, b.x), max(a.y, b.y));
}
-static bool isFinite(const Vector2 &v) {
+static bool isFinite(const Vector2 &v)
+{
return isFinite(v.x) && isFinite(v.y);
}
-static float triangleArea(const Vector2 &a, const Vector2 &b, const Vector2 &c) {
+static float triangleArea(const Vector2 &a, const Vector2 &b, const Vector2 &c)
+{
// IC: While it may be appealing to use the following expression:
//return (c.x * a.y + a.x * b.y + b.x * c.y - b.x * a.y - c.x * b.y - a.x * c.y) * 0.5f;
// That's actually a terrible idea. Small triangles far from the origin can end up producing fairly large floating point
@@ -639,7 +682,8 @@ static float triangleArea(const Vector2 &a, const Vector2 &b, const Vector2 &c)
return (v0.x * v1.y - v0.y * v1.x) * 0.5f;
}
-static bool linesIntersect(const Vector2 &a1, const Vector2 &a2, const Vector2 &b1, const Vector2 &b2, float epsilon) {
+static bool linesIntersect(const Vector2 &a1, const Vector2 &a2, const Vector2 &b1, const Vector2 &b2, float epsilon)
+{
const Vector2 v0 = a2 - a1;
const Vector2 v1 = b2 - b1;
const float denom = -v1.x * v0.y + v0.x * v1.y;
@@ -647,70 +691,76 @@ static bool linesIntersect(const Vector2 &a1, const Vector2 &a2, const Vector2 &
return false;
const float s = (-v0.y * (a1.x - b1.x) + v0.x * (a1.y - b1.y)) / denom;
if (s > epsilon && s < 1.0f - epsilon) {
- const float t = (v1.x * (a1.y - b1.y) - v1.y * (a1.x - b1.x)) / denom;
+ const float t = ( v1.x * (a1.y - b1.y) - v1.y * (a1.x - b1.x)) / denom;
return t > epsilon && t < 1.0f - epsilon;
}
return false;
}
-struct Vector2i {
+struct Vector2i
+{
Vector2i() {}
- Vector2i(int32_t _x, int32_t _y) :
- x(_x), y(_y) {}
+ Vector2i(int32_t _x, int32_t _y) : x(_x), y(_y) {}
int32_t x, y;
};
-class Vector3 {
+class Vector3
+{
public:
Vector3() {}
- explicit Vector3(float f) :
- x(f), y(f), z(f) {}
- Vector3(float _x, float _y, float _z) :
- x(_x), y(_y), z(_z) {}
- Vector3(const Vector2 &v, float _z) :
- x(v.x), y(v.y), z(_z) {}
-
- Vector2 xy() const {
+ explicit Vector3(float f) : x(f), y(f), z(f) {}
+ Vector3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
+ Vector3(const Vector2 &v, float _z) : x(v.x), y(v.y), z(_z) {}
+
+ Vector2 xy() const
+ {
return Vector2(x, y);
}
- Vector3 operator-() const {
+ Vector3 operator-() const
+ {
return Vector3(-x, -y, -z);
}
- void operator+=(const Vector3 &v) {
+ void operator+=(const Vector3 &v)
+ {
x += v.x;
y += v.y;
z += v.z;
}
- void operator-=(const Vector3 &v) {
+ void operator-=(const Vector3 &v)
+ {
x -= v.x;
y -= v.y;
z -= v.z;
}
- void operator*=(float s) {
+ void operator*=(float s)
+ {
x *= s;
y *= s;
z *= s;
}
- void operator/=(float s) {
+ void operator/=(float s)
+ {
float is = 1.0f / s;
x *= is;
y *= is;
z *= is;
}
- void operator*=(const Vector3 &v) {
+ void operator*=(const Vector3 &v)
+ {
x *= v.x;
y *= v.y;
z *= v.z;
}
- void operator/=(const Vector3 &v) {
+ void operator/=(const Vector3 &v)
+ {
x /= v.x;
y /= v.y;
z /= v.z;
@@ -719,47 +769,58 @@ public:
float x, y, z;
};
-static Vector3 operator+(const Vector3 &a, const Vector3 &b) {
+static Vector3 operator+(const Vector3 &a, const Vector3 &b)
+{
return Vector3(a.x + b.x, a.y + b.y, a.z + b.z);
}
-static Vector3 operator-(const Vector3 &a, const Vector3 &b) {
+static Vector3 operator-(const Vector3 &a, const Vector3 &b)
+{
return Vector3(a.x - b.x, a.y - b.y, a.z - b.z);
}
-static bool operator==(const Vector3 &a, const Vector3 &b) {
+static bool operator==(const Vector3 &a, const Vector3 &b)
+{
return a.x == b.x && a.y == b.y && a.z == b.z;
}
-static Vector3 cross(const Vector3 &a, const Vector3 &b) {
+static Vector3 cross(const Vector3 &a, const Vector3 &b)
+{
return Vector3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
}
-static Vector3 operator*(const Vector3 &v, float s) {
+static Vector3 operator*(const Vector3 &v, float s)
+{
return Vector3(v.x * s, v.y * s, v.z * s);
}
-static Vector3 operator/(const Vector3 &v, float s) {
+static Vector3 operator/(const Vector3 &v, float s)
+{
return v * (1.0f / s);
}
-static float dot(const Vector3 &a, const Vector3 &b) {
+static float dot(const Vector3 &a, const Vector3 &b)
+{
return a.x * b.x + a.y * b.y + a.z * b.z;
}
-static float lengthSquared(const Vector3 &v) {
+static float lengthSquared(const Vector3 &v)
+{
return v.x * v.x + v.y * v.y + v.z * v.z;
}
-static float length(const Vector3 &v) {
+static float length(const Vector3 &v)
+{
return sqrtf(lengthSquared(v));
}
-static bool isNormalized(const Vector3 &v, float epsilon = kNormalEpsilon) {
+static bool isNormalized(const Vector3 &v, float epsilon = kNormalEpsilon)
+{
return equal(length(v), 1.0f, epsilon);
}
-static Vector3 normalize(const Vector3 &v) {
+static Vector3 normalize(const Vector3 &v)
+{
const float l = length(v);
XA_DEBUG_ASSERT(l > 0.0f); // Never negative.
const Vector3 n = v * (1.0f / l);
@@ -767,103 +828,116 @@ static Vector3 normalize(const Vector3 &v) {
return n;
}
-static Vector3 normalizeSafe(const Vector3 &v, const Vector3 &fallback) {
+static Vector3 normalizeSafe(const Vector3 &v, const Vector3 &fallback)
+{
const float l = length(v);
if (l > 0.0f) // Never negative.
return v * (1.0f / l);
return fallback;
}
-static bool equal(const Vector3 &v0, const Vector3 &v1, float epsilon) {
+static bool equal(const Vector3 &v0, const Vector3 &v1, float epsilon)
+{
return fabs(v0.x - v1.x) <= epsilon && fabs(v0.y - v1.y) <= epsilon && fabs(v0.z - v1.z) <= epsilon;
}
-static Vector3 min(const Vector3 &a, const Vector3 &b) {
+static Vector3 min(const Vector3 &a, const Vector3 &b)
+{
return Vector3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
}
-static Vector3 max(const Vector3 &a, const Vector3 &b) {
+static Vector3 max(const Vector3 &a, const Vector3 &b)
+{
return Vector3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
}
#if XA_DEBUG
-bool isFinite(const Vector3 &v) {
+bool isFinite(const Vector3 &v)
+{
return isFinite(v.x) && isFinite(v.y) && isFinite(v.z);
}
#endif
-struct Extents2 {
+struct Extents2
+{
Vector2 min, max;
Extents2() {}
- Extents2(Vector2 p1, Vector2 p2) {
+ Extents2(Vector2 p1, Vector2 p2)
+ {
min = xatlas::internal::min(p1, p2);
max = xatlas::internal::max(p1, p2);
}
- void reset() {
+ void reset()
+ {
min.x = min.y = FLT_MAX;
max.x = max.y = -FLT_MAX;
}
- void add(Vector2 p) {
+ void add(Vector2 p)
+ {
min = xatlas::internal::min(min, p);
max = xatlas::internal::max(max, p);
}
- Vector2 midpoint() const {
+ Vector2 midpoint() const
+ {
return Vector2(min.x + (max.x - min.x) * 0.5f, min.y + (max.y - min.y) * 0.5f);
}
- static bool intersect(const Extents2 &e1, const Extents2 &e2) {
+ static bool intersect(const Extents2 &e1, const Extents2 &e2)
+ {
return e1.min.x <= e2.max.x && e1.max.x >= e2.min.x && e1.min.y <= e2.max.y && e1.max.y >= e2.min.y;
}
};
// From Fast-BVH
-struct AABB {
- AABB() :
- min(FLT_MAX, FLT_MAX, FLT_MAX), max(-FLT_MAX, -FLT_MAX, -FLT_MAX) {}
- AABB(const Vector3 &_min, const Vector3 &_max) :
- min(_min), max(_max) {}
- AABB(const Vector3 &p, float radius = 0.0f) :
- min(p), max(p) {
- if (radius > 0.0f)
- expand(radius);
- }
-
- bool intersect(const AABB &other) const {
+struct AABB
+{
+ AABB() : min(FLT_MAX, FLT_MAX, FLT_MAX), max(-FLT_MAX, -FLT_MAX, -FLT_MAX) {}
+ AABB(const Vector3 &_min, const Vector3 &_max) : min(_min), max(_max) { }
+ AABB(const Vector3 &p, float radius = 0.0f) : min(p), max(p) { if (radius > 0.0f) expand(radius); }
+
+ bool intersect(const AABB &other) const
+ {
return min.x <= other.max.x && max.x >= other.min.x && min.y <= other.max.y && max.y >= other.min.y && min.z <= other.max.z && max.z >= other.min.z;
}
- void expandToInclude(const Vector3 &p) {
+ void expandToInclude(const Vector3 &p)
+ {
min = internal::min(min, p);
max = internal::max(max, p);
}
- void expandToInclude(const AABB &aabb) {
+ void expandToInclude(const AABB &aabb)
+ {
min = internal::min(min, aabb.min);
max = internal::max(max, aabb.max);
}
- void expand(float amount) {
+ void expand(float amount)
+ {
min -= Vector3(amount);
max += Vector3(amount);
}
- Vector3 centroid() const {
+ Vector3 centroid() const
+ {
return min + (max - min) * 0.5f;
}
- uint32_t maxDimension() const {
+ uint32_t maxDimension() const
+ {
const Vector3 extent = max - min;
uint32_t result = 0;
if (extent.y > extent.x) {
result = 1;
if (extent.z > extent.y)
result = 2;
- } else if (extent.z > extent.x)
+ }
+ else if(extent.z > extent.x)
result = 2;
return result;
}
@@ -871,9 +945,10 @@ struct AABB {
Vector3 min, max;
};
-struct ArrayBase {
- ArrayBase(uint32_t _elementSize, int memTag = MemTag::Default) :
- buffer(nullptr), elementSize(_elementSize), size(0), capacity(0) {
+struct ArrayBase
+{
+ ArrayBase(uint32_t _elementSize, int memTag = MemTag::Default) : buffer(nullptr), elementSize(_elementSize), size(0), capacity(0)
+ {
#if XA_DEBUG_HEAP
this->memTag = memTag;
#else
@@ -881,15 +956,18 @@ struct ArrayBase {
#endif
}
- ~ArrayBase() {
+ ~ArrayBase()
+ {
XA_FREE(buffer);
}
- XA_INLINE void clear() {
+ XA_INLINE void clear()
+ {
size = 0;
}
- void copyFrom(const uint8_t *data, uint32_t length) {
+ void copyFrom(const uint8_t *data, uint32_t length)
+ {
XA_DEBUG_ASSERT(data);
XA_DEBUG_ASSERT(length > 0);
resize(length, true);
@@ -897,7 +975,8 @@ struct ArrayBase {
memcpy(buffer, data, length * elementSize);
}
- void copyTo(ArrayBase &other) const {
+ void copyTo(ArrayBase &other) const
+ {
XA_DEBUG_ASSERT(elementSize == other.elementSize);
XA_DEBUG_ASSERT(size > 0);
other.resize(size, true);
@@ -905,7 +984,8 @@ struct ArrayBase {
memcpy(other.buffer, buffer, size * elementSize);
}
- void destroy() {
+ void destroy()
+ {
size = 0;
XA_FREE(buffer);
buffer = nullptr;
@@ -914,7 +994,8 @@ struct ArrayBase {
}
// Insert the given element at the given index shifting all the elements up.
- void insertAt(uint32_t index, const uint8_t *value) {
+ void insertAt(uint32_t index, const uint8_t *value)
+ {
XA_DEBUG_ASSERT(index >= 0 && index <= size);
XA_DEBUG_ASSERT(value);
resize(size + 1, false);
@@ -925,7 +1006,8 @@ struct ArrayBase {
memcpy(&buffer[index * elementSize], value, elementSize);
}
- void moveTo(ArrayBase &other) {
+ void moveTo(ArrayBase &other)
+ {
XA_DEBUG_ASSERT(elementSize == other.elementSize);
other.destroy();
other.buffer = buffer;
@@ -939,12 +1021,14 @@ struct ArrayBase {
elementSize = size = capacity = 0;
}
- void pop_back() {
+ void pop_back()
+ {
XA_DEBUG_ASSERT(size > 0);
resize(size - 1, false);
}
- void push_back(const uint8_t *value) {
+ void push_back(const uint8_t *value)
+ {
XA_DEBUG_ASSERT(value < buffer || value >= buffer + size);
XA_DEBUG_ASSERT(value);
resize(size + 1, false);
@@ -953,7 +1037,8 @@ struct ArrayBase {
memcpy(&buffer[(size - 1) * elementSize], value, elementSize);
}
- void push_back(const ArrayBase &other) {
+ void push_back(const ArrayBase &other)
+ {
XA_DEBUG_ASSERT(elementSize == other.elementSize);
if (other.size > 0) {
const uint32_t oldSize = size;
@@ -965,7 +1050,8 @@ struct ArrayBase {
}
// Remove the element at the given index. This is an expensive operation!
- void removeAt(uint32_t index) {
+ void removeAt(uint32_t index)
+ {
XA_DEBUG_ASSERT(index >= 0 && index < size);
XA_DEBUG_ASSERT(buffer);
if (buffer) {
@@ -977,7 +1063,8 @@ struct ArrayBase {
}
// Element at index is swapped with the last element, then the array length is decremented.
- void removeAtFast(uint32_t index) {
+ void removeAtFast(uint32_t index)
+ {
XA_DEBUG_ASSERT(index >= 0 && index < size);
XA_DEBUG_ASSERT(buffer);
if (buffer) {
@@ -988,12 +1075,14 @@ struct ArrayBase {
}
}
- void reserve(uint32_t desiredSize) {
+ void reserve(uint32_t desiredSize)
+ {
if (desiredSize > capacity)
setArrayCapacity(desiredSize);
}
- void resize(uint32_t newSize, bool exact) {
+ void resize(uint32_t newSize, bool exact)
+ {
size = newSize;
if (size > capacity) {
// First allocation is always exact. Otherwise, following allocations grow array to 150% of desired size.
@@ -1006,7 +1095,8 @@ struct ArrayBase {
}
}
- void setArrayCapacity(uint32_t newCapacity) {
+ void setArrayCapacity(uint32_t newCapacity)
+ {
XA_DEBUG_ASSERT(newCapacity >= size);
if (newCapacity == 0) {
// free the buffer.
@@ -1026,7 +1116,8 @@ struct ArrayBase {
}
#if XA_DEBUG_HEAP
- void setMemTag(int _memTag) {
+ void setMemTag(int _memTag)
+ {
this->memTag = _memTag;
}
#endif
@@ -1040,27 +1131,30 @@ struct ArrayBase {
#endif
};
-template <typename T>
-class Array {
+template<typename T>
+class Array
+{
public:
- Array(int memTag = MemTag::Default) :
- m_base(sizeof(T), memTag) {}
- Array(const Array &) = delete;
+ Array(int memTag = MemTag::Default) : m_base(sizeof(T), memTag) {}
+ Array(const Array&) = delete;
Array &operator=(const Array &) = delete;
- XA_INLINE const T &operator[](uint32_t index) const {
+ XA_INLINE const T &operator[](uint32_t index) const
+ {
XA_DEBUG_ASSERT(index < m_base.size);
XA_DEBUG_ASSERT(m_base.buffer);
return ((const T *)m_base.buffer)[index];
}
- XA_INLINE T &operator[](uint32_t index) {
+ XA_INLINE T &operator[](uint32_t index)
+ {
XA_DEBUG_ASSERT(index < m_base.size);
XA_DEBUG_ASSERT(m_base.buffer);
return ((T *)m_base.buffer)[index];
}
- XA_INLINE const T &back() const {
+ XA_INLINE const T &back() const
+ {
XA_DEBUG_ASSERT(!isEmpty());
return ((const T *)m_base.buffer)[m_base.size - 1];
}
@@ -1068,7 +1162,8 @@ public:
XA_INLINE T *begin() { return (T *)m_base.buffer; }
XA_INLINE void clear() { m_base.clear(); }
- bool contains(const T &value) const {
+ bool contains(const T &value) const
+ {
for (uint32_t i = 0; i < m_base.size; i++) {
if (((const T *)m_base.buffer)[i] == value)
return true;
@@ -1093,23 +1188,27 @@ public:
void reserve(uint32_t desiredSize) { m_base.reserve(desiredSize); }
void resize(uint32_t newSize) { m_base.resize(newSize, true); }
- void runCtors() {
+ void runCtors()
+ {
for (uint32_t i = 0; i < m_base.size; i++)
new (&((T *)m_base.buffer)[i]) T;
}
- void runDtors() {
+ void runDtors()
+ {
for (uint32_t i = 0; i < m_base.size; i++)
((T *)m_base.buffer)[i].~T();
}
- void fill(const T &value) {
+ void fill(const T &value)
+ {
auto buffer = (T *)m_base.buffer;
for (uint32_t i = 0; i < m_base.size; i++)
buffer[i] = value;
}
- void fillBytes(uint8_t value) {
+ void fillBytes(uint8_t value)
+ {
if (m_base.buffer && m_base.size > 0)
memset(m_base.buffer, (int)value, m_base.size * m_base.elementSize);
}
@@ -1120,7 +1219,8 @@ public:
XA_INLINE uint32_t size() const { return m_base.size; }
- XA_INLINE void zeroOutMemory() {
+ XA_INLINE void zeroOutMemory()
+ {
if (m_base.buffer && m_base.size > 0)
memset(m_base.buffer, 0, m_base.elementSize * m_base.size);
}
@@ -1129,57 +1229,37 @@ private:
ArrayBase m_base;
};
-template <typename T>
-struct ArrayView {
- ArrayView() :
- data(nullptr), length(0) {}
- ArrayView(Array<T> &a) :
- data(a.data()), length(a.size()) {}
- ArrayView(T *_data, uint32_t _length) :
- data(_data), length(_length) {}
- ArrayView &operator=(Array<T> &a) {
- data = a.data();
- length = a.size();
- return *this;
- }
- XA_INLINE const T &operator[](uint32_t index) const {
- XA_DEBUG_ASSERT(index < length);
- return data[index];
- }
- XA_INLINE T &operator[](uint32_t index) {
- XA_DEBUG_ASSERT(index < length);
- return data[index];
- }
+template<typename T>
+struct ArrayView
+{
+ ArrayView() : data(nullptr), length(0) {}
+ ArrayView(Array<T> &a) : data(a.data()), length(a.size()) {}
+ ArrayView(T *_data, uint32_t _length) : data(_data), length(_length) {}
+ ArrayView &operator=(Array<T> &a) { data = a.data(); length = a.size(); return *this; }
+ XA_INLINE const T &operator[](uint32_t index) const { XA_DEBUG_ASSERT(index < length); return data[index]; }
+ XA_INLINE T &operator[](uint32_t index) { XA_DEBUG_ASSERT(index < length); return data[index]; }
T *data;
uint32_t length;
};
-template <typename T>
-struct ConstArrayView {
- ConstArrayView() :
- data(nullptr), length(0) {}
- ConstArrayView(const Array<T> &a) :
- data(a.data()), length(a.size()) {}
- ConstArrayView(ArrayView<T> av) :
- data(av.data), length(av.length) {}
- ConstArrayView(const T *_data, uint32_t _length) :
- data(_data), length(_length) {}
- ConstArrayView &operator=(const Array<T> &a) {
- data = a.data();
- length = a.size();
- return *this;
- }
- XA_INLINE const T &operator[](uint32_t index) const {
- XA_DEBUG_ASSERT(index < length);
- return data[index];
- }
+template<typename T>
+struct ConstArrayView
+{
+ ConstArrayView() : data(nullptr), length(0) {}
+ ConstArrayView(const Array<T> &a) : data(a.data()), length(a.size()) {}
+ ConstArrayView(ArrayView<T> av) : data(av.data), length(av.length) {}
+ ConstArrayView(const T *_data, uint32_t _length) : data(_data), length(_length) {}
+ ConstArrayView &operator=(const Array<T> &a) { data = a.data(); length = a.size(); return *this; }
+ XA_INLINE const T &operator[](uint32_t index) const { XA_DEBUG_ASSERT(index < length); return data[index]; }
const T *data;
uint32_t length;
};
/// Basis class to compute tangent space basis, ortogonalizations and to transform vectors from one space to another.
-struct Basis {
- XA_NODISCARD static Vector3 computeTangent(const Vector3 &normal) {
+struct Basis
+{
+ XA_NODISCARD static Vector3 computeTangent(const Vector3 &normal)
+ {
XA_ASSERT(isNormalized(normal));
// Choose minimum axis.
Vector3 tangent;
@@ -1195,7 +1275,8 @@ struct Basis {
return tangent;
}
- XA_NODISCARD static Vector3 computeBitangent(const Vector3 &normal, const Vector3 &tangent) {
+ XA_NODISCARD static Vector3 computeBitangent(const Vector3 &normal, const Vector3 &tangent)
+ {
return cross(normal, tangent);
}
@@ -1205,36 +1286,42 @@ struct Basis {
};
// Simple bit array.
-class BitArray {
+class BitArray
+{
public:
- BitArray() :
- m_size(0) {}
+ BitArray() : m_size(0) {}
- BitArray(uint32_t sz) {
+ BitArray(uint32_t sz)
+ {
resize(sz);
}
- void resize(uint32_t new_size) {
+ void resize(uint32_t new_size)
+ {
m_size = new_size;
m_wordArray.resize((m_size + 31) >> 5);
}
- bool get(uint32_t index) const {
+ bool get(uint32_t index) const
+ {
XA_DEBUG_ASSERT(index < m_size);
return (m_wordArray[index >> 5] & (1 << (index & 31))) != 0;
}
- void set(uint32_t index) {
+ void set(uint32_t index)
+ {
XA_DEBUG_ASSERT(index < m_size);
m_wordArray[index >> 5] |= (1 << (index & 31));
}
- void unset(uint32_t index) {
+ void unset(uint32_t index)
+ {
XA_DEBUG_ASSERT(index < m_size);
m_wordArray[index >> 5] &= ~(1 << (index & 31));
}
- void zeroOutMemory() {
+ void zeroOutMemory()
+ {
m_wordArray.zeroOutMemory();
}
@@ -1243,13 +1330,13 @@ private:
Array<uint32_t> m_wordArray;
};
-class BitImage {
+class BitImage
+{
public:
- BitImage() :
- m_width(0), m_height(0), m_rowStride(0), m_data(MemTag::BitImage) {}
+ BitImage() : m_width(0), m_height(0), m_rowStride(0), m_data(MemTag::BitImage) {}
- BitImage(uint32_t w, uint32_t h) :
- m_width(w), m_height(h), m_data(MemTag::BitImage) {
+ BitImage(uint32_t w, uint32_t h) : m_width(w), m_height(h), m_data(MemTag::BitImage)
+ {
m_rowStride = (m_width + 63) >> 6;
m_data.resize(m_rowStride * m_height);
m_data.zeroOutMemory();
@@ -1260,14 +1347,16 @@ public:
uint32_t width() const { return m_width; }
uint32_t height() const { return m_height; }
- void copyTo(BitImage &other) {
+ void copyTo(BitImage &other)
+ {
other.m_width = m_width;
other.m_height = m_height;
other.m_rowStride = m_rowStride;
m_data.copyTo(other.m_data);
}
- void resize(uint32_t w, uint32_t h, bool discard) {
+ void resize(uint32_t w, uint32_t h, bool discard)
+ {
const uint32_t rowStride = (w + 63) >> 6;
if (discard) {
m_data.resize(rowStride * h);
@@ -1291,24 +1380,28 @@ public:
m_rowStride = rowStride;
}
- bool get(uint32_t x, uint32_t y) const {
+ bool get(uint32_t x, uint32_t y) const
+ {
XA_DEBUG_ASSERT(x < m_width && y < m_height);
const uint32_t index = (x >> 6) + y * m_rowStride;
return (m_data[index] & (UINT64_C(1) << (uint64_t(x) & UINT64_C(63)))) != 0;
}
- void set(uint32_t x, uint32_t y) {
+ void set(uint32_t x, uint32_t y)
+ {
XA_DEBUG_ASSERT(x < m_width && y < m_height);
const uint32_t index = (x >> 6) + y * m_rowStride;
m_data[index] |= UINT64_C(1) << (uint64_t(x) & UINT64_C(63));
XA_DEBUG_ASSERT(get(x, y));
}
- void zeroOutMemory() {
+ void zeroOutMemory()
+ {
m_data.zeroOutMemory();
}
- bool canBlit(const BitImage &image, uint32_t offsetX, uint32_t offsetY) const {
+ bool canBlit(const BitImage &image, uint32_t offsetX, uint32_t offsetY) const
+ {
for (uint32_t y = 0; y < image.m_height; y++) {
const uint32_t thisY = y + offsetY;
if (thisY >= m_height)
@@ -1332,7 +1425,8 @@ public:
return true;
}
- void dilate(uint32_t padding) {
+ void dilate(uint32_t padding)
+ {
BitImage tmp(m_width, m_height);
for (uint32_t p = 0; p < padding; p++) {
tmp.zeroOutMemory();
@@ -1342,21 +1436,15 @@ public:
if (!b) {
if (x > 0) {
b |= get(x - 1, y);
- if (y > 0)
- b |= get(x - 1, y - 1);
- if (y < m_height - 1)
- b |= get(x - 1, y + 1);
+ if (y > 0) b |= get(x - 1, y - 1);
+ if (y < m_height - 1) b |= get(x - 1, y + 1);
}
- if (y > 0)
- b |= get(x, y - 1);
- if (y < m_height - 1)
- b |= get(x, y + 1);
+ if (y > 0) b |= get(x, y - 1);
+ if (y < m_height - 1) b |= get(x, y + 1);
if (x < m_width - 1) {
b |= get(x + 1, y);
- if (y > 0)
- b |= get(x + 1, y - 1);
- if (y < m_height - 1)
- b |= get(x + 1, y + 1);
+ if (y > 0) b |= get(x + 1, y - 1);
+ if (y < m_height - 1) b |= get(x + 1, y + 1);
}
}
if (b)
@@ -1375,10 +1463,11 @@ private:
};
// From Fast-BVH
-class BVH {
+class BVH
+{
public:
- BVH(const Array<AABB> &objectAabbs, uint32_t leafSize = 4) :
- m_objectIds(MemTag::BVH), m_nodes(MemTag::BVH) {
+ BVH(const Array<AABB> &objectAabbs, uint32_t leafSize = 4) : m_objectIds(MemTag::BVH), m_nodes(MemTag::BVH)
+ {
m_objectAabbs = &objectAabbs;
if (m_objectAabbs->isEmpty())
return;
@@ -1398,7 +1487,7 @@ public:
Node node;
m_nodes.reserve(objectAabbs.size() * 2);
uint32_t nNodes = 0;
- while (stackptr > 0) {
+ while(stackptr > 0) {
// Pop the next item off of the stack
const BuildEntry &bnode = todo[--stackptr];
const uint32_t start = bnode.start;
@@ -1411,7 +1500,7 @@ public:
// Calculate the bounding box for this node
AABB bb(objectAabbs[m_objectIds[start]]);
AABB bc(objectAabbs[m_objectIds[start]].centroid());
- for (uint32_t p = start + 1; p < end; ++p) {
+ for(uint32_t p = start + 1; p < end; ++p) {
bb.expandToInclude(objectAabbs[m_objectIds[p]]);
bc.expandToInclude(objectAabbs[m_objectIds[p]].centroid());
}
@@ -1427,7 +1516,7 @@ public:
m_nodes[bnode.parent].rightOffset--;
// When this is the second touch, this is the right child.
// The right child sets up the offset for the flat tree.
- if (m_nodes[bnode.parent].rightOffset == kTouchedTwice)
+ if (m_nodes[bnode.parent].rightOffset == kTouchedTwice )
m_nodes[bnode.parent].rightOffset = nNodes - 1 - bnode.parent;
}
// If this is a leaf, no need to subdivide.
@@ -1462,20 +1551,21 @@ public:
}
}
- void query(const AABB &queryAabb, Array<uint32_t> &result) const {
+ void query(const AABB &queryAabb, Array<uint32_t> &result) const
+ {
result.clear();
// Working set
uint32_t todo[64];
int32_t stackptr = 0;
// "Push" on the root node to the working set
todo[stackptr] = 0;
- while (stackptr >= 0) {
+ while(stackptr >= 0) {
// Pop off the next node to work on.
const int ni = todo[stackptr--];
const Node &node = m_nodes[ni];
// Is leaf -> Intersect
if (node.rightOffset == 0) {
- for (uint32_t o = 0; o < node.nPrims; ++o) {
+ for(uint32_t o = 0; o < node.nPrims; ++o) {
const uint32_t obj = node.start + o;
if (queryAabb.intersect((*m_objectAabbs)[m_objectIds[obj]]))
result.push_back(m_objectIds[obj]);
@@ -1492,12 +1582,14 @@ public:
}
private:
- struct BuildEntry {
+ struct BuildEntry
+ {
uint32_t parent; // If non-zero then this is the index of the parent. (used in offsets)
uint32_t start, end; // The range of objects in the object list covered by this node.
};
- struct Node {
+ struct Node
+ {
AABB aabb;
uint32_t start, nPrims, rightOffset;
};
@@ -1507,8 +1599,10 @@ private:
Array<Node> m_nodes;
};
-struct Fit {
- static bool computeBasis(ConstArrayView<Vector3> points, Basis *basis) {
+struct Fit
+{
+ static bool computeBasis(ConstArrayView<Vector3> points, Basis *basis)
+ {
if (computeLeastSquaresNormal(points, &basis->normal)) {
basis->tangent = Basis::computeTangent(basis->normal);
basis->bitangent = Basis::computeBitangent(basis->normal, basis->tangent);
@@ -1522,7 +1616,8 @@ private:
// Fast, and accurate to within a few degrees.
// Returns None if the points do not span a plane.
// https://www.ilikebigbits.com/2015_03_04_plane_from_points.html
- static bool computeLeastSquaresNormal(ConstArrayView<Vector3> points, Vector3 *normal) {
+ static bool computeLeastSquaresNormal(ConstArrayView<Vector3> points, Vector3 *normal)
+ {
XA_DEBUG_ASSERT(points.length >= 3);
if (points.length == 3) {
*normal = normalize(cross(points[2] - points[0], points[1] - points[0]));
@@ -1587,7 +1682,7 @@ private:
// Pick path with best conditioning:
Vector3 dir(0.0f);
if (det_max == det_x)
- dir = Vector3(det_x, xz * yz - xy * zz, xy * yz - xz * yy);
+ dir = Vector3(det_x,xz * yz - xy * zz,xy * yz - xz * yy);
else if (det_max == det_y)
dir = Vector3(xz * yz - xy * zz, det_y, xy * xz - yz * xx);
else if (det_max == det_z)
@@ -1600,7 +1695,8 @@ private:
return isNormalized(*normal);
}
- static bool computeEigen(ConstArrayView<Vector3> points, Basis *basis) {
+ static bool computeEigen(ConstArrayView<Vector3> points, Basis *basis)
+ {
float matrix[6];
computeCovariance(points, matrix);
if (matrix[0] == 0 && matrix[3] == 0 && matrix[5] == 0)
@@ -1615,7 +1711,8 @@ private:
return true;
}
- static Vector3 computeCentroid(ConstArrayView<Vector3> points) {
+ static Vector3 computeCentroid(ConstArrayView<Vector3> points)
+ {
Vector3 centroid(0.0f);
for (uint32_t i = 0; i < points.length; i++)
centroid += points[i];
@@ -1623,7 +1720,8 @@ private:
return centroid;
}
- static Vector3 computeCovariance(ConstArrayView<Vector3> points, float *covariance) {
+ static Vector3 computeCovariance(ConstArrayView<Vector3> points, float * covariance)
+ {
// compute the centroid
Vector3 centroid = computeCentroid(points);
// compute covariance matrix
@@ -1645,7 +1743,8 @@ private:
// Tridiagonal solver from Charles Bloom.
// Householder transforms followed by QL decomposition.
// Seems to be based on the code from Numerical Recipes in C.
- static bool eigenSolveSymmetric3(const float matrix[6], float eigenValues[3], Vector3 eigenVectors[3]) {
+ static bool eigenSolveSymmetric3(const float matrix[6], float eigenValues[3], Vector3 eigenVectors[3])
+ {
XA_DEBUG_ASSERT(matrix != nullptr && eigenValues != nullptr && eigenVectors != nullptr);
float subd[3];
float diag[3];
@@ -1670,7 +1769,7 @@ private:
// eigenvectors are the columns; make them the rows :
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
- (&eigenVectors[j].x)[i] = (float)work[i][j];
+ (&eigenVectors[j].x)[i] = (float) work[i][j];
}
}
// shuffle to sort by singular value :
@@ -1692,7 +1791,8 @@ private:
}
private:
- static void EigenSolver3_Tridiagonal(float mat[3][3], float *diag, float *subd) {
+ static void EigenSolver3_Tridiagonal(float mat[3][3], float *diag, float *subd)
+ {
// Householder reduction T = Q^t M Q
// Input:
// mat, symmetric 3x3 matrix M
@@ -1744,7 +1844,8 @@ private:
}
}
- static bool EigenSolver3_QLAlgorithm(float mat[3][3], float *diag, float *subd) {
+ static bool EigenSolver3_QLAlgorithm(float mat[3][3], float *diag, float *subd)
+ {
// QL iteration with implicit shifting to reduce matrix from tridiagonal
// to diagonal
const int maxiter = 32;
@@ -1754,21 +1855,21 @@ private:
int m;
for (m = ell; m <= 1; m++) {
float dd = fabsf(diag[m]) + fabsf(diag[m + 1]);
- if (fabsf(subd[m]) + dd == dd)
+ if ( fabsf(subd[m]) + dd == dd )
break;
}
- if (m == ell)
+ if ( m == ell )
break;
float g = (diag[ell + 1] - diag[ell]) / (2 * subd[ell]);
float r = sqrtf(g * g + 1);
- if (g < 0)
+ if ( g < 0 )
g = diag[m] - diag[ell] + subd[ell] / (g - r);
else
g = diag[m] - diag[ell] + subd[ell] / (g + r);
float s = 1, c = 1, p = 0;
for (int i = m - 1; i >= ell; i--) {
float f = s * subd[i], b = c * subd[i];
- if (fabsf(f) >= fabsf(g)) {
+ if ( fabsf(f) >= fabsf(g) ) {
c = g / f;
r = sqrtf(c * c + 1);
subd[i + 1] = f * r;
@@ -1794,7 +1895,7 @@ private:
subd[ell] = g;
subd[m] = 0;
}
- if (iter == maxiter)
+ if ( iter == maxiter )
// should not get here under normal circumstances
return false;
}
@@ -1802,48 +1903,56 @@ private:
}
};
-static uint32_t sdbmHash(const void *data_in, uint32_t size, uint32_t h = 5381) {
- const uint8_t *data = (const uint8_t *)data_in;
+static uint32_t sdbmHash(const void *data_in, uint32_t size, uint32_t h = 5381)
+{
+ const uint8_t *data = (const uint8_t *) data_in;
uint32_t i = 0;
while (i < size) {
- h = (h << 16) + (h << 6) - h + (uint32_t)data[i++];
+ h = (h << 16) + (h << 6) - h + (uint32_t ) data[i++];
}
return h;
}
template <typename T>
-static uint32_t hash(const T &t, uint32_t h = 5381) {
+static uint32_t hash(const T &t, uint32_t h = 5381)
+{
return sdbmHash(&t, sizeof(T), h);
}
template <typename Key>
-struct Hash {
+struct Hash
+{
uint32_t operator()(const Key &k) const { return hash(k); }
};
template <typename Key>
-struct PassthroughHash {
+struct PassthroughHash
+{
uint32_t operator()(const Key &k) const { return (uint32_t)k; }
};
template <typename Key>
-struct Equal {
+struct Equal
+{
bool operator()(const Key &k0, const Key &k1) const { return k0 == k1; }
};
-template <typename Key, typename H = Hash<Key>, typename E = Equal<Key>>
-class HashMap {
+template<typename Key, typename H = Hash<Key>, typename E = Equal<Key> >
+class HashMap
+{
public:
- HashMap(int memTag, uint32_t size) :
- m_memTag(memTag), m_size(size), m_numSlots(0), m_slots(nullptr), m_keys(memTag), m_next(memTag) {
+ HashMap(int memTag, uint32_t size) : m_memTag(memTag), m_size(size), m_numSlots(0), m_slots(nullptr), m_keys(memTag), m_next(memTag)
+ {
}
- ~HashMap() {
+ ~HashMap()
+ {
if (m_slots)
XA_FREE(m_slots);
}
- void destroy() {
+ void destroy()
+ {
if (m_slots) {
XA_FREE(m_slots);
m_slots = nullptr;
@@ -1852,7 +1961,8 @@ public:
m_next.destroy();
}
- uint32_t add(const Key &key) {
+ uint32_t add(const Key &key)
+ {
if (!m_slots)
alloc();
const uint32_t hash = computeHash(key);
@@ -1862,18 +1972,21 @@ public:
return m_keys.size() - 1;
}
- uint32_t get(const Key &key) const {
+ uint32_t get(const Key &key) const
+ {
if (!m_slots)
return UINT32_MAX;
return find(key, m_slots[computeHash(key)]);
}
- uint32_t getNext(const Key &key, uint32_t current) const {
+ uint32_t getNext(const Key &key, uint32_t current) const
+ {
return find(key, m_next[current]);
}
private:
- void alloc() {
+ void alloc()
+ {
XA_DEBUG_ASSERT(m_size > 0);
m_numSlots = nextPowerOfTwo(m_size);
auto minNumSlots = uint32_t(m_size * 1.3);
@@ -1886,12 +1999,14 @@ private:
m_next.reserve(m_size);
}
- uint32_t computeHash(const Key &key) const {
+ uint32_t computeHash(const Key &key) const
+ {
H hash;
return hash(key) & (m_numSlots - 1);
}
- uint32_t find(const Key &key, uint32_t current) const {
+ uint32_t find(const Key &key, uint32_t current) const
+ {
E equal;
while (current != UINT32_MAX) {
if (equal(m_keys[current], key))
@@ -1909,8 +2024,9 @@ private:
Array<uint32_t> m_next;
};
-template <typename T>
-static void insertionSort(T *data, uint32_t length) {
+template<typename T>
+static void insertionSort(T *data, uint32_t length)
+{
for (int32_t i = 1; i < (int32_t)length; i++) {
T x = data[i];
int32_t j = i - 1;
@@ -1922,18 +2038,21 @@ static void insertionSort(T *data, uint32_t length) {
}
}
-class KISSRng {
+class KISSRng
+{
public:
KISSRng() { reset(); }
- void reset() {
+ void reset()
+ {
x = 123456789;
y = 362436000;
z = 521288629;
c = 7654321;
}
- uint32_t getRange(uint32_t range) {
+ uint32_t getRange(uint32_t range)
+ {
if (range == 0)
return 0;
x = 69069 * x + 12345;
@@ -1952,9 +2071,11 @@ private:
// Based on Pierre Terdiman's and Michael Herf's source code.
// http://www.codercorner.com/RadixSortRevisited.htm
// http://www.stereopsis.com/radix.html
-class RadixSort {
+class RadixSort
+{
public:
- void sort(ConstArrayView<float> input) {
+ void sort(ConstArrayView<float> input)
+ {
if (input.length == 0) {
m_buffer1.clear();
m_buffer2.clear();
@@ -1983,7 +2104,8 @@ public:
}
// Access to results. m_ranks is a list of indices in sorted order, i.e. in the order you may further process your data
- const uint32_t *ranks() const {
+ const uint32_t *ranks() const
+ {
XA_DEBUG_ASSERT(m_validRanks);
return m_ranks;
}
@@ -1993,17 +2115,20 @@ private:
Array<uint32_t> m_buffer1, m_buffer2;
bool m_validRanks = false;
- void floatFlip(uint32_t &f) {
+ void floatFlip(uint32_t &f)
+ {
int32_t mask = (int32_t(f) >> 31) | 0x80000000; // Warren Hunt, Manchor Ko.
f ^= mask;
}
- void ifloatFlip(uint32_t &f) {
+ void ifloatFlip(uint32_t &f)
+ {
uint32_t mask = ((f >> 31) - 1) | 0x80000000; // Michael Herf.
f ^= mask;
}
- void createHistograms(ConstArrayView<uint32_t> input, uint32_t *histogram) {
+ void createHistograms(ConstArrayView<uint32_t> input, uint32_t *histogram)
+ {
const uint32_t bucketCount = sizeof(uint32_t);
// Init bucket pointers.
uint32_t *h[bucketCount];
@@ -2014,14 +2139,15 @@ private:
memset(histogram, 0, 256 * bucketCount * sizeof(uint32_t));
// @@ Add support for signed integers.
// Build histograms.
- const uint8_t *p = (const uint8_t *)input.data; // @@ Does this break aliasing rules?
+ const uint8_t *p = (const uint8_t *)input.data; // @@ Does this break aliasing rules?
const uint8_t *pe = p + input.length * sizeof(uint32_t);
while (p != pe) {
h[0][*p++]++, h[1][*p++]++, h[2][*p++]++, h[3][*p++]++;
}
}
- void insertionSort(ConstArrayView<float> input) {
+ void insertionSort(ConstArrayView<float> input)
+ {
if (!m_validRanks) {
m_ranks[0] = 0;
for (uint32_t i = 1; i != input.length; ++i) {
@@ -2051,7 +2177,8 @@ private:
}
}
- void radixSort(ConstArrayView<uint32_t> input) {
+ void radixSort(ConstArrayView<uint32_t> input)
+ {
const uint32_t P = sizeof(uint32_t); // pass count
// Allocate histograms & offsets on the stack
uint32_t histogram[256 * P];
@@ -2069,8 +2196,7 @@ private:
}
// Create offsets
link[0] = m_ranks2;
- for (uint32_t i = 1; i < 256; i++)
- link[i] = link[i - 1] + h[i - 1];
+ for (uint32_t i = 1; i < 256; i++) link[i] = link[i - 1] + h[i - 1];
// Perform Radix Sort
if (!m_validRanks) {
for (uint32_t i = 0; i < input.length; i++) {
@@ -2096,21 +2222,25 @@ private:
};
// Wrapping this in a class allows temporary arrays to be re-used.
-class BoundingBox2D {
+class BoundingBox2D
+{
public:
Vector2 majorAxis, minorAxis, minCorner, maxCorner;
- void clear() {
+ void clear()
+ {
m_boundaryVertices.clear();
}
- void appendBoundaryVertex(Vector2 v) {
+ void appendBoundaryVertex(Vector2 v)
+ {
m_boundaryVertices.push_back(v);
}
// This should compute convex hull and use rotating calipers to find the best box. Currently it uses a brute force method.
// If vertices are empty, the boundary vertices are used.
- void compute(ConstArrayView<Vector2> vertices = ConstArrayView<Vector2>()) {
+ void compute(ConstArrayView<Vector2> vertices = ConstArrayView<Vector2>())
+ {
XA_DEBUG_ASSERT(!m_boundaryVertices.isEmpty());
if (vertices.length == 0)
vertices = m_boundaryVertices;
@@ -2157,7 +2287,8 @@ public:
private:
// Compute the convex hull using Graham Scan.
- void convexHull(ConstArrayView<Vector2> input, Array<Vector2> &output, float epsilon) {
+ void convexHull(ConstArrayView<Vector2> input, Array<Vector2> &output, float epsilon)
+ {
m_coords.resize(input.length);
for (uint32_t i = 0; i < input.length; i++)
m_coords[i] = input[i].x;
@@ -2186,7 +2317,7 @@ private:
XA_DEBUG_ASSERT(m_top.size() >= 2);
output.push_back(m_top[0]);
output.push_back(m_top[1]);
- for (uint32_t i = 2; i < m_top.size();) {
+ for (uint32_t i = 2; i < m_top.size(); ) {
Vector2 a = output[output.size() - 2];
Vector2 b = output[output.size() - 1];
Vector2 c = m_top[i];
@@ -2202,7 +2333,7 @@ private:
XA_DEBUG_ASSERT(m_bottom.size() >= 2);
output.push_back(m_bottom[1]);
// Filter bottom list.
- for (uint32_t i = 2; i < m_bottom.size();) {
+ for (uint32_t i = 2; i < m_bottom.size(); ) {
Vector2 a = output[output.size() - 2];
Vector2 b = output[output.size() - 1];
Vector2 c = m_bottom[i];
@@ -2225,45 +2356,45 @@ private:
RadixSort m_radix;
};
-struct EdgeKey {
- EdgeKey(const EdgeKey &k) :
- v0(k.v0), v1(k.v1) {}
- EdgeKey(uint32_t _v0, uint32_t _v1) :
- v0(_v0), v1(_v1) {}
+struct EdgeKey
+{
+ EdgeKey(const EdgeKey &k) : v0(k.v0), v1(k.v1) {}
+ EdgeKey(uint32_t _v0, uint32_t _v1) : v0(_v0), v1(_v1) {}
bool operator==(const EdgeKey &k) const { return v0 == k.v0 && v1 == k.v1; }
uint32_t v0;
uint32_t v1;
};
-struct EdgeHash {
+struct EdgeHash
+{
uint32_t operator()(const EdgeKey &k) const { return k.v0 * 32768u + k.v1; }
};
-static uint32_t meshEdgeFace(uint32_t edge) {
- return edge / 3;
-}
-static uint32_t meshEdgeIndex0(uint32_t edge) {
- return edge;
-}
+static uint32_t meshEdgeFace(uint32_t edge) { return edge / 3; }
+static uint32_t meshEdgeIndex0(uint32_t edge) { return edge; }
-static uint32_t meshEdgeIndex1(uint32_t edge) {
+static uint32_t meshEdgeIndex1(uint32_t edge)
+{
const uint32_t faceFirstEdge = edge / 3 * 3;
return faceFirstEdge + (edge - faceFirstEdge + 1) % 3;
}
-struct MeshFlags {
- enum {
- HasIgnoredFaces = 1 << 0,
- HasNormals = 1 << 1,
- HasMaterials = 1 << 2
+struct MeshFlags
+{
+ enum
+ {
+ HasIgnoredFaces = 1<<0,
+ HasNormals = 1<<1,
+ HasMaterials = 1<<2
};
};
-class Mesh {
+class Mesh
+{
public:
- Mesh(float epsilon, uint32_t approxVertexCount, uint32_t approxFaceCount, uint32_t flags = 0, uint32_t id = UINT32_MAX) :
- m_epsilon(epsilon), m_flags(flags), m_id(id), m_faceIgnore(MemTag::Mesh), m_faceMaterials(MemTag::Mesh), m_indices(MemTag::MeshIndices), m_positions(MemTag::MeshPositions), m_normals(MemTag::MeshNormals), m_texcoords(MemTag::MeshTexcoords), m_nextColocalVertex(MemTag::MeshColocals), m_firstColocalVertex(MemTag::MeshColocals), m_boundaryEdges(MemTag::MeshBoundaries), m_oppositeEdges(MemTag::MeshBoundaries), m_edgeMap(MemTag::MeshEdgeMap, approxFaceCount * 3) {
+ Mesh(float epsilon, uint32_t approxVertexCount, uint32_t approxFaceCount, uint32_t flags = 0, uint32_t id = UINT32_MAX) : m_epsilon(epsilon), m_flags(flags), m_id(id), m_faceIgnore(MemTag::Mesh), m_faceMaterials(MemTag::Mesh), m_indices(MemTag::MeshIndices), m_positions(MemTag::MeshPositions), m_normals(MemTag::MeshNormals), m_texcoords(MemTag::MeshTexcoords), m_nextColocalVertex(MemTag::MeshColocals), m_firstColocalVertex(MemTag::MeshColocals), m_boundaryEdges(MemTag::MeshBoundaries), m_oppositeEdges(MemTag::MeshBoundaries), m_edgeMap(MemTag::MeshEdgeMap, approxFaceCount * 3)
+ {
m_indices.reserve(approxFaceCount * 3);
m_positions.reserve(approxVertexCount);
m_texcoords.reserve(approxVertexCount);
@@ -2278,7 +2409,8 @@ public:
uint32_t flags() const { return m_flags; }
uint32_t id() const { return m_id; }
- void addVertex(const Vector3 &pos, const Vector3 &normal = Vector3(0.0f), const Vector2 &texcoord = Vector2(0.0f)) {
+ void addVertex(const Vector3 &pos, const Vector3 &normal = Vector3(0.0f), const Vector2 &texcoord = Vector2(0.0f))
+ {
XA_DEBUG_ASSERT(isFinite(pos));
m_positions.push_back(pos);
if (m_flags & MeshFlags::HasNormals)
@@ -2286,7 +2418,8 @@ public:
m_texcoords.push_back(texcoord);
}
- void addFace(const uint32_t *indices, bool ignore = false, uint32_t material = UINT32_MAX) {
+ void addFace(const uint32_t *indices, bool ignore = false, uint32_t material = UINT32_MAX)
+ {
if (m_flags & MeshFlags::HasIgnoredFaces)
m_faceIgnore.push_back(ignore);
if (m_flags & MeshFlags::HasMaterials)
@@ -2301,7 +2434,8 @@ public:
}
}
- void createColocalsBVH() {
+ void createColocalsBVH()
+ {
const uint32_t vertexCount = m_positions.size();
Array<AABB> aabbs(MemTag::BVH);
aabbs.resize(vertexCount);
@@ -2342,7 +2476,8 @@ public:
}
}
- void createColocalsHash() {
+ void createColocalsHash()
+ {
const uint32_t vertexCount = m_positions.size();
HashMap<Vector3> positionToVertexMap(MemTag::Default, vertexCount);
for (uint32_t i = 0; i < vertexCount; i++)
@@ -2380,14 +2515,16 @@ public:
}
}
- void createColocals() {
+ void createColocals()
+ {
if (m_epsilon <= FLT_EPSILON)
createColocalsHash();
else
createColocalsBVH();
}
- void createBoundaries() {
+ void createBoundaries()
+ {
const uint32_t edgeCount = m_indices.size();
const uint32_t vertexCount = m_positions.size();
m_oppositeEdges.resize(edgeCount);
@@ -2418,7 +2555,8 @@ public:
}
/// Find edge, test all colocals.
- uint32_t findEdge(uint32_t vertex0, uint32_t vertex1) const {
+ uint32_t findEdge(uint32_t vertex0, uint32_t vertex1) const
+ {
// Try to find exact vertex match first.
{
EdgeKey key(vertex0, vertex1);
@@ -2459,12 +2597,14 @@ public:
// Edge map can be destroyed when no longer used to reduce memory usage. It's used by:
// * Mesh::createBoundaries()
// * Mesh::edgeMap() (used by MeshFaceGroups)
- void destroyEdgeMap() {
+ void destroyEdgeMap()
+ {
m_edgeMap.destroy();
}
#if XA_DEBUG_EXPORT_OBJ
- void writeObjVertices(FILE *file) const {
+ void writeObjVertices(FILE *file) const
+ {
for (uint32_t i = 0; i < m_positions.size(); i++)
fprintf(file, "v %g %g %g\n", m_positions[i].x, m_positions[i].y, m_positions[i].z);
if (m_flags & MeshFlags::HasNormals) {
@@ -2475,7 +2615,8 @@ public:
fprintf(file, "vt %g %g\n", m_texcoords[i].x, m_texcoords[i].y);
}
- void writeObjFace(FILE *file, uint32_t face, uint32_t offset = 0) const {
+ void writeObjFace(FILE *file, uint32_t face, uint32_t offset = 0) const
+ {
fprintf(file, "f ");
for (uint32_t j = 0; j < 3; j++) {
const uint32_t index = m_indices[face * 3 + j] + 1 + offset; // 1-indexed
@@ -2483,7 +2624,8 @@ public:
}
}
- void writeObjBoundaryEges(FILE *file) const {
+ void writeObjBoundaryEges(FILE *file) const
+ {
if (m_oppositeEdges.isEmpty())
return; // Boundaries haven't been created.
fprintf(file, "o boundary_edges\n");
@@ -2494,7 +2636,8 @@ public:
}
}
- void writeObjFile(const char *filename) const {
+ void writeObjFile(const char *filename) const
+ {
FILE *file;
XA_FOPEN(file, filename, "w");
if (!file)
@@ -2509,7 +2652,8 @@ public:
}
#endif
- float computeSurfaceArea() const {
+ float computeSurfaceArea() const
+ {
float area = 0;
for (uint32_t f = 0; f < faceCount(); f++)
area += computeFaceArea(f);
@@ -2518,21 +2662,24 @@ public:
}
// Returned value is always positive, even if some triangles are flipped.
- float computeParametricArea() const {
+ float computeParametricArea() const
+ {
float area = 0;
for (uint32_t f = 0; f < faceCount(); f++)
area += fabsf(computeFaceParametricArea(f)); // May be negative, depends on texcoord winding.
return area;
}
- float computeFaceArea(uint32_t face) const {
+ float computeFaceArea(uint32_t face) const
+ {
const Vector3 &p0 = m_positions[m_indices[face * 3 + 0]];
const Vector3 &p1 = m_positions[m_indices[face * 3 + 1]];
const Vector3 &p2 = m_positions[m_indices[face * 3 + 2]];
return length(cross(p1 - p0, p2 - p0)) * 0.5f;
}
- Vector3 computeFaceCentroid(uint32_t face) const {
+ Vector3 computeFaceCentroid(uint32_t face) const
+ {
Vector3 sum(0.0f);
for (uint32_t i = 0; i < 3; i++)
sum += m_positions[m_indices[face * 3 + i]];
@@ -2541,7 +2688,8 @@ public:
// Average of the edge midpoints weighted by the edge length.
// I want a point inside the triangle, but closer to the cirumcenter.
- Vector3 computeFaceCenter(uint32_t face) const {
+ Vector3 computeFaceCenter(uint32_t face) const
+ {
const Vector3 &p0 = m_positions[m_indices[face * 3 + 0]];
const Vector3 &p1 = m_positions[m_indices[face * 3 + 1]];
const Vector3 &p2 = m_positions[m_indices[face * 3 + 2]];
@@ -2554,7 +2702,8 @@ public:
return m0 + m1 + m2;
}
- Vector3 computeFaceNormal(uint32_t face) const {
+ Vector3 computeFaceNormal(uint32_t face) const
+ {
const Vector3 &p0 = m_positions[m_indices[face * 3 + 0]];
const Vector3 &p1 = m_positions[m_indices[face * 3 + 1]];
const Vector3 &p2 = m_positions[m_indices[face * 3 + 2]];
@@ -2564,7 +2713,8 @@ public:
return normalizeSafe(normalAreaScaled, Vector3(0, 0, 1));
}
- float computeFaceParametricArea(uint32_t face) const {
+ float computeFaceParametricArea(uint32_t face) const
+ {
const Vector2 &t0 = m_texcoords[m_indices[face * 3 + 0]];
const Vector2 &t1 = m_texcoords[m_indices[face * 3 + 1]];
const Vector2 &t2 = m_texcoords[m_indices[face * 3 + 2]];
@@ -2572,7 +2722,8 @@ public:
}
// @@ This is not exactly accurate, we should compare the texture coordinates...
- bool isSeam(uint32_t edge) const {
+ bool isSeam(uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_oppositeEdges[edge];
if (oppositeEdge == UINT32_MAX)
return false; // boundary edge
@@ -2583,7 +2734,8 @@ public:
return m_indices[e0] != m_indices[oe1] || m_indices[e1] != m_indices[oe0];
}
- bool isTextureSeam(uint32_t edge) const {
+ bool isTextureSeam(uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_oppositeEdges[edge];
if (oppositeEdge == UINT32_MAX)
return false; // boundary edge
@@ -2594,7 +2746,8 @@ public:
return m_texcoords[m_indices[e0]] != m_texcoords[m_indices[oe1]] || m_texcoords[m_indices[e1]] != m_texcoords[m_indices[oe0]];
}
- uint32_t firstColocalVertex(uint32_t vertex) const {
+ uint32_t firstColocalVertex(uint32_t vertex) const
+ {
XA_DEBUG_ASSERT(m_firstColocalVertex.size() == m_positions.size());
return m_firstColocalVertex[vertex];
}
@@ -2609,10 +2762,7 @@ public:
XA_INLINE uint32_t vertexAt(uint32_t i) const { return m_indices[i]; }
XA_INLINE const Vector3 &position(uint32_t vertex) const { return m_positions[vertex]; }
XA_INLINE ConstArrayView<Vector3> positions() const { return m_positions; }
- XA_INLINE const Vector3 &normal(uint32_t vertex) const {
- XA_DEBUG_ASSERT(m_flags & MeshFlags::HasNormals);
- return m_normals[vertex];
- }
+ XA_INLINE const Vector3 &normal(uint32_t vertex) const { XA_DEBUG_ASSERT(m_flags & MeshFlags::HasNormals); return m_normals[vertex]; }
XA_INLINE const Vector2 &texcoord(uint32_t vertex) const { return m_texcoords[vertex]; }
XA_INLINE Vector2 &texcoord(uint32_t vertex) { return m_texcoords[vertex]; }
XA_INLINE const ConstArrayView<Vector2> texcoords() const { return m_texcoords; }
@@ -2625,6 +2775,7 @@ public:
XA_INLINE const HashMap<EdgeKey, EdgeHash> &edgeMap() const { return m_edgeMap; }
private:
+
float m_epsilon;
uint32_t m_flags;
uint32_t m_id;
@@ -2647,21 +2798,24 @@ private:
HashMap<EdgeKey, EdgeHash> m_edgeMap;
public:
- class FaceEdgeIterator {
+ class FaceEdgeIterator
+ {
public:
- FaceEdgeIterator(const Mesh *mesh, uint32_t face) :
- m_mesh(mesh), m_face(face), m_relativeEdge(0) {
+ FaceEdgeIterator (const Mesh *mesh, uint32_t face) : m_mesh(mesh), m_face(face), m_relativeEdge(0)
+ {
m_edge = m_face * 3;
}
- void advance() {
+ void advance()
+ {
if (m_relativeEdge < 3) {
m_edge++;
m_relativeEdge++;
}
}
- bool isDone() const {
+ bool isDone() const
+ {
return m_relativeEdge == 3;
}
@@ -2673,7 +2827,8 @@ public:
uint32_t face() const { return m_face; }
uint32_t oppositeEdge() const { return m_mesh->m_oppositeEdges[m_edge]; }
- uint32_t oppositeFace() const {
+ uint32_t oppositeFace() const
+ {
const uint32_t oedge = m_mesh->m_oppositeEdges[m_edge];
if (oedge == UINT32_MAX)
return UINT32_MAX;
@@ -2697,18 +2852,19 @@ public:
};
};
-struct MeshFaceGroups {
+struct MeshFaceGroups
+{
typedef uint32_t Handle;
static constexpr Handle kInvalid = UINT32_MAX;
- MeshFaceGroups(const Mesh *mesh) :
- m_mesh(mesh), m_groups(MemTag::Mesh), m_firstFace(MemTag::Mesh), m_nextFace(MemTag::Mesh), m_faceCount(MemTag::Mesh) {}
+ MeshFaceGroups(const Mesh *mesh) : m_mesh(mesh), m_groups(MemTag::Mesh), m_firstFace(MemTag::Mesh), m_nextFace(MemTag::Mesh), m_faceCount(MemTag::Mesh) {}
XA_INLINE Handle groupAt(uint32_t face) const { return m_groups[face]; }
XA_INLINE uint32_t groupCount() const { return m_faceCount.size(); }
XA_INLINE uint32_t nextFace(uint32_t face) const { return m_nextFace[face]; }
XA_INLINE uint32_t faceCount(uint32_t group) const { return m_faceCount[group]; }
- void compute() {
+ void compute()
+ {
m_groups.resize(m_mesh->faceCount());
m_groups.fillBytes(0xff); // Set all faces to kInvalid
uint32_t firstUnassignedFace = 0;
@@ -2767,23 +2923,27 @@ struct MeshFaceGroups {
}
}
- class Iterator {
+ class Iterator
+ {
public:
- Iterator(const MeshFaceGroups *meshFaceGroups, Handle group) :
- m_meshFaceGroups(meshFaceGroups) {
+ Iterator(const MeshFaceGroups *meshFaceGroups, Handle group) : m_meshFaceGroups(meshFaceGroups)
+ {
XA_DEBUG_ASSERT(group != kInvalid);
m_current = m_meshFaceGroups->m_firstFace[group];
}
- void advance() {
+ void advance()
+ {
m_current = m_meshFaceGroups->m_nextFace[m_current];
}
- bool isDone() const {
+ bool isDone() const
+ {
return m_current == UINT32_MAX;
}
- uint32_t face() const {
+ uint32_t face() const
+ {
return m_current;
}
@@ -2803,7 +2963,8 @@ private:
constexpr MeshFaceGroups::Handle MeshFaceGroups::kInvalid;
#if XA_CHECK_T_JUNCTIONS
-static bool lineIntersectsPoint(const Vector3 &point, const Vector3 &lineStart, const Vector3 &lineEnd, float *t, float epsilon) {
+static bool lineIntersectsPoint(const Vector3 &point, const Vector3 &lineStart, const Vector3 &lineEnd, float *t, float epsilon)
+{
float tt;
if (!t)
t = &tt;
@@ -2821,7 +2982,8 @@ static bool lineIntersectsPoint(const Vector3 &point, const Vector3 &lineStart,
}
// Returns the number of T-junctions found.
-static int meshCheckTJunctions(const Mesh &inputMesh) {
+static int meshCheckTJunctions(const Mesh &inputMesh)
+{
int count = 0;
const uint32_t vertexCount = inputMesh.vertexCount();
const uint32_t edgeCount = inputMesh.edgeCount();
@@ -2845,10 +3007,12 @@ static int meshCheckTJunctions(const Mesh &inputMesh) {
#endif
// References invalid faces and vertices in a mesh.
-struct InvalidMeshGeometry {
+struct InvalidMeshGeometry
+{
// If meshFaceGroups is not null, invalid faces have the face group MeshFaceGroups::kInvalid.
// If meshFaceGroups is null, invalid faces are Mesh::isFaceIgnored.
- void extract(const Mesh *mesh, const MeshFaceGroups *meshFaceGroups) {
+ void extract(const Mesh *mesh, const MeshFaceGroups *meshFaceGroups)
+ {
// Copy invalid faces.
m_faces.clear();
const uint32_t meshFaceCount = mesh->faceCount();
@@ -2886,28 +3050,32 @@ private:
Array<uint32_t> m_vertexToSourceVertexMap; // Map face vertices to vertices of the source mesh.
};
-struct Progress {
- Progress(ProgressCategory category, ProgressFunc func, void *userData, uint32_t maxValue) :
- cancel(false), m_category(category), m_func(func), m_userData(userData), m_value(0), m_maxValue(maxValue), m_percent(0) {
+struct Progress
+{
+ Progress(ProgressCategory category, ProgressFunc func, void *userData, uint32_t maxValue) : cancel(false), m_category(category), m_func(func), m_userData(userData), m_value(0), m_maxValue(maxValue), m_percent(0)
+ {
if (m_func) {
if (!m_func(category, 0, userData))
cancel = true;
}
}
- ~Progress() {
+ ~Progress()
+ {
if (m_func) {
if (!m_func(m_category, 100, m_userData))
cancel = true;
}
}
- void increment(uint32_t value) {
+ void increment(uint32_t value)
+ {
m_value += value;
update();
}
- void setMaxValue(uint32_t maxValue) {
+ void setMaxValue(uint32_t maxValue)
+ {
m_maxValue = maxValue;
update();
}
@@ -2915,15 +3083,15 @@ struct Progress {
std::atomic<bool> cancel;
private:
- void update() {
+ void update()
+ {
if (!m_func)
return;
const uint32_t newPercent = uint32_t(ceilf(m_value.load() / (float)m_maxValue.load() * 100.0f));
if (newPercent != m_percent) {
// Atomic max.
uint32_t oldPercent = m_percent;
- while (oldPercent < newPercent && !m_percent.compare_exchange_weak(oldPercent, newPercent)) {
- }
+ while (oldPercent < newPercent && !m_percent.compare_exchange_weak(oldPercent, newPercent)) {}
if (!m_func(m_category, m_percent, m_userData))
cancel = true;
}
@@ -2935,31 +3103,32 @@ private:
std::atomic<uint32_t> m_value, m_maxValue, m_percent;
};
-struct Spinlock {
- void lock() {
- while (m_lock.test_and_set(std::memory_order_acquire)) {
- }
- }
+struct Spinlock
+{
+ void lock() { while(m_lock.test_and_set(std::memory_order_acquire)) {} }
void unlock() { m_lock.clear(std::memory_order_release); }
private:
std::atomic_flag m_lock = ATOMIC_FLAG_INIT;
};
-struct TaskGroupHandle {
+struct TaskGroupHandle
+{
uint32_t value = UINT32_MAX;
};
-struct Task {
+struct Task
+{
void (*func)(void *groupUserData, void *taskUserData);
void *userData; // Passed to func as taskUserData.
};
#if XA_MULTITHREADED
-class TaskScheduler {
+class TaskScheduler
+{
public:
- TaskScheduler() :
- m_shutdown(false) {
+ TaskScheduler() : m_shutdown(false)
+ {
m_threadIndex = 0;
// Max with current task scheduler usage is 1 per thread + 1 deep nesting, but allow for some slop.
m_maxGroups = std::thread::hardware_concurrency() * 4;
@@ -2978,7 +3147,8 @@ public:
}
}
- ~TaskScheduler() {
+ ~TaskScheduler()
+ {
m_shutdown = true;
for (uint32_t i = 0; i < m_workers.size(); i++) {
Worker &worker = m_workers[i];
@@ -2996,12 +3166,14 @@ public:
XA_FREE(m_groups);
}
- uint32_t threadCount() const {
+ uint32_t threadCount() const
+ {
return max(1u, std::thread::hardware_concurrency()); // Including the main thread.
}
// userData is passed to Task::func as groupUserData.
- TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0) {
+ TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0)
+ {
// Claim the first free group.
for (uint32_t i = 0; i < m_maxGroups; i++) {
TaskGroup &group = m_groups[i];
@@ -3025,7 +3197,8 @@ public:
return handle;
}
- void run(TaskGroupHandle handle, const Task &task) {
+ void run(TaskGroupHandle handle, const Task &task)
+ {
XA_DEBUG_ASSERT(handle.value != UINT32_MAX);
TaskGroup &group = m_groups[handle.value];
group.queueLock.lock();
@@ -3039,7 +3212,8 @@ public:
}
}
- void wait(TaskGroupHandle *handle) {
+ void wait(TaskGroupHandle *handle)
+ {
if (handle->value == UINT32_MAX) {
XA_DEBUG_ASSERT(false);
return;
@@ -3067,7 +3241,8 @@ public:
static uint32_t currentThreadIndex() { return m_threadIndex; }
private:
- struct TaskGroup {
+ struct TaskGroup
+ {
std::atomic<bool> free;
Array<Task> queue; // Items are never removed. queueHead is incremented to pop items.
uint32_t queueHead = 0;
@@ -3076,7 +3251,8 @@ private:
void *userData;
};
- struct Worker {
+ struct Worker
+ {
std::thread *thread = nullptr;
std::mutex mutex;
std::condition_variable cv;
@@ -3089,11 +3265,12 @@ private:
uint32_t m_maxGroups;
static thread_local uint32_t m_threadIndex;
- static void workerThread(TaskScheduler *scheduler, Worker *worker, uint32_t threadIndex) {
+ static void workerThread(TaskScheduler *scheduler, Worker *worker, uint32_t threadIndex)
+ {
m_threadIndex = threadIndex;
std::unique_lock<std::mutex> lock(worker->mutex);
for (;;) {
- worker->cv.wait(lock, [=] { return worker->wakeup.load(); });
+ worker->cv.wait(lock, [=]{ return worker->wakeup.load(); });
worker->wakeup = false;
for (;;) {
if (scheduler->m_shutdown)
@@ -3124,18 +3301,22 @@ private:
thread_local uint32_t TaskScheduler::m_threadIndex;
#else
-class TaskScheduler {
+class TaskScheduler
+{
public:
- ~TaskScheduler() {
+ ~TaskScheduler()
+ {
for (uint32_t i = 0; i < m_groups.size(); i++)
destroyGroup({ i });
}
- uint32_t threadCount() const {
+ uint32_t threadCount() const
+ {
return 1;
}
- TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0) {
+ TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0)
+ {
TaskGroup *group = XA_NEW(MemTag::Default, TaskGroup);
group->queue.reserve(reserveSize);
group->userData = userData;
@@ -3145,11 +3326,13 @@ public:
return handle;
}
- void run(TaskGroupHandle handle, Task task) {
+ void run(TaskGroupHandle handle, Task task)
+ {
m_groups[handle.value]->queue.push_back(task);
}
- void wait(TaskGroupHandle *handle) {
+ void wait(TaskGroupHandle *handle)
+ {
if (handle->value == UINT32_MAX) {
XA_DEBUG_ASSERT(false);
return;
@@ -3165,7 +3348,8 @@ public:
static uint32_t currentThreadIndex() { return 0; }
private:
- void destroyGroup(TaskGroupHandle handle) {
+ void destroyGroup(TaskGroupHandle handle)
+ {
TaskGroup *group = m_groups[handle.value];
if (group) {
group->~TaskGroup();
@@ -3174,7 +3358,8 @@ private:
}
}
- struct TaskGroup {
+ struct TaskGroup
+ {
Array<Task> queue;
void *userData;
};
@@ -3188,7 +3373,8 @@ const uint8_t TGA_TYPE_RGB = 2;
const uint8_t TGA_ORIGIN_UPPER = 0x20;
#pragma pack(push, 1)
-struct TgaHeader {
+struct TgaHeader
+{
uint8_t id_length;
uint8_t colormap_type;
uint8_t image_type;
@@ -3205,7 +3391,8 @@ struct TgaHeader {
};
#pragma pack(pop)
-static void WriteTga(const char *filename, const uint8_t *data, uint32_t width, uint32_t height) {
+static void WriteTga(const char *filename, const uint8_t *data, uint32_t width, uint32_t height)
+{
XA_DEBUG_ASSERT(sizeof(TgaHeader) == TgaHeader::Size);
FILE *f;
XA_FOPEN(f, filename, "wb");
@@ -3230,10 +3417,12 @@ static void WriteTga(const char *filename, const uint8_t *data, uint32_t width,
}
#endif
-template <typename T>
-class ThreadLocal {
+template<typename T>
+class ThreadLocal
+{
public:
- ThreadLocal() {
+ ThreadLocal()
+ {
#if XA_MULTITHREADED
const uint32_t n = std::thread::hardware_concurrency();
#else
@@ -3244,7 +3433,8 @@ public:
new (&m_array[i]) T;
}
- ~ThreadLocal() {
+ ~ThreadLocal()
+ {
#if XA_MULTITHREADED
const uint32_t n = std::thread::hardware_concurrency();
#else
@@ -3255,7 +3445,8 @@ public:
XA_FREE(m_array);
}
- T &get() const {
+ T &get() const
+ {
return m_array[TaskScheduler::currentThreadIndex()];
}
@@ -3264,10 +3455,12 @@ private:
};
// Implemented as a struct so the temporary arrays can be reused.
-struct Triangulator {
+struct Triangulator
+{
// This is doing a simple ear-clipping algorithm that skips invalid triangles. Ideally, we should
// also sort the ears by angle, start with the ones that have the smallest angle and proceed in order.
- void triangulatePolygon(ConstArrayView<Vector3> vertices, ConstArrayView<uint32_t> inputIndices, Array<uint32_t> &outputIndices) {
+ void triangulatePolygon(ConstArrayView<Vector3> vertices, ConstArrayView<uint32_t> inputIndices, Array<uint32_t> &outputIndices)
+ {
m_polygonVertices.clear();
m_polygonVertices.reserve(inputIndices.length);
outputIndices.clear();
@@ -3276,7 +3469,8 @@ struct Triangulator {
outputIndices.push_back(inputIndices[0]);
outputIndices.push_back(inputIndices[1]);
outputIndices.push_back(inputIndices[2]);
- } else {
+ }
+ else {
// Build 2D polygon projecting vertices onto normal plane.
// Faces are not necesarily planar, this is for example the case, when the face comes from filling a hole. In such cases
// it's much better to use the best fit plane.
@@ -3348,7 +3542,8 @@ struct Triangulator {
}
private:
- static bool pointInTriangle(const Vector2 &p, const Vector2 &a, const Vector2 &b, const Vector2 &c) {
+ static bool pointInTriangle(const Vector2 &p, const Vector2 &a, const Vector2 &b, const Vector2 &c)
+ {
return triangleArea(a, b, p) >= kAreaEpsilon && triangleArea(b, c, p) >= kAreaEpsilon && triangleArea(c, a, p) >= kAreaEpsilon;
}
@@ -3357,10 +3552,12 @@ private:
Array<Vector2> m_polygonPoints;
};
-class UniformGrid2 {
+class UniformGrid2
+{
public:
// indices are optional.
- void reset(ConstArrayView<Vector2> positions, ConstArrayView<uint32_t> indices = ConstArrayView<uint32_t>(), uint32_t reserveEdgeCount = 0) {
+ void reset(ConstArrayView<Vector2> positions, ConstArrayView<uint32_t> indices = ConstArrayView<uint32_t>(), uint32_t reserveEdgeCount = 0)
+ {
m_edges.clear();
if (reserveEdgeCount > 0)
m_edges.reserve(reserveEdgeCount);
@@ -3369,12 +3566,14 @@ public:
m_cellDataOffsets.clear();
}
- void append(uint32_t edge) {
+ void append(uint32_t edge)
+ {
XA_DEBUG_ASSERT(m_cellDataOffsets.isEmpty());
m_edges.push_back(edge);
}
- bool intersect(Vector2 v1, Vector2 v2, float epsilon) {
+ bool intersect(Vector2 v1, Vector2 v2, float epsilon)
+ {
const uint32_t edgeCount = m_edges.size();
bool bruteForce = edgeCount <= 20;
if (!bruteForce && m_cellDataOffsets.isEmpty())
@@ -3401,7 +3600,8 @@ public:
}
// If edges is empty, checks for intersection with all edges in the grid.
- bool intersect(float epsilon, ConstArrayView<uint32_t> edges = ConstArrayView<uint32_t>(), ConstArrayView<uint32_t> ignoreEdges = ConstArrayView<uint32_t>()) {
+ bool intersect(float epsilon, ConstArrayView<uint32_t> edges = ConstArrayView<uint32_t>(), ConstArrayView<uint32_t> ignoreEdges = ConstArrayView<uint32_t>())
+ {
bool bruteForce = m_edges.size() <= 20;
if (!bruteForce && m_cellDataOffsets.isEmpty())
bruteForce = !createGrid();
@@ -3471,7 +3671,8 @@ public:
}
#if XA_DEBUG_EXPORT_BOUNDARY_GRID
- void debugExport(const char *filename) {
+ void debugExport(const char *filename)
+ {
Array<uint8_t> image;
image.resize(m_gridWidth * m_gridHeight * 3);
for (uint32_t y = 0; y < m_gridHeight; y++) {
@@ -3493,7 +3694,8 @@ public:
#endif
private:
- bool createGrid() {
+ bool createGrid()
+ {
// Compute edge extents. Min will be the grid origin.
const uint32_t edgeCount = m_edges.size();
Extents2 edgeExtents;
@@ -3545,7 +3747,8 @@ private:
return true;
}
- void computePotentialEdges(Vector2 p1, Vector2 p2) {
+ void computePotentialEdges(Vector2 p1, Vector2 p2)
+ {
m_potentialEdges.clear();
traverse(p1, p2);
for (uint32_t j = 0; j < m_traversedCellOffsets.size(); j++) {
@@ -3563,7 +3766,8 @@ private:
}
// "A Fast Voxel Traversal Algorithm for Ray Tracing"
- void traverse(Vector2 p1, Vector2 p2) {
+ void traverse(Vector2 p1, Vector2 p2)
+ {
const Vector2 dir = p2 - p1;
const Vector2 normal = normalizeSafe(dir, Vector2(0.0f));
const int stepX = dir.x >= 0 ? 1 : -1;
@@ -3584,12 +3788,14 @@ private:
if (normal.x > kEpsilon || normal.x < -kEpsilon) {
tMaxX = (distToNextCellX * stepX) / normal.x;
tDeltaX = (m_cellSize * stepX) / normal.x;
- } else
+ }
+ else
tMaxX = tDeltaX = FLT_MAX;
if (normal.y > kEpsilon || normal.y < -kEpsilon) {
tMaxY = (distToNextCellY * stepY) / normal.y;
tDeltaY = (m_cellSize * stepY) / normal.y;
- } else
+ }
+ else
tMaxY = tDeltaY = FLT_MAX;
m_traversedCellOffsets.clear();
m_traversedCellOffsets.push_back(firstCell[0] + firstCell[1] * m_gridWidth);
@@ -3616,23 +3822,28 @@ private:
}
}
- uint32_t cellX(float x) const {
+ uint32_t cellX(float x) const
+ {
return min((uint32_t)max(0.0f, (x - m_gridOrigin.x) / m_cellSize), m_gridWidth - 1u);
}
- uint32_t cellY(float y) const {
+ uint32_t cellY(float y) const
+ {
return min((uint32_t)max(0.0f, (y - m_gridOrigin.y) / m_cellSize), m_gridHeight - 1u);
}
- Vector2 edgePosition0(uint32_t edge) const {
+ Vector2 edgePosition0(uint32_t edge) const
+ {
return m_positions[vertexAt(meshEdgeIndex0(edge))];
}
- Vector2 edgePosition1(uint32_t edge) const {
+ Vector2 edgePosition1(uint32_t edge) const
+ {
return m_positions[vertexAt(meshEdgeIndex1(edge))];
}
- uint32_t vertexAt(uint32_t index) const {
+ uint32_t vertexAt(uint32_t index) const
+ {
return m_indices.length > 0 ? m_indices[index] : index;
}
@@ -3648,13 +3859,15 @@ private:
Array<uint32_t> m_traversedCellOffsets;
};
-struct UvMeshChart {
+struct UvMeshChart
+{
Array<uint32_t> faces;
Array<uint32_t> indices;
uint32_t material;
};
-struct UvMesh {
+struct UvMesh
+{
UvMeshDecl decl;
BitArray faceIgnore;
Array<uint32_t> faceMaterials;
@@ -3664,7 +3877,8 @@ struct UvMesh {
Array<uint32_t> vertexToChartMap;
};
-struct UvMeshInstance {
+struct UvMeshInstance
+{
UvMesh *mesh;
Array<Vector2> texcoords;
};
@@ -3712,30 +3926,27 @@ struct UvMeshInstance {
* FRANCE
*/
namespace opennl {
-#define NL_NEW(T) XA_ALLOC(MemTag::OpenNL, T)
-#define NL_NEW_ARRAY(T, NB) XA_ALLOC_ARRAY(MemTag::OpenNL, T, NB)
-#define NL_RENEW_ARRAY(T, x, NB) XA_REALLOC(MemTag::OpenNL, x, T, NB)
-#define NL_DELETE(x) \
- XA_FREE(x); \
- x = nullptr
-#define NL_DELETE_ARRAY(x) \
- XA_FREE(x); \
- x = nullptr
-#define NL_CLEAR(x, T) memset(x, 0, sizeof(T));
-#define NL_CLEAR_ARRAY(T, x, NB) memset(x, 0, (size_t)(NB) * sizeof(T))
-#define NL_NEW_VECTOR(dim) XA_ALLOC_ARRAY(MemTag::OpenNL, double, dim)
-#define NL_DELETE_VECTOR(ptr) XA_FREE(ptr)
+#define NL_NEW(T) XA_ALLOC(MemTag::OpenNL, T)
+#define NL_NEW_ARRAY(T,NB) XA_ALLOC_ARRAY(MemTag::OpenNL, T, NB)
+#define NL_RENEW_ARRAY(T,x,NB) XA_REALLOC(MemTag::OpenNL, x, T, NB)
+#define NL_DELETE(x) XA_FREE(x); x = nullptr
+#define NL_DELETE_ARRAY(x) XA_FREE(x); x = nullptr
+#define NL_CLEAR(x, T) memset(x, 0, sizeof(T));
+#define NL_CLEAR_ARRAY(T,x,NB) memset(x, 0, (size_t)(NB)*sizeof(T))
+#define NL_NEW_VECTOR(dim) XA_ALLOC_ARRAY(MemTag::OpenNL, double, dim)
+#define NL_DELETE_VECTOR(ptr) XA_FREE(ptr)
struct NLMatrixStruct;
-typedef NLMatrixStruct *NLMatrix;
+typedef NLMatrixStruct * NLMatrix;
typedef void (*NLDestroyMatrixFunc)(NLMatrix M);
-typedef void (*NLMultMatrixVectorFunc)(NLMatrix M, const double *x, double *y);
+typedef void (*NLMultMatrixVectorFunc)(NLMatrix M, const double* x, double* y);
#define NL_MATRIX_SPARSE_DYNAMIC 0x1001
-#define NL_MATRIX_CRS 0x1002
-#define NL_MATRIX_OTHER 0x1006
+#define NL_MATRIX_CRS 0x1002
+#define NL_MATRIX_OTHER 0x1006
-struct NLMatrixStruct {
+struct NLMatrixStruct
+{
uint32_t m;
uint32_t n;
uint32_t type;
@@ -3745,35 +3956,39 @@ struct NLMatrixStruct {
/* Dynamic arrays for sparse row/columns */
-struct NLCoeff {
+struct NLCoeff
+{
uint32_t index;
double value;
};
-struct NLRowColumn {
+struct NLRowColumn
+{
uint32_t size;
uint32_t capacity;
- NLCoeff *coeff;
+ NLCoeff* coeff;
};
/* Compressed Row Storage */
-struct NLCRSMatrix {
+struct NLCRSMatrix
+{
uint32_t m;
uint32_t n;
uint32_t type;
NLDestroyMatrixFunc destroy_func;
NLMultMatrixVectorFunc mult_func;
- double *val;
- uint32_t *rowptr;
- uint32_t *colind;
+ double* val;
+ uint32_t* rowptr;
+ uint32_t* colind;
uint32_t nslices;
- uint32_t *sliceptr;
+ uint32_t* sliceptr;
};
/* SparseMatrix data structure */
-struct NLSparseMatrix {
+struct NLSparseMatrix
+{
uint32_t m;
uint32_t n;
uint32_t type;
@@ -3781,23 +3996,25 @@ struct NLSparseMatrix {
NLMultMatrixVectorFunc mult_func;
uint32_t diag_size;
uint32_t diag_capacity;
- NLRowColumn *row;
- NLRowColumn *column;
- double *diag;
+ NLRowColumn* row;
+ NLRowColumn* column;
+ double* diag;
uint32_t row_capacity;
uint32_t column_capacity;
};
/* NLContext data structure */
-struct NLBufferBinding {
- void *base_address;
+struct NLBufferBinding
+{
+ void* base_address;
uint32_t stride;
};
-#define NL_BUFFER_ITEM(B, i) *(double *)((void *)((char *)((B).base_address) + ((i) * (B).stride)))
+#define NL_BUFFER_ITEM(B,i) *(double*)((void*)((char*)((B).base_address)+((i)*(B).stride)))
-struct NLContext {
+struct NLContext
+{
NLBufferBinding *variable_buffer;
double *variable_value;
bool *variable_is_locked;
@@ -3821,30 +4038,35 @@ struct NLContext {
double error;
};
-static void nlDeleteMatrix(NLMatrix M) {
+static void nlDeleteMatrix(NLMatrix M)
+{
if (!M)
return;
M->destroy_func(M);
NL_DELETE(M);
}
-static void nlMultMatrixVector(NLMatrix M, const double *x, double *y) {
+static void nlMultMatrixVector(NLMatrix M, const double* x, double* y)
+{
M->mult_func(M, x, y);
}
-static void nlRowColumnConstruct(NLRowColumn *c) {
+static void nlRowColumnConstruct(NLRowColumn* c)
+{
c->size = 0;
c->capacity = 0;
c->coeff = nullptr;
}
-static void nlRowColumnDestroy(NLRowColumn *c) {
+static void nlRowColumnDestroy(NLRowColumn* c)
+{
NL_DELETE_ARRAY(c->coeff);
c->size = 0;
c->capacity = 0;
}
-static void nlRowColumnGrow(NLRowColumn *c) {
+static void nlRowColumnGrow(NLRowColumn* c)
+{
if (c->capacity != 0) {
c->capacity = 2 * c->capacity;
c->coeff = NL_RENEW_ARRAY(NLCoeff, c->coeff, c->capacity);
@@ -3855,7 +4077,8 @@ static void nlRowColumnGrow(NLRowColumn *c) {
}
}
-static void nlRowColumnAdd(NLRowColumn *c, uint32_t index, double value) {
+static void nlRowColumnAdd(NLRowColumn* c, uint32_t index, double value)
+{
for (uint32_t i = 0; i < c->size; i++) {
if (c->coeff[i].index == index) {
c->coeff[i].value += value;
@@ -3870,7 +4093,8 @@ static void nlRowColumnAdd(NLRowColumn *c, uint32_t index, double value) {
}
/* Does not check whether the index already exists */
-static void nlRowColumnAppend(NLRowColumn *c, uint32_t index, double value) {
+static void nlRowColumnAppend(NLRowColumn* c, uint32_t index, double value)
+{
if (c->size == c->capacity)
nlRowColumnGrow(c);
c->coeff[c->size].index = index;
@@ -3878,27 +4102,32 @@ static void nlRowColumnAppend(NLRowColumn *c, uint32_t index, double value) {
c->size++;
}
-static void nlRowColumnZero(NLRowColumn *c) {
+static void nlRowColumnZero(NLRowColumn* c)
+{
c->size = 0;
}
-static void nlRowColumnClear(NLRowColumn *c) {
+static void nlRowColumnClear(NLRowColumn* c)
+{
c->size = 0;
c->capacity = 0;
NL_DELETE_ARRAY(c->coeff);
}
-static int nlCoeffCompare(const void *p1, const void *p2) {
- return (((NLCoeff *)(p2))->index < ((NLCoeff *)(p1))->index);
+static int nlCoeffCompare(const void* p1, const void* p2)
+{
+ return (((NLCoeff*)(p2))->index < ((NLCoeff*)(p1))->index);
}
-static void nlRowColumnSort(NLRowColumn *c) {
+static void nlRowColumnSort(NLRowColumn* c)
+{
qsort(c->coeff, c->size, sizeof(NLCoeff), nlCoeffCompare);
}
/* CRSMatrix data structure */
-static void nlCRSMatrixDestroy(NLCRSMatrix *M) {
+static void nlCRSMatrixDestroy(NLCRSMatrix* M)
+{
NL_DELETE_ARRAY(M->val);
NL_DELETE_ARRAY(M->rowptr);
NL_DELETE_ARRAY(M->colind);
@@ -3908,7 +4137,8 @@ static void nlCRSMatrixDestroy(NLCRSMatrix *M) {
M->nslices = 0;
}
-static void nlCRSMatrixMultSlice(NLCRSMatrix *M, const double *x, double *y, uint32_t Ibegin, uint32_t Iend) {
+static void nlCRSMatrixMultSlice(NLCRSMatrix* M, const double* x, double* y, uint32_t Ibegin, uint32_t Iend)
+{
for (uint32_t i = Ibegin; i < Iend; ++i) {
double sum = 0.0;
for (uint32_t j = M->rowptr[i]; j < M->rowptr[i + 1]; ++j)
@@ -3917,13 +4147,15 @@ static void nlCRSMatrixMultSlice(NLCRSMatrix *M, const double *x, double *y, uin
}
}
-static void nlCRSMatrixMult(NLCRSMatrix *M, const double *x, double *y) {
+static void nlCRSMatrixMult(NLCRSMatrix* M, const double* x, double* y)
+{
int nslices = (int)(M->nslices);
for (int slice = 0; slice < nslices; ++slice)
nlCRSMatrixMultSlice(M, x, y, M->sliceptr[slice], M->sliceptr[slice + 1]);
}
-static void nlCRSMatrixConstruct(NLCRSMatrix *M, uint32_t m, uint32_t n, uint32_t nnz, uint32_t nslices) {
+static void nlCRSMatrixConstruct(NLCRSMatrix* M, uint32_t m, uint32_t n, uint32_t nnz, uint32_t nslices)
+{
M->m = m;
M->n = n;
M->type = NL_MATRIX_CRS;
@@ -3942,19 +4174,22 @@ static void nlCRSMatrixConstruct(NLCRSMatrix *M, uint32_t m, uint32_t n, uint32_
/* SparseMatrix data structure */
-static void nlSparseMatrixDestroyRowColumns(NLSparseMatrix *M) {
+static void nlSparseMatrixDestroyRowColumns(NLSparseMatrix* M)
+{
for (uint32_t i = 0; i < M->m; i++)
nlRowColumnDestroy(&(M->row[i]));
NL_DELETE_ARRAY(M->row);
}
-static void nlSparseMatrixDestroy(NLSparseMatrix *M) {
+static void nlSparseMatrixDestroy(NLSparseMatrix* M)
+{
XA_DEBUG_ASSERT(M->type == NL_MATRIX_SPARSE_DYNAMIC);
nlSparseMatrixDestroyRowColumns(M);
NL_DELETE_ARRAY(M->diag);
}
-static void nlSparseMatrixAdd(NLSparseMatrix *M, uint32_t i, uint32_t j, double value) {
+static void nlSparseMatrixAdd(NLSparseMatrix* M, uint32_t i, uint32_t j, double value)
+{
XA_DEBUG_ASSERT(i >= 0 && i <= M->m - 1);
XA_DEBUG_ASSERT(j >= 0 && j <= M->n - 1);
if (i == j)
@@ -3963,21 +4198,24 @@ static void nlSparseMatrixAdd(NLSparseMatrix *M, uint32_t i, uint32_t j, double
}
/* Returns the number of non-zero coefficients */
-static uint32_t nlSparseMatrixNNZ(NLSparseMatrix *M) {
+static uint32_t nlSparseMatrixNNZ(NLSparseMatrix* M)
+{
uint32_t nnz = 0;
for (uint32_t i = 0; i < M->m; i++)
nnz += M->row[i].size;
return nnz;
}
-static void nlSparseMatrixSort(NLSparseMatrix *M) {
+static void nlSparseMatrixSort(NLSparseMatrix* M)
+{
for (uint32_t i = 0; i < M->m; i++)
nlRowColumnSort(&(M->row[i]));
}
/* SparseMatrix x Vector routines, internal helper routines */
-static void nlSparseMatrix_mult_rows(NLSparseMatrix *A, const double *x, double *y) {
+static void nlSparseMatrix_mult_rows(NLSparseMatrix* A, const double* x, double* y)
+{
/*
* Note: OpenMP does not like unsigned ints
* (causes some floating point exceptions),
@@ -3985,8 +4223,8 @@ static void nlSparseMatrix_mult_rows(NLSparseMatrix *A, const double *x, double
* indices.
*/
int m = (int)(A->m);
- NLCoeff *c = nullptr;
- NLRowColumn *Ri = nullptr;
+ NLCoeff* c = nullptr;
+ NLRowColumn* Ri = nullptr;
for (int i = 0; i < m; i++) {
Ri = &(A->row[i]);
y[i] = 0;
@@ -3997,12 +4235,14 @@ static void nlSparseMatrix_mult_rows(NLSparseMatrix *A, const double *x, double
}
}
-static void nlSparseMatrixMult(NLSparseMatrix *A, const double *x, double *y) {
+static void nlSparseMatrixMult(NLSparseMatrix* A, const double* x, double* y)
+{
XA_DEBUG_ASSERT(A->type == NL_MATRIX_SPARSE_DYNAMIC);
nlSparseMatrix_mult_rows(A, x, y);
}
-static void nlSparseMatrixConstruct(NLSparseMatrix *M, uint32_t m, uint32_t n) {
+static void nlSparseMatrixConstruct(NLSparseMatrix* M, uint32_t m, uint32_t n)
+{
M->m = m;
M->n = n;
M->type = NL_MATRIX_SPARSE_DYNAMIC;
@@ -4022,23 +4262,24 @@ static void nlSparseMatrixConstruct(NLSparseMatrix *M, uint32_t m, uint32_t n) {
NL_CLEAR_ARRAY(double, M->diag, M->diag_size);
}
-static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix *M) {
+static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix* M)
+{
uint32_t nnz = nlSparseMatrixNNZ(M);
uint32_t nslices = 8; /* TODO: get number of cores */
uint32_t slice, cur_bound, cur_NNZ, cur_row;
uint32_t k;
uint32_t slice_size = nnz / nslices;
- NLCRSMatrix *CRS = NL_NEW(NLCRSMatrix);
+ NLCRSMatrix* CRS = NL_NEW(NLCRSMatrix);
NL_CLEAR(CRS, NLCRSMatrix);
nlCRSMatrixConstruct(CRS, M->m, M->n, nnz, nslices);
nlSparseMatrixSort(M);
/* Convert matrix to CRS format */
k = 0;
for (uint32_t i = 0; i < M->m; ++i) {
- NLRowColumn *Ri = &(M->row[i]);
+ NLRowColumn* Ri = &(M->row[i]);
CRS->rowptr[i] = k;
for (uint32_t ij = 0; ij < Ri->size; ij++) {
- NLCoeff *c = &(Ri->coeff[ij]);
+ NLCoeff* c = &(Ri->coeff[ij]);
CRS->val[k] = c->value;
CRS->colind[k] = c->index;
++k;
@@ -4053,8 +4294,8 @@ static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix *M) {
CRS->sliceptr[0] = 0;
for (slice = 1; slice < nslices; ++slice) {
while (cur_NNZ < cur_bound && cur_row < M->m) {
- ++cur_row;
cur_NNZ += CRS->rowptr[cur_row + 1] - CRS->rowptr[cur_row];
+ ++cur_row;
}
CRS->sliceptr[slice] = cur_row;
cur_bound += slice_size;
@@ -4064,17 +4305,19 @@ static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix *M) {
return (NLMatrix)CRS;
}
-static void nlMatrixCompress(NLMatrix *M) {
+static void nlMatrixCompress(NLMatrix* M)
+{
NLMatrix CRS = nullptr;
if ((*M)->type != NL_MATRIX_SPARSE_DYNAMIC)
return;
- CRS = nlCRSMatrixNewFromSparseMatrix((NLSparseMatrix *)*M);
+ CRS = nlCRSMatrixNewFromSparseMatrix((NLSparseMatrix*)*M);
nlDeleteMatrix(*M);
*M = CRS;
}
-static NLContext *nlNewContext() {
- NLContext *result = NL_NEW(NLContext);
+static NLContext *nlNewContext()
+{
+ NLContext* result = NL_NEW(NLContext);
NL_CLEAR(result, NLContext);
result->max_iterations = 100;
result->threshold = 1e-6;
@@ -4083,7 +4326,8 @@ static NLContext *nlNewContext() {
return result;
}
-static void nlDeleteContext(NLContext *context) {
+static void nlDeleteContext(NLContext *context)
+{
nlDeleteMatrix(context->M);
context->M = nullptr;
nlDeleteMatrix(context->P);
@@ -4101,19 +4345,22 @@ static void nlDeleteContext(NLContext *context) {
NL_DELETE(context);
}
-static double ddot(int n, const double *x, const double *y) {
+static double ddot(int n, const double *x, const double *y)
+{
double sum = 0.0;
for (int i = 0; i < n; i++)
sum += x[i] * y[i];
return sum;
}
-static void daxpy(int n, double a, const double *x, double *y) {
+static void daxpy(int n, double a, const double *x, double *y)
+{
for (int i = 0; i < n; i++)
y[i] = a * x[i] + y[i];
}
-static void dscal(int n, double a, double *x) {
+static void dscal(int n, double a, double *x)
+{
for (int i = 0; i < n; i++)
x[i] *= a;
}
@@ -4136,16 +4383,17 @@ static void dscal(int n, double a, double *x) {
* versions of matrix x vector product (CPU/GPU, sparse/dense ...)
*/
-static uint32_t nlSolveSystem_PRE_CG(NLMatrix M, NLMatrix P, double *b, double *x, double eps, uint32_t max_iter, double *sq_bnorm, double *sq_rnorm) {
- int N = (int)M->n;
- double *r = NL_NEW_VECTOR(N);
- double *d = NL_NEW_VECTOR(N);
- double *h = NL_NEW_VECTOR(N);
+static uint32_t nlSolveSystem_PRE_CG(NLMatrix M, NLMatrix P, double* b, double* x, double eps, uint32_t max_iter, double *sq_bnorm, double *sq_rnorm)
+{
+ int N = (int)M->n;
+ double* r = NL_NEW_VECTOR(N);
+ double* d = NL_NEW_VECTOR(N);
+ double* h = NL_NEW_VECTOR(N);
double *Ad = h;
uint32_t its = 0;
double rh, alpha, beta;
double b_square = ddot(N, b, b);
- double err = eps * eps * b_square;
+ double err = eps * eps*b_square;
double curr_err;
nlMultMatrixVector(M, x, r);
daxpy(N, -1., b, r);
@@ -4175,12 +4423,13 @@ static uint32_t nlSolveSystem_PRE_CG(NLMatrix M, NLMatrix P, double *b, double *
return its;
}
-static uint32_t nlSolveSystemIterative(NLContext *context, NLMatrix M, NLMatrix P, double *b_in, double *x_in, double eps, uint32_t max_iter) {
+static uint32_t nlSolveSystemIterative(NLContext *context, NLMatrix M, NLMatrix P, double* b_in, double* x_in, double eps, uint32_t max_iter)
+{
uint32_t result = 0;
double rnorm = 0.0;
double bnorm = 0.0;
- double *b = b_in;
- double *x = x_in;
+ double* b = b_in;
+ double* x = x_in;
XA_DEBUG_ASSERT(M->m == M->n);
double sq_bnorm, sq_rnorm;
result = nlSolveSystem_PRE_CG(M, P, b, x, eps, max_iter, &sq_bnorm, &sq_rnorm);
@@ -4195,9 +4444,10 @@ static uint32_t nlSolveSystemIterative(NLContext *context, NLMatrix M, NLMatrix
return result;
}
-static bool nlSolveIterative(NLContext *context) {
- double *b = context->b;
- double *x = context->x;
+static bool nlSolveIterative(NLContext *context)
+{
+ double* b = context->b;
+ double* x = context->x;
uint32_t n = context->n;
NLMatrix M = context->M;
NLMatrix P = context->P;
@@ -4209,30 +4459,34 @@ static bool nlSolveIterative(NLContext *context) {
return true;
}
-struct NLJacobiPreconditioner {
+struct NLJacobiPreconditioner
+{
uint32_t m;
uint32_t n;
uint32_t type;
NLDestroyMatrixFunc destroy_func;
NLMultMatrixVectorFunc mult_func;
- double *diag_inv;
+ double* diag_inv;
};
-static void nlJacobiPreconditionerDestroy(NLJacobiPreconditioner *M) {
+static void nlJacobiPreconditionerDestroy(NLJacobiPreconditioner* M)
+{
NL_DELETE_ARRAY(M->diag_inv);
}
-static void nlJacobiPreconditionerMult(NLJacobiPreconditioner *M, const double *x, double *y) {
+static void nlJacobiPreconditionerMult(NLJacobiPreconditioner* M, const double* x, double* y)
+{
for (uint32_t i = 0; i < M->n; ++i)
y[i] = x[i] * M->diag_inv[i];
}
-static NLMatrix nlNewJacobiPreconditioner(NLMatrix M_in) {
- NLSparseMatrix *M = nullptr;
- NLJacobiPreconditioner *result = nullptr;
+static NLMatrix nlNewJacobiPreconditioner(NLMatrix M_in)
+{
+ NLSparseMatrix* M = nullptr;
+ NLJacobiPreconditioner* result = nullptr;
XA_DEBUG_ASSERT(M_in->type == NL_MATRIX_SPARSE_DYNAMIC);
XA_DEBUG_ASSERT(M_in->m == M_in->n);
- M = (NLSparseMatrix *)M_in;
+ M = (NLSparseMatrix*)M_in;
result = NL_NEW(NLJacobiPreconditioner);
NL_CLEAR(result, NLJacobiPreconditioner);
result->m = M->m;
@@ -4250,7 +4504,8 @@ static NLMatrix nlNewJacobiPreconditioner(NLMatrix M_in) {
#define NL_NB_VARIABLES 0x101
#define NL_MAX_ITERATIONS 0x103
-static void nlSolverParameteri(NLContext *context, uint32_t pname, int param) {
+static void nlSolverParameteri(NLContext *context, uint32_t pname, int param)
+{
if (pname == NL_NB_VARIABLES) {
XA_DEBUG_ASSERT(param > 0);
context->nb_variables = (uint32_t)param;
@@ -4261,22 +4516,26 @@ static void nlSolverParameteri(NLContext *context, uint32_t pname, int param) {
}
}
-static void nlSetVariable(NLContext *context, uint32_t index, double value) {
+static void nlSetVariable(NLContext *context, uint32_t index, double value)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
NL_BUFFER_ITEM(context->variable_buffer[0], index) = value;
}
-static double nlGetVariable(NLContext *context, uint32_t index) {
+static double nlGetVariable(NLContext *context, uint32_t index)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
return NL_BUFFER_ITEM(context->variable_buffer[0], index);
}
-static void nlLockVariable(NLContext *context, uint32_t index) {
+static void nlLockVariable(NLContext *context, uint32_t index)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
context->variable_is_locked[index] = true;
}
-static void nlVariablesToVector(NLContext *context) {
+static void nlVariablesToVector(NLContext *context)
+{
uint32_t n = context->n;
XA_DEBUG_ASSERT(context->x);
for (uint32_t k = 0; k < context->nb_systems; ++k) {
@@ -4291,7 +4550,8 @@ static void nlVariablesToVector(NLContext *context) {
}
}
-static void nlVectorToVariables(NLContext *context) {
+static void nlVectorToVariables(NLContext *context)
+{
uint32_t n = context->n;
XA_DEBUG_ASSERT(context->x);
for (uint32_t k = 0; k < context->nb_systems; ++k) {
@@ -4306,7 +4566,8 @@ static void nlVectorToVariables(NLContext *context) {
}
}
-static void nlCoefficient(NLContext *context, uint32_t index, double value) {
+static void nlCoefficient(NLContext *context, uint32_t index, double value)
+{
XA_DEBUG_ASSERT(index >= 0 && index <= context->nb_variables - 1);
if (context->variable_is_locked[index]) {
/*
@@ -4323,11 +4584,12 @@ static void nlCoefficient(NLContext *context, uint32_t index, double value) {
}
}
-#define NL_SYSTEM 0x0
-#define NL_MATRIX 0x1
-#define NL_ROW 0x2
+#define NL_SYSTEM 0x0
+#define NL_MATRIX 0x1
+#define NL_ROW 0x2
-static void nlBegin(NLContext *context, uint32_t prim) {
+static void nlBegin(NLContext *context, uint32_t prim)
+{
if (prim == NL_SYSTEM) {
XA_DEBUG_ASSERT(context->nb_variables > 0);
context->variable_buffer = NL_NEW_ARRAY(NLBufferBinding, context->nb_systems);
@@ -4336,8 +4598,8 @@ static void nlBegin(NLContext *context, uint32_t prim) {
NL_CLEAR_ARRAY(double, context->variable_value, context->nb_variables * context->nb_systems);
for (uint32_t k = 0; k < context->nb_systems; ++k) {
context->variable_buffer[k].base_address =
- context->variable_value +
- k * context->nb_variables;
+ context->variable_value +
+ k * context->nb_variables;
context->variable_buffer[k].stride = sizeof(double);
}
context->variable_is_locked = NL_NEW_ARRAY(bool, context->nb_variables);
@@ -4360,11 +4622,11 @@ static void nlBegin(NLContext *context, uint32_t prim) {
context->max_iterations = n * 5;
context->M = (NLMatrix)(NL_NEW(NLSparseMatrix));
NL_CLEAR(context->M, NLSparseMatrix);
- nlSparseMatrixConstruct((NLSparseMatrix *)(context->M), n, n);
- context->x = NL_NEW_ARRAY(double, n * context->nb_systems);
- NL_CLEAR_ARRAY(double, context->x, n * context->nb_systems);
- context->b = NL_NEW_ARRAY(double, n * context->nb_systems);
- NL_CLEAR_ARRAY(double, context->b, n * context->nb_systems);
+ nlSparseMatrixConstruct((NLSparseMatrix*)(context->M), n, n);
+ context->x = NL_NEW_ARRAY(double, n*context->nb_systems);
+ NL_CLEAR_ARRAY(double, context->x, n*context->nb_systems);
+ context->b = NL_NEW_ARRAY(double, n*context->nb_systems);
+ NL_CLEAR_ARRAY(double, context->b, n*context->nb_systems);
nlVariablesToVector(context);
nlRowColumnConstruct(&context->af);
nlRowColumnConstruct(&context->al);
@@ -4375,15 +4637,16 @@ static void nlBegin(NLContext *context, uint32_t prim) {
}
}
-static void nlEnd(NLContext *context, uint32_t prim) {
+static void nlEnd(NLContext *context, uint32_t prim)
+{
if (prim == NL_MATRIX) {
nlRowColumnClear(&context->af);
nlRowColumnClear(&context->al);
} else if (prim == NL_ROW) {
- NLRowColumn *af = &context->af;
- NLRowColumn *al = &context->al;
- NLSparseMatrix *M = (NLSparseMatrix *)context->M;
- double *b = context->b;
+ NLRowColumn* af = &context->af;
+ NLRowColumn* al = &context->al;
+ NLSparseMatrix* M = (NLSparseMatrix*)context->M;
+ double* b = context->b;
uint32_t nf = af->size;
uint32_t nl = al->size;
uint32_t n = context->n;
@@ -4404,13 +4667,14 @@ static void nlEnd(NLContext *context, uint32_t prim) {
S += al->coeff[jj].value * NL_BUFFER_ITEM(context->variable_buffer[k], j);
}
for (uint32_t jj = 0; jj < nf; jj++)
- b[k * n + af->coeff[jj].index] -= af->coeff[jj].value * S;
+ b[k*n + af->coeff[jj].index] -= af->coeff[jj].value * S;
}
context->current_row++;
}
}
-static bool nlSolve(NLContext *context) {
+static bool nlSolve(NLContext *context)
+{
nlDeleteMatrix(context->P);
context->P = nlNewJacobiPreconditioner(context->M);
nlMatrixCompress(&context->M);
@@ -4421,9 +4685,11 @@ static bool nlSolve(NLContext *context) {
} // namespace opennl
namespace raster {
-class ClippedTriangle {
+class ClippedTriangle
+{
public:
- ClippedTriangle(const Vector2 &a, const Vector2 &b, const Vector2 &c) {
+ ClippedTriangle(const Vector2 &a, const Vector2 &b, const Vector2 &c)
+ {
m_numVertices = 3;
m_activeVertexBuffer = 0;
m_verticesA[0] = a;
@@ -4434,20 +4700,20 @@ public:
m_area = 0;
}
- void clipHorizontalPlane(float offset, float clipdirection) {
- Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ void clipHorizontalPlane(float offset, float clipdirection)
+ {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
m_activeVertexBuffer ^= 1;
Vector2 *v2 = m_vertexBuffers[m_activeVertexBuffer];
v[m_numVertices] = v[0];
- float dy2, dy1 = offset - v[0].y;
- int dy2in, dy1in = clipdirection * dy1 >= 0;
- uint32_t p = 0;
+ float dy2, dy1 = offset - v[0].y;
+ int dy2in, dy1in = clipdirection * dy1 >= 0;
+ uint32_t p = 0;
for (uint32_t k = 0; k < m_numVertices; k++) {
- dy2 = offset - v[k + 1].y;
+ dy2 = offset - v[k + 1].y;
dy2in = clipdirection * dy2 >= 0;
- if (dy1in)
- v2[p++] = v[k];
- if (dy1in + dy2in == 1) { // not both in/out
+ if (dy1in) v2[p++] = v[k];
+ if ( dy1in + dy2in == 1 ) { // not both in/out
float dx = v[k + 1].x - v[k].x;
float dy = v[k + 1].y - v[k].y;
v2[p++] = Vector2(v[k].x + dy1 * (dx / dy), offset);
@@ -4458,20 +4724,20 @@ public:
m_numVertices = p;
}
- void clipVerticalPlane(float offset, float clipdirection) {
- Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ void clipVerticalPlane(float offset, float clipdirection)
+ {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
m_activeVertexBuffer ^= 1;
Vector2 *v2 = m_vertexBuffers[m_activeVertexBuffer];
v[m_numVertices] = v[0];
- float dx2, dx1 = offset - v[0].x;
- int dx2in, dx1in = clipdirection * dx1 >= 0;
- uint32_t p = 0;
+ float dx2, dx1 = offset - v[0].x;
+ int dx2in, dx1in = clipdirection * dx1 >= 0;
+ uint32_t p = 0;
for (uint32_t k = 0; k < m_numVertices; k++) {
dx2 = offset - v[k + 1].x;
dx2in = clipdirection * dx2 >= 0;
- if (dx1in)
- v2[p++] = v[k];
- if (dx1in + dx2in == 1) { // not both in/out
+ if (dx1in) v2[p++] = v[k];
+ if ( dx1in + dx2in == 1 ) { // not both in/out
float dx = v[k + 1].x - v[k].x;
float dy = v[k + 1].y - v[k].y;
v2[p++] = Vector2(offset, v[k].y + dx1 * (dy / dx));
@@ -4482,8 +4748,9 @@ public:
m_numVertices = p;
}
- void computeArea() {
- Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
+ void computeArea()
+ {
+ Vector2 *v = m_vertexBuffers[m_activeVertexBuffer];
v[m_numVertices] = v[0];
m_area = 0;
float centroidx = 0, centroidy = 0;
@@ -4497,7 +4764,8 @@ public:
m_area = 0.5f * fabsf(m_area);
}
- void clipAABox(float x0, float y0, float x1, float y1) {
+ void clipAABox(float x0, float y0, float x1, float y1)
+ {
clipVerticalPlane(x0, -1);
clipHorizontalPlane(y0, -1);
clipVerticalPlane(x1, 1);
@@ -4505,7 +4773,8 @@ public:
computeArea();
}
- float area() const {
+ float area() const
+ {
return m_area;
}
@@ -4522,9 +4791,10 @@ private:
typedef bool (*SamplingCallback)(void *param, int x, int y);
/// A triangle for rasterization.
-struct Triangle {
- Triangle(const Vector2 &_v0, const Vector2 &_v1, const Vector2 &_v2) :
- v1(_v0), v2(_v2), v3(_v1), n1(0.0f), n2(0.0f), n3(0.0f) {
+struct Triangle
+{
+ Triangle(const Vector2 &_v0, const Vector2 &_v1, const Vector2 &_v2) : v1(_v0), v2(_v2), v3(_v1), n1(0.0f), n2(0.0f), n3(0.0f)
+ {
// make sure every triangle is front facing.
flipBackface();
// Compute deltas.
@@ -4532,7 +4802,8 @@ struct Triangle {
computeUnitInwardNormals();
}
- bool isValid() {
+ bool isValid()
+ {
const Vector2 e0 = v3 - v1;
const Vector2 e1 = v2 - v1;
const float area = e0.y * e1.x - e1.y * e0.x;
@@ -4540,17 +4811,18 @@ struct Triangle {
}
// extents has to be multiple of BK_SIZE!!
- bool drawAA(const Vector2 &extents, SamplingCallback cb, void *param) {
- const float PX_INSIDE = 1.0f / sqrtf(2.0f);
- const float PX_OUTSIDE = -1.0f / sqrtf(2.0f);
+ bool drawAA(const Vector2 &extents, SamplingCallback cb, void *param)
+ {
+ const float PX_INSIDE = 1.0f/sqrtf(2.0f);
+ const float PX_OUTSIDE = -1.0f/sqrtf(2.0f);
const float BK_SIZE = 8;
- const float BK_INSIDE = sqrtf(BK_SIZE * BK_SIZE / 2.0f);
- const float BK_OUTSIDE = -sqrtf(BK_SIZE * BK_SIZE / 2.0f);
+ const float BK_INSIDE = sqrtf(BK_SIZE*BK_SIZE/2.0f);
+ const float BK_OUTSIDE = -sqrtf(BK_SIZE*BK_SIZE/2.0f);
// Bounding rectangle
float minx = floorf(max(min3(v1.x, v2.x, v3.x), 0.0f));
float miny = floorf(max(min3(v1.y, v2.y, v3.y), 0.0f));
- float maxx = ceilf(min(max3(v1.x, v2.x, v3.x), extents.x - 1.0f));
- float maxy = ceilf(min(max3(v1.y, v2.y, v3.y), extents.y - 1.0f));
+ float maxx = ceilf( min(max3(v1.x, v2.x, v3.x), extents.x - 1.0f));
+ float maxy = ceilf( min(max3(v1.y, v2.y, v3.y), extents.y - 1.0f));
// There's no reason to align the blocks to the viewport, instead we align them to the origin of the triangle bounds.
minx = floorf(minx);
miny = floorf(miny);
@@ -4575,10 +4847,9 @@ struct Triangle {
float bC = C2 + n2.x * xc + n2.y * yc;
float cC = C3 + n3.x * xc + n3.y * yc;
// Skip block when outside an edge
- if ((aC <= BK_OUTSIDE) || (bC <= BK_OUTSIDE) || (cC <= BK_OUTSIDE))
- continue;
+ if ( (aC <= BK_OUTSIDE) || (bC <= BK_OUTSIDE) || (cC <= BK_OUTSIDE) ) continue;
// Accept whole block when totally covered
- if ((aC >= BK_INSIDE) && (bC >= BK_INSIDE) && (cC >= BK_INSIDE)) {
+ if ( (aC >= BK_INSIDE) && (bC >= BK_INSIDE) && (cC >= BK_INSIDE) ) {
for (float y = y0; y < y0 + BK_SIZE; y++) {
for (float x = x0; x < x0 + BK_SIZE; x++) {
if (!cb(param, (int)x, (int)y))
@@ -4621,9 +4892,10 @@ struct Triangle {
}
private:
- void flipBackface() {
+ void flipBackface()
+ {
// check if triangle is backfacing, if so, swap two vertices
- if (((v3.x - v1.x) * (v2.y - v1.y) - (v3.y - v1.y) * (v2.x - v1.x)) < 0) {
+ if ( ((v3.x - v1.x) * (v2.y - v1.y) - (v3.y - v1.y) * (v2.x - v1.x)) < 0 ) {
Vector2 hv = v1;
v1 = v2;
v2 = hv; // swap pos
@@ -4631,7 +4903,8 @@ private:
}
// compute unit inward normals for each edge.
- void computeUnitInwardNormals() {
+ void computeUnitInwardNormals()
+ {
n1 = v1 - v2;
n1 = Vector2(-n1.y, n1.x);
n1 = n1 * (1.0f / sqrtf(dot(n1, n1)));
@@ -4649,7 +4922,8 @@ private:
};
// Process the given triangle. Returns false if rasterization was interrupted by the callback.
-static bool drawTriangle(const Vector2 &extents, const Vector2 v[3], SamplingCallback cb, void *param) {
+static bool drawTriangle(const Vector2 &extents, const Vector2 v[3], SamplingCallback cb, void *param)
+{
Triangle tri(v[0], v[1], v[2]);
// @@ It would be nice to have a conservative drawing mode that enlarges the triangle extents by one texel and is able to handle degenerate triangles.
// @@ Maybe the simplest thing to do would be raster triangle edges.
@@ -4664,19 +4938,22 @@ namespace segment {
// - Insertion is o(n)
// - Smallest element goes at the end, so that popping it is o(1).
-struct CostQueue {
- CostQueue(uint32_t size = UINT32_MAX) :
- m_maxSize(size), m_pairs(MemTag::SegmentAtlasChartCandidates) {}
+struct CostQueue
+{
+ CostQueue(uint32_t size = UINT32_MAX) : m_maxSize(size), m_pairs(MemTag::SegmentAtlasChartCandidates) {}
- float peekCost() const {
+ float peekCost() const
+ {
return m_pairs.back().cost;
}
- uint32_t peekFace() const {
+ uint32_t peekFace() const
+ {
return m_pairs.back().face;
}
- void push(float cost, uint32_t face) {
+ void push(float cost, uint32_t face)
+ {
const Pair p = { cost, face };
if (m_pairs.isEmpty() || cost < peekCost())
m_pairs.push_back(p);
@@ -4693,25 +4970,29 @@ struct CostQueue {
}
}
- uint32_t pop() {
+ uint32_t pop()
+ {
XA_DEBUG_ASSERT(!m_pairs.isEmpty());
uint32_t f = m_pairs.back().face;
m_pairs.pop_back();
return f;
}
- XA_INLINE void clear() {
+ XA_INLINE void clear()
+ {
m_pairs.clear();
}
- XA_INLINE uint32_t count() const {
+ XA_INLINE uint32_t count() const
+ {
return m_pairs.size();
}
private:
const uint32_t m_maxSize;
- struct Pair {
+ struct Pair
+ {
float cost;
uint32_t face;
};
@@ -4719,7 +5000,8 @@ private:
Array<Pair> m_pairs;
};
-struct AtlasData {
+struct AtlasData
+{
ChartOptions options;
const Mesh *mesh = nullptr;
Array<float> edgeDihedralAngles;
@@ -4729,10 +5011,10 @@ struct AtlasData {
Array<Vector3> faceNormals;
BitArray isFaceInChart;
- AtlasData() :
- edgeDihedralAngles(MemTag::SegmentAtlasMeshData), edgeLengths(MemTag::SegmentAtlasMeshData), faceAreas(MemTag::SegmentAtlasMeshData), faceNormals(MemTag::SegmentAtlasMeshData) {}
+ AtlasData() : edgeDihedralAngles(MemTag::SegmentAtlasMeshData), edgeLengths(MemTag::SegmentAtlasMeshData), faceAreas(MemTag::SegmentAtlasMeshData), faceNormals(MemTag::SegmentAtlasMeshData) {}
- void compute() {
+ void compute()
+ {
const uint32_t faceCount = mesh->faceCount();
const uint32_t edgeCount = mesh->edgeCount();
edgeDihedralAngles.resize(edgeCount);
@@ -4773,18 +5055,20 @@ struct AtlasData {
};
// If MeshDecl::vertexUvData is set on input meshes, find charts by floodfilling faces in world/model space without crossing UV seams.
-struct OriginalUvCharts {
- OriginalUvCharts(AtlasData &data) :
- m_data(data) {}
+struct OriginalUvCharts
+{
+ OriginalUvCharts(AtlasData &data) : m_data(data) {}
uint32_t chartCount() const { return m_charts.size(); }
const Basis &chartBasis(uint32_t chartIndex) const { return m_chartBasis[chartIndex]; }
- ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const {
+ ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const
+ {
const Chart &chart = m_charts[chartIndex];
return ConstArrayView<uint32_t>(&m_chartFaces[chart.firstFace], chart.faceCount);
}
- void compute() {
+ void compute()
+ {
m_charts.clear();
m_chartFaces.clear();
const Mesh *mesh = m_data.mesh;
@@ -4805,7 +5089,8 @@ struct OriginalUvCharts {
}
// Compute basis for each chart.
m_chartBasis.resize(m_charts.size());
- for (uint32_t c = 0; c < m_charts.size(); c++) {
+ for (uint32_t c = 0; c < m_charts.size(); c++)
+ {
const Chart &chart = m_charts[c];
m_tempPoints.resize(chart.faceCount * 3);
for (uint32_t f = 0; f < chart.faceCount; f++) {
@@ -4818,11 +5103,13 @@ struct OriginalUvCharts {
}
private:
- struct Chart {
+ struct Chart
+ {
uint32_t firstFace, faceCount;
};
- void floodfillFaces(Chart &chart) {
+ void floodfillFaces(Chart &chart)
+ {
const bool isFaceAreaNegative = m_data.faceUvAreas[m_chartFaces[chart.firstFace]] < 0.0f;
for (;;) {
bool newFaceAdded = false;
@@ -4868,13 +5155,14 @@ static uint32_t s_planarRegionsCurrentRegion;
static uint32_t s_planarRegionsCurrentVertex;
#endif
-struct PlanarCharts {
- PlanarCharts(AtlasData &data) :
- m_data(data), m_nextRegionFace(MemTag::SegmentAtlasPlanarRegions), m_faceToRegionId(MemTag::SegmentAtlasPlanarRegions) {}
+struct PlanarCharts
+{
+ PlanarCharts(AtlasData &data) : m_data(data), m_nextRegionFace(MemTag::SegmentAtlasPlanarRegions), m_faceToRegionId(MemTag::SegmentAtlasPlanarRegions) {}
const Basis &chartBasis(uint32_t chartIndex) const { return m_chartBasis[chartIndex]; }
uint32_t chartCount() const { return m_charts.size(); }
- ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const {
+ ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const
+ {
const Chart &chart = m_charts[chartIndex];
return ConstArrayView<uint32_t>(&m_chartFaces[chart.firstFace], chart.faceCount);
}
@@ -4883,7 +5171,8 @@ struct PlanarCharts {
uint32_t nextRegionFace(uint32_t face) const { return m_nextRegionFace[face]; }
float regionArea(uint32_t region) const { return m_regionAreas[region]; }
- void compute() {
+ void compute()
+ {
const uint32_t faceCount = m_data.mesh->faceCount();
// Precompute regions of coplanar incident faces.
m_regionFirstFace.clear();
@@ -4983,7 +5272,8 @@ struct PlanarCharts {
if (!createChart)
break;
face = m_nextRegionFace[face];
- } while (face != firstRegionFace);
+ }
+ while (face != firstRegionFace);
// Create a chart.
if (createChart) {
Chart chart;
@@ -4995,13 +5285,15 @@ struct PlanarCharts {
m_chartFaces.push_back(face);
chart.faceCount++;
face = m_nextRegionFace[face];
- } while (face != firstRegionFace);
+ }
+ while (face != firstRegionFace);
m_charts.push_back(chart);
}
}
// Compute basis for each chart using the first face normal (all faces have the same normal).
m_chartBasis.resize(m_charts.size());
- for (uint32_t c = 0; c < m_charts.size(); c++) {
+ for (uint32_t c = 0; c < m_charts.size(); c++)
+ {
const uint32_t face = m_chartFaces[m_charts[c].firstFace];
Basis &basis = m_chartBasis[c];
basis.normal = m_data.faceNormals[face];
@@ -5011,7 +5303,8 @@ struct PlanarCharts {
}
private:
- struct Chart {
+ struct Chart
+ {
uint32_t firstFace, faceCount;
};
@@ -5025,11 +5318,12 @@ private:
Array<Basis> m_chartBasis;
};
-struct ClusteredCharts {
- ClusteredCharts(AtlasData &data, const PlanarCharts &planarCharts) :
- m_data(data), m_planarCharts(planarCharts), m_texcoords(MemTag::SegmentAtlasMeshData), m_bestTriangles(10), m_placingSeeds(false) {}
+struct ClusteredCharts
+{
+ ClusteredCharts(AtlasData &data, const PlanarCharts &planarCharts) : m_data(data), m_planarCharts(planarCharts), m_texcoords(MemTag::SegmentAtlasMeshData), m_bestTriangles(10), m_placingSeeds(false) {}
- ~ClusteredCharts() {
+ ~ClusteredCharts()
+ {
const uint32_t chartCount = m_charts.size();
for (uint32_t i = 0; i < chartCount; i++) {
m_charts[i]->~Chart();
@@ -5041,7 +5335,8 @@ struct ClusteredCharts {
ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const { return m_charts[chartIndex]->faces; }
const Basis &chartBasis(uint32_t chartIndex) const { return m_charts[chartIndex]->basis; }
- void compute() {
+ void compute()
+ {
const uint32_t faceCount = m_data.mesh->faceCount();
m_facesLeft = 0;
for (uint32_t i = 0; i < faceCount; i++) {
@@ -5087,9 +5382,9 @@ struct ClusteredCharts {
}
private:
- struct Chart {
- Chart() :
- faces(MemTag::SegmentAtlasChartFaces) {}
+ struct Chart
+ {
+ Chart() : faces(MemTag::SegmentAtlasChartFaces) {}
int id = -1;
Basis basis; // Best fit normal.
@@ -5103,7 +5398,8 @@ private:
uint32_t seed;
};
- void placeSeeds(float threshold) {
+ void placeSeeds(float threshold)
+ {
XA_PROFILE_START(clusteredChartsPlaceSeeds)
m_placingSeeds = true;
// Instead of using a predefiened number of seeds:
@@ -5119,7 +5415,8 @@ private:
}
// Returns true if any of the charts can grow more.
- void growCharts(float threshold) {
+ void growCharts(float threshold)
+ {
XA_PROFILE_START(clusteredChartsGrow)
for (;;) {
if (m_facesLeft == 0)
@@ -5165,7 +5462,8 @@ private:
XA_PROFILE_END(clusteredChartsGrow)
}
- void resetCharts() {
+ void resetCharts()
+ {
XA_PROFILE_START(clusteredChartsReset)
const uint32_t faceCount = m_data.mesh->faceCount();
for (uint32_t i = 0; i < faceCount; i++) {
@@ -5196,7 +5494,8 @@ private:
XA_PROFILE_END(clusteredChartsReset)
}
- bool relocateSeeds() {
+ bool relocateSeeds()
+ {
XA_PROFILE_START(clusteredChartsRelocateSeeds)
bool anySeedChanged = false;
const uint32_t chartCount = m_charts.size();
@@ -5209,7 +5508,8 @@ private:
return anySeedChanged;
}
- void fillHoles(float threshold) {
+ void fillHoles(float threshold)
+ {
XA_PROFILE_START(clusteredChartsFillHoles)
while (m_facesLeft > 0)
createChart(threshold);
@@ -5217,7 +5517,8 @@ private:
}
#if XA_MERGE_CHARTS
- void mergeCharts() {
+ void mergeCharts()
+ {
XA_PROFILE_START(clusteredChartsMerge)
const uint32_t chartCount = m_charts.size();
// Merge charts progressively until there's none left to merge.
@@ -5286,7 +5587,7 @@ private:
if (m_sharedBoundaryLengthsNoSeams[cc] > 0.0f && equal(m_sharedBoundaryLengthsNoSeams[cc], chart2->boundaryLength, kEpsilon))
goto merge;
if (m_sharedBoundaryLengths[cc] > 0.2f * max(0.0f, chart->boundaryLength - externalBoundaryLength) ||
- m_sharedBoundaryLengths[cc] > 0.75f * chart2->boundaryLength)
+ m_sharedBoundaryLengths[cc] > 0.75f * chart2->boundaryLength)
goto merge;
continue;
merge:
@@ -5324,7 +5625,8 @@ private:
#endif
private:
- void createChart(float threshold) {
+ void createChart(float threshold)
+ {
Chart *chart = XA_NEW(MemTag::Default, Chart);
chart->id = (int)m_charts.size();
m_charts.push_back(chart);
@@ -5355,13 +5657,15 @@ private:
}
}
- bool isChartBoundaryEdge(const Chart *chart, uint32_t edge) const {
+ bool isChartBoundaryEdge(const Chart *chart, uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_data.mesh->oppositeEdge(edge);
const uint32_t oppositeFace = meshEdgeFace(oppositeEdge);
return oppositeEdge == UINT32_MAX || m_faceCharts[oppositeFace] != chart->id;
}
- bool computeChartBasis(Chart *chart, Basis *basis) {
+ bool computeChartBasis(Chart *chart, Basis *basis)
+ {
const uint32_t faceCount = chart->faces.size();
m_tempPoints.resize(chart->faces.size() * 3);
for (uint32_t i = 0; i < faceCount; i++) {
@@ -5372,7 +5676,8 @@ private:
return Fit::computeBasis(m_tempPoints, basis);
}
- bool isFaceFlipped(uint32_t face) const {
+ bool isFaceFlipped(uint32_t face) const
+ {
const Vector2 &v1 = m_texcoords[face * 3 + 0];
const Vector2 &v2 = m_texcoords[face * 3 + 1];
const Vector2 &v3 = m_texcoords[face * 3 + 2];
@@ -5380,7 +5685,8 @@ private:
return parametricArea < 0.0f;
}
- void parameterizeChart(const Chart *chart) {
+ void parameterizeChart(const Chart *chart)
+ {
const uint32_t faceCount = chart->faces.size();
for (uint32_t i = 0; i < faceCount; i++) {
const uint32_t face = chart->faces[i];
@@ -5393,7 +5699,8 @@ private:
}
// m_faceCharts for the chart faces must be set to the chart ID. Needed to compute boundary edges.
- bool isChartParameterizationValid(const Chart *chart) {
+ bool isChartParameterizationValid(const Chart *chart)
+ {
const uint32_t faceCount = chart->faces.size();
// Check for flipped faces in the parameterization. OK if all are flipped.
uint32_t flippedFaceCount = 0;
@@ -5427,7 +5734,8 @@ private:
return true;
}
- bool addFaceToChart(Chart *chart, uint32_t face) {
+ bool addFaceToChart(Chart *chart, uint32_t face)
+ {
XA_DEBUG_ASSERT(!m_data.isFaceInChart.get(face));
const uint32_t oldFaceCount = chart->faces.size();
const bool firstFace = oldFaceCount == 0;
@@ -5505,7 +5813,8 @@ private:
}
// Returns true if the seed has changed.
- bool relocateSeed(Chart *chart) {
+ bool relocateSeed(Chart *chart)
+ {
// Find the first N triangles that fit the proxy best.
const uint32_t faceCount = chart->faces.size();
m_bestTriangles.clear();
@@ -5535,7 +5844,8 @@ private:
}
// Cost is combined metrics * weights.
- float computeCost(Chart *chart, uint32_t face) const {
+ float computeCost(Chart *chart, uint32_t face) const
+ {
// Estimate boundary length and area:
const float newChartArea = computeArea(chart, face);
const float newBoundaryLength = computeBoundaryLength(chart, face);
@@ -5571,20 +5881,23 @@ private:
// Returns a value in [0-1].
// 0 if face normal is coplanar to the chart's best fit normal.
// 1 if face normal is perpendicular.
- float computeNormalDeviationMetric(Chart *chart, uint32_t face) const {
+ float computeNormalDeviationMetric(Chart *chart, uint32_t face) const
+ {
// All faces in coplanar regions have the same normal, can use any face.
const Vector3 faceNormal = m_data.faceNormals[face];
// Use plane fitting metric for now:
return min(1.0f - dot(faceNormal, chart->basis.normal), 1.0f); // @@ normal deviations should be weighted by face area
}
- float computeRoundnessMetric(Chart *chart, float newBoundaryLength, float newChartArea) const {
+ float computeRoundnessMetric(Chart *chart, float newBoundaryLength, float newChartArea) const
+ {
const float oldRoundness = square(chart->boundaryLength) / chart->area;
const float newRoundness = square(newBoundaryLength) / newChartArea;
return 1.0f - oldRoundness / newRoundness;
}
- float computeStraightnessMetric(Chart *chart, uint32_t firstFace) const {
+ float computeStraightnessMetric(Chart *chart, uint32_t firstFace) const
+ {
float l_out = 0.0f; // Length of firstFace planar region boundary that doesn't border the chart.
float l_in = 0.0f; // Length that does border the chart.
const uint32_t planarRegionId = m_planarCharts.regionIdFromFace(firstFace);
@@ -5613,7 +5926,8 @@ private:
#endif
}
- bool isNormalSeam(uint32_t edge) const {
+ bool isNormalSeam(uint32_t edge) const
+ {
const uint32_t oppositeEdge = m_data.mesh->oppositeEdge(edge);
if (oppositeEdge == UINT32_MAX)
return false; // boundary edge
@@ -5633,7 +5947,8 @@ private:
return !equal(m_data.faceNormals[f0], m_data.faceNormals[f1], kNormalEpsilon);
}
- float computeNormalSeamMetric(Chart *chart, uint32_t firstFace) const {
+ float computeNormalSeamMetric(Chart *chart, uint32_t firstFace) const
+ {
float seamFactor = 0.0f, totalLength = 0.0f;
uint32_t face = firstFace;
for (;;) {
@@ -5673,7 +5988,8 @@ private:
return seamFactor / totalLength;
}
- float computeTextureSeamMetric(Chart *chart, uint32_t firstFace) const {
+ float computeTextureSeamMetric(Chart *chart, uint32_t firstFace) const
+ {
float seamLength = 0.0f, totalLength = 0.0f;
uint32_t face = firstFace;
for (;;) {
@@ -5699,7 +6015,8 @@ private:
return seamLength / totalLength;
}
- float computeArea(Chart *chart, uint32_t firstFace) const {
+ float computeArea(Chart *chart, uint32_t firstFace) const
+ {
float area = chart->area;
uint32_t face = firstFace;
for (;;) {
@@ -5711,7 +6028,8 @@ private:
return area;
}
- float computeBoundaryLength(Chart *chart, uint32_t firstFace) const {
+ float computeBoundaryLength(Chart *chart, uint32_t firstFace) const
+ {
float boundaryLength = chart->boundaryLength;
// Add new edges, subtract edges shared with the chart.
const uint32_t planarRegionId = m_planarCharts.regionIdFromFace(firstFace);
@@ -5732,10 +6050,11 @@ private:
if (face == firstFace)
break;
}
- return max(0.0f, boundaryLength); // @@ Hack!
+ return max(0.0f, boundaryLength); // @@ Hack!
}
- bool mergeChart(Chart *owner, Chart *chart, float sharedBoundaryLength) {
+ bool mergeChart(Chart *owner, Chart *chart, float sharedBoundaryLength)
+ {
const uint32_t oldOwnerFaceCount = owner->faces.size();
const uint32_t chartFaceCount = chart->faces.size();
owner->faces.push_back(chart->faces);
@@ -5793,8 +6112,10 @@ private:
bool m_placingSeeds;
};
-struct ChartGeneratorType {
- enum Enum {
+struct ChartGeneratorType
+{
+ enum Enum
+ {
OriginalUv,
Planar,
Clustered,
@@ -5802,15 +6123,17 @@ struct ChartGeneratorType {
};
};
-struct Atlas {
- Atlas() :
- m_originalUvCharts(m_data), m_planarCharts(m_data), m_clusteredCharts(m_data, m_planarCharts) {}
+struct Atlas
+{
+ Atlas() : m_originalUvCharts(m_data), m_planarCharts(m_data), m_clusteredCharts(m_data, m_planarCharts) {}
- uint32_t chartCount() const {
+ uint32_t chartCount() const
+ {
return m_originalUvCharts.chartCount() + m_planarCharts.chartCount() + m_clusteredCharts.chartCount();
}
- ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const {
+ ConstArrayView<uint32_t> chartFaces(uint32_t chartIndex) const
+ {
if (chartIndex < m_originalUvCharts.chartCount())
return m_originalUvCharts.chartFaces(chartIndex);
chartIndex -= m_originalUvCharts.chartCount();
@@ -5820,7 +6143,8 @@ struct Atlas {
return m_clusteredCharts.chartFaces(chartIndex);
}
- const Basis &chartBasis(uint32_t chartIndex) const {
+ const Basis &chartBasis(uint32_t chartIndex) const
+ {
if (chartIndex < m_originalUvCharts.chartCount())
return m_originalUvCharts.chartBasis(chartIndex);
chartIndex -= m_originalUvCharts.chartCount();
@@ -5830,7 +6154,8 @@ struct Atlas {
return m_clusteredCharts.chartBasis(chartIndex);
}
- ChartGeneratorType::Enum chartGeneratorType(uint32_t chartIndex) const {
+ ChartGeneratorType::Enum chartGeneratorType(uint32_t chartIndex) const
+ {
if (chartIndex < m_originalUvCharts.chartCount())
return ChartGeneratorType::OriginalUv;
chartIndex -= m_originalUvCharts.chartCount();
@@ -5839,7 +6164,8 @@ struct Atlas {
return ChartGeneratorType::Clustered;
}
- void reset(const Mesh *mesh, const ChartOptions &options) {
+ void reset(const Mesh *mesh, const ChartOptions &options)
+ {
XA_PROFILE_START(buildAtlasInit)
m_data.options = options;
m_data.mesh = mesh;
@@ -5847,7 +6173,8 @@ struct Atlas {
XA_PROFILE_END(buildAtlasInit)
}
- void compute() {
+ void compute()
+ {
if (m_data.options.useInputMeshUvs) {
XA_PROFILE_START(originalUvCharts)
m_originalUvCharts.compute();
@@ -5868,17 +6195,19 @@ private:
ClusteredCharts m_clusteredCharts;
};
-struct ComputeUvMeshChartsTaskArgs {
+struct ComputeUvMeshChartsTaskArgs
+{
UvMesh *mesh;
Progress *progress;
};
// Charts are found by floodfilling faces without crossing UV seams.
-struct ComputeUvMeshChartsTask {
- ComputeUvMeshChartsTask(ComputeUvMeshChartsTaskArgs *args) :
- m_mesh(args->mesh), m_progress(args->progress), m_uvToEdgeMap(MemTag::Default, m_mesh->indices.size()), m_faceAssigned(m_mesh->indices.size() / 3) {}
+struct ComputeUvMeshChartsTask
+{
+ ComputeUvMeshChartsTask(ComputeUvMeshChartsTaskArgs *args) : m_mesh(args->mesh), m_progress(args->progress), m_uvToEdgeMap(MemTag::Default, m_mesh->indices.size()), m_faceAssigned(m_mesh->indices.size() / 3) {}
- void run() {
+ void run()
+ {
const uint32_t vertexCount = m_mesh->texcoords.size();
const uint32_t indexCount = m_mesh->indices.size();
const uint32_t faceCount = indexCount / 3;
@@ -5932,7 +6261,8 @@ struct ComputeUvMeshChartsTask {
private:
// The chart at chartIndex doesn't have to exist yet.
- bool canAddFaceToChart(uint32_t chartIndex, uint32_t face) const {
+ bool canAddFaceToChart(uint32_t chartIndex, uint32_t face) const
+ {
if (m_faceAssigned.get(face))
return false; // Already assigned to a chart.
if (m_mesh->faceIgnore.get(face))
@@ -5949,7 +6279,8 @@ private:
return true;
}
- void addFaceToChart(uint32_t chartIndex, uint32_t face) {
+ void addFaceToChart(uint32_t chartIndex, uint32_t face)
+ {
UvMeshChart *chart = m_mesh->charts[chartIndex];
m_faceAssigned.set(face);
chart->faces.push_back(face);
@@ -5960,20 +6291,22 @@ private:
}
}
- UvMesh *const m_mesh;
- Progress *const m_progress;
+ UvMesh * const m_mesh;
+ Progress * const m_progress;
HashMap<Vector2> m_uvToEdgeMap; // Face is edge / 3.
BitArray m_faceAssigned;
};
-static void runComputeUvMeshChartsTask(void * /*groupUserData*/, void *taskUserData) {
+static void runComputeUvMeshChartsTask(void * /*groupUserData*/, void *taskUserData)
+{
XA_PROFILE_START(computeChartsThread)
ComputeUvMeshChartsTask task((ComputeUvMeshChartsTaskArgs *)taskUserData);
task.run();
XA_PROFILE_END(computeChartsThread)
}
-static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *> meshes, ProgressFunc progressFunc, void *progressUserData) {
+static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *> meshes, ProgressFunc progressFunc, void *progressUserData)
+{
uint32_t totalFaceCount = 0;
for (uint32_t i = 0; i < meshes.length; i++)
totalFaceCount += meshes[i]->indices.size() / 3;
@@ -5981,7 +6314,8 @@ static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *
TaskGroupHandle taskGroup = taskScheduler->createTaskGroup(nullptr, meshes.length);
Array<ComputeUvMeshChartsTaskArgs> taskArgs;
taskArgs.resize(meshes.length);
- for (uint32_t i = 0; i < meshes.length; i++) {
+ for (uint32_t i = 0; i < meshes.length; i++)
+ {
ComputeUvMeshChartsTaskArgs &args = taskArgs[i];
args.mesh = meshes[i];
args.progress = &progress;
@@ -5999,7 +6333,8 @@ static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *
namespace param {
// Fast sweep in 3 directions
-static bool findApproximateDiameterVertices(Mesh *mesh, uint32_t *a, uint32_t *b) {
+static bool findApproximateDiameterVertices(Mesh *mesh, uint32_t *a, uint32_t *b)
+{
XA_DEBUG_ASSERT(a != nullptr);
XA_DEBUG_ASSERT(b != nullptr);
const uint32_t vertexCount = mesh->vertexCount();
@@ -6056,7 +6391,8 @@ static bool findApproximateDiameterVertices(Mesh *mesh, uint32_t *a, uint32_t *b
// From OpenNL LSCM example.
// Computes the coordinates of the vertices of a triangle in a local 2D orthonormal basis of the triangle's plane.
-static void projectTriangle(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 *z0, Vector2 *z1, Vector2 *z2) {
+static void projectTriangle(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 *z0, Vector2 *z1, Vector2 *z2)
+{
Vector3 X = normalize(p1 - p0);
Vector3 Z = normalize(cross(X, p2 - p0));
Vector3 Y = cross(Z, X);
@@ -6068,24 +6404,28 @@ static void projectTriangle(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 *z0, Vec
// Conformal relations from Brecht Van Lommel (based on ABF):
-static float vec_angle_cos(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) {
+static float vec_angle_cos(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
+{
Vector3 d1 = v1 - v2;
Vector3 d2 = v3 - v2;
return clamp(dot(d1, d2) / (length(d1) * length(d2)), -1.0f, 1.0f);
}
-static float vec_angle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3) {
+static float vec_angle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
+{
float dot = vec_angle_cos(v1, v2, v3);
return acosf(dot);
}
-static void triangle_angles(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, float *a1, float *a2, float *a3) {
+static void triangle_angles(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, float *a1, float *a2, float *a3)
+{
*a1 = vec_angle(v3, v1, v2);
*a2 = vec_angle(v1, v2, v3);
*a3 = kPi - *a2 - *a1;
}
-static bool setup_abf_relations(opennl::NLContext *context, int id0, int id1, int id2, const Vector3 &p0, const Vector3 &p1, const Vector3 &p2) {
+static bool setup_abf_relations(opennl::NLContext *context, int id0, int id1, int id2, const Vector3 &p0, const Vector3 &p1, const Vector3 &p2)
+{
// @@ IC: Wouldn't it be more accurate to return cos and compute 1-cos^2?
// It does indeed seem to be a little bit more robust.
// @@ Need to revisit this more carefully!
@@ -6142,7 +6482,8 @@ static bool setup_abf_relations(opennl::NLContext *context, int id0, int id1, in
return true;
}
-static bool computeLeastSquaresConformalMap(Mesh *mesh) {
+static bool computeLeastSquaresConformalMap(Mesh *mesh)
+{
uint32_t lockedVertex0, lockedVertex1;
if (!findApproximateDiameterVertices(mesh, &lockedVertex0, &lockedVertex1)) {
// Mesh has no boundaries.
@@ -6189,16 +6530,16 @@ static bool computeLeastSquaresConformalMap(Mesh *mesh) {
// Note : b = 0
// Real part
opennl::nlBegin(context, NL_ROW);
- opennl::nlCoefficient(context, u0_id, -a + c);
- opennl::nlCoefficient(context, v0_id, b - d);
- opennl::nlCoefficient(context, u1_id, -c);
- opennl::nlCoefficient(context, v1_id, d);
+ opennl::nlCoefficient(context, u0_id, -a+c) ;
+ opennl::nlCoefficient(context, v0_id, b-d) ;
+ opennl::nlCoefficient(context, u1_id, -c) ;
+ opennl::nlCoefficient(context, v1_id, d) ;
opennl::nlCoefficient(context, u2_id, a);
opennl::nlEnd(context, NL_ROW);
// Imaginary part
opennl::nlBegin(context, NL_ROW);
- opennl::nlCoefficient(context, u0_id, -b + d);
- opennl::nlCoefficient(context, v0_id, -a + c);
+ opennl::nlCoefficient(context, u0_id, -b+d);
+ opennl::nlCoefficient(context, v0_id, -a+c);
opennl::nlCoefficient(context, u1_id, -d);
opennl::nlCoefficient(context, v1_id, -c);
opennl::nlCoefficient(context, v2_id, a);
@@ -6222,8 +6563,10 @@ static bool computeLeastSquaresConformalMap(Mesh *mesh) {
return true;
}
-struct PiecewiseParam {
- void reset(const Mesh *mesh) {
+struct PiecewiseParam
+{
+ void reset(const Mesh *mesh)
+ {
m_mesh = mesh;
const uint32_t faceCount = m_mesh->faceCount();
const uint32_t vertexCount = m_mesh->vertexCount();
@@ -6241,7 +6584,8 @@ struct PiecewiseParam {
ConstArrayView<uint32_t> chartFaces() const { return m_patch; }
ConstArrayView<Vector2> texcoords() const { return m_texcoords; }
- bool computeChart() {
+ bool computeChart()
+ {
// Clear per-patch state.
m_patch.clear();
m_candidates.clear();
@@ -6370,7 +6714,8 @@ struct PiecewiseParam {
}
private:
- struct Candidate {
+ struct Candidate
+ {
uint32_t face, vertex;
Candidate *prev, *next; // The previous/next candidate with the same vertex.
Vector2 position;
@@ -6380,14 +6725,10 @@ private:
float patchVertexOrient;
};
- struct CandidateIterator {
- CandidateIterator(Candidate *head) :
- m_current(head) { XA_DEBUG_ASSERT(!head->prev); }
- void advance() {
- if (m_current != nullptr) {
- m_current = m_current->next;
- }
- }
+ struct CandidateIterator
+ {
+ CandidateIterator(Candidate *head) : m_current(head) { XA_DEBUG_ASSERT(!head->prev); }
+ void advance() { if (m_current != nullptr) { m_current = m_current->next; } }
bool isDone() const { return !m_current; }
Candidate *current() { return m_current; }
@@ -6406,7 +6747,8 @@ private:
UniformGrid2 m_boundaryGrid;
Array<uint32_t> m_newBoundaryEdges, m_ignoreBoundaryEdges; // Temp arrays used when testing for boundary intersection.
- void addFaceToPatch(uint32_t face) {
+ void addFaceToPatch(uint32_t face)
+ {
XA_DEBUG_ASSERT(!m_faceInPatch.get(face));
XA_DEBUG_ASSERT(!m_faceInAnyPatch.get(face));
m_patch.push_back(face);
@@ -6446,7 +6788,8 @@ private:
}
}
- void addCandidateFace(uint32_t patchEdge, float patchVertexOrient, uint32_t face, uint32_t edge, uint32_t freeVertex) {
+ void addCandidateFace(uint32_t patchEdge, float patchVertexOrient, uint32_t face, uint32_t edge, uint32_t freeVertex)
+ {
XA_DEBUG_ASSERT(!m_faceToCandidate[face]);
Vector2 texcoords[3];
orthoProjectFace(face, texcoords);
@@ -6549,7 +6892,8 @@ private:
it.current()->maxCost = maxCost;
}
- Candidate *linkedCandidateHead(Candidate *candidate) {
+ Candidate *linkedCandidateHead(Candidate *candidate)
+ {
Candidate *current = candidate;
for (;;) {
if (!current->prev)
@@ -6559,7 +6903,8 @@ private:
return current;
}
- void removeLinkedCandidates(Candidate *head) {
+ void removeLinkedCandidates(Candidate *head)
+ {
XA_DEBUG_ASSERT(!head->prev);
Candidate *current = head;
while (current) {
@@ -6576,7 +6921,8 @@ private:
}
}
- void orthoProjectFace(uint32_t face, Vector2 *texcoords) const {
+ void orthoProjectFace(uint32_t face, Vector2 *texcoords) const
+ {
const Vector3 normal = -m_mesh->computeFaceNormal(face);
const Vector3 tangent = normalize(m_mesh->position(m_mesh->vertexAt(face * 3 + 1)) - m_mesh->position(m_mesh->vertexAt(face * 3 + 0)));
const Vector3 bitangent = cross(normal, tangent);
@@ -6586,14 +6932,16 @@ private:
}
}
- float parametricArea(const Vector2 *texcoords) const {
+ float parametricArea(const Vector2 *texcoords) const
+ {
const Vector2 &v1 = texcoords[0];
const Vector2 &v2 = texcoords[1];
const Vector2 &v3 = texcoords[2];
return ((v2.x - v1.x) * (v3.y - v1.y) - (v3.x - v1.x) * (v2.y - v1.y)) * 0.5f;
}
- float computeStretch(Vector3 p1, Vector3 p2, Vector3 p3, Vector2 t1, Vector2 t2, Vector2 t3) const {
+ float computeStretch(Vector3 p1, Vector3 p2, Vector3 p3, Vector2 t1, Vector2 t2, Vector2 t3) const
+ {
float parametricArea = ((t2.y - t1.y) * (t3.x - t1.x) - (t3.y - t1.y) * (t2.x - t1.x)) * 0.5f;
if (isZero(parametricArea, kAreaEpsilon))
return FLT_MAX;
@@ -6607,13 +6955,15 @@ private:
}
// Return value is positive if the point is one side of the edge, negative if on the other side.
- float orientToEdge(Vector2 edgeVertex0, Vector2 edgeVertex1, Vector2 point) const {
+ float orientToEdge(Vector2 edgeVertex0, Vector2 edgeVertex1, Vector2 point) const
+ {
return (edgeVertex0.x - point.x) * (edgeVertex1.y - point.y) - (edgeVertex0.y - point.y) * (edgeVertex1.x - point.x);
}
};
// Estimate quality of existing parameterization.
-struct Quality {
+struct Quality
+{
// computeBoundaryIntersection
bool boundaryIntersection = false;
@@ -6630,7 +6980,8 @@ struct Quality {
float conformalMetric = 0.0f;
float authalicMetric = 0.0f;
- void computeBoundaryIntersection(const Mesh *mesh, UniformGrid2 &boundaryGrid) {
+ void computeBoundaryIntersection(const Mesh *mesh, UniformGrid2 &boundaryGrid)
+ {
const Array<uint32_t> &boundaryEdges = mesh->boundaryEdges();
const uint32_t boundaryEdgeCount = boundaryEdges.size();
boundaryGrid.reset(mesh->texcoords(), mesh->indices(), boundaryEdgeCount);
@@ -6646,7 +6997,8 @@ struct Quality {
#endif
}
- void computeFlippedFaces(const Mesh *mesh, Array<uint32_t> *flippedFaces) {
+ void computeFlippedFaces(const Mesh *mesh, Array<uint32_t> *flippedFaces)
+ {
totalTriangleCount = flippedTriangleCount = zeroAreaTriangleCount = 0;
if (flippedFaces)
flippedFaces->clear();
@@ -6682,7 +7034,8 @@ struct Quality {
flippedFaces->clear();
flippedTriangleCount = 0;
}
- if (flippedTriangleCount > totalTriangleCount / 2) {
+ if (flippedTriangleCount > totalTriangleCount / 2)
+ {
// If more than half the triangles are flipped, reverse the flipped / not flipped classification.
flippedTriangleCount = totalTriangleCount - flippedTriangleCount;
if (flippedFaces) {
@@ -6704,7 +7057,8 @@ struct Quality {
}
}
- void computeMetrics(const Mesh *mesh) {
+ void computeMetrics(const Mesh *mesh)
+ {
totalGeometricArea = totalParametricArea = 0.0f;
stretchMetric = maxStretchMetric = conformalMetric = authalicMetric = 0.0f;
const uint32_t faceCount = mesh->faceCount();
@@ -6736,7 +7090,7 @@ struct Quality {
const float a = dot(Ss, Ss); // E
const float b = dot(Ss, St); // F
const float c = dot(St, St); // G
- // Compute eigen-values of the first fundamental form:
+ // Compute eigen-values of the first fundamental form:
const float sigma1 = sqrtf(0.5f * max(0.0f, a + c - sqrtf(square(a - c) + 4 * square(b)))); // gamma uppercase, min eigenvalue.
const float sigma2 = sqrtf(0.5f * max(0.0f, a + c + sqrtf(square(a - c) + 4 * square(b)))); // gamma lowercase, max eigenvalue.
XA_ASSERT(sigma2 > sigma1 || equal(sigma1, sigma2, kEpsilon));
@@ -6767,22 +7121,24 @@ struct Quality {
if (totalGeometricArea > 0.0f) {
const float normFactor = sqrtf(totalParametricArea / totalGeometricArea);
stretchMetric = sqrtf(stretchMetric / totalGeometricArea) * normFactor;
- maxStretchMetric *= normFactor;
+ maxStretchMetric *= normFactor;
conformalMetric = sqrtf(conformalMetric / totalGeometricArea);
authalicMetric = sqrtf(authalicMetric / totalGeometricArea);
}
}
};
-struct ChartCtorBuffers {
+struct ChartCtorBuffers
+{
Array<uint32_t> chartMeshIndices;
Array<uint32_t> unifiedMeshIndices;
};
-class Chart {
+class Chart
+{
public:
- Chart(const Basis &basis, segment::ChartGeneratorType::Enum generatorType, ConstArrayView<uint32_t> faces, const Mesh *sourceMesh, uint32_t chartGroupId, uint32_t chartId) :
- m_basis(basis), m_unifiedMesh(nullptr), m_type(ChartType::LSCM), m_generatorType(generatorType), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false) {
+ Chart(const Basis &basis, segment::ChartGeneratorType::Enum generatorType, ConstArrayView<uint32_t> faces, const Mesh *sourceMesh, uint32_t chartGroupId, uint32_t chartId) : m_basis(basis), m_unifiedMesh(nullptr), m_type(ChartType::LSCM), m_generatorType(generatorType), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false)
+ {
XA_UNUSED(chartGroupId);
XA_UNUSED(chartId);
m_faceToSourceFaceMap.copyFrom(faces.data, faces.length);
@@ -6813,8 +7169,7 @@ public:
m_chartVertexToUnifiedVertexMap.push_back(unifiedVertex);
m_originalVertexCount++;
}
- m_originalIndices[f * 3 + i] = sourceVertexToChartVertexMap.get(sourceVertex);
- ;
+ m_originalIndices[f * 3 + i] = sourceVertexToChartVertexMap.get(sourceVertex);;
XA_DEBUG_ASSERT(m_originalIndices[f * 3 + i] != UINT32_MAX);
unifiedIndices[i] = sourceVertexToUnifiedVertexMap.get(sourceUnifiedVertex);
XA_DEBUG_ASSERT(unifiedIndices[i] != UINT32_MAX);
@@ -6838,8 +7193,8 @@ public:
#endif
}
- Chart(ChartCtorBuffers &buffers, const Chart *parent, const Mesh *parentMesh, ConstArrayView<uint32_t> faces, ConstArrayView<Vector2> texcoords, const Mesh *sourceMesh) :
- m_unifiedMesh(nullptr), m_type(ChartType::Piecewise), m_generatorType(segment::ChartGeneratorType::Piecewise), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false) {
+ Chart(ChartCtorBuffers &buffers, const Chart *parent, const Mesh *parentMesh, ConstArrayView<uint32_t> faces, ConstArrayView<Vector2> texcoords, const Mesh *sourceMesh) : m_unifiedMesh(nullptr), m_type(ChartType::Piecewise), m_generatorType(segment::ChartGeneratorType::Piecewise), m_tjunctionCount(0), m_originalVertexCount(0), m_isInvalid(false)
+ {
const uint32_t faceCount = faces.length;
m_faceToSourceFaceMap.resize(faceCount);
for (uint32_t i = 0; i < faceCount; i++)
@@ -6886,7 +7241,8 @@ public:
backupTexcoords();
}
- ~Chart() {
+ ~Chart()
+ {
if (m_unifiedMesh) {
m_unifiedMesh->~Mesh();
XA_FREE(m_unifiedMesh);
@@ -6914,7 +7270,8 @@ public:
ConstArrayView<uint32_t> originalVertices() const { return m_originalIndices; }
- void parameterize(const ChartOptions &options, UniformGrid2 &boundaryGrid) {
+ void parameterize(const ChartOptions &options, UniformGrid2 &boundaryGrid)
+ {
const uint32_t unifiedVertexCount = m_unifiedMesh->vertexCount();
if (m_generatorType == segment::ChartGeneratorType::OriginalUv) {
} else {
@@ -6938,7 +7295,8 @@ public:
XA_PROFILE_START(parameterizeChartsLSCM)
if (options.paramFunc) {
options.paramFunc(&m_unifiedMesh->position(0).x, &m_unifiedMesh->texcoord(0).x, m_unifiedMesh->vertexCount(), m_unifiedMesh->indices().data, m_unifiedMesh->indexCount());
- } else
+ }
+ else
computeLeastSquaresConformalMap(m_unifiedMesh);
XA_PROFILE_END(parameterizeChartsLSCM)
XA_PROFILE_START(parameterizeChartsEvaluateQuality)
@@ -6980,7 +7338,8 @@ public:
backupTexcoords();
}
- Vector2 computeParametricBounds() const {
+ Vector2 computeParametricBounds() const
+ {
Vector2 minCorner(FLT_MAX, FLT_MAX);
Vector2 maxCorner(-FLT_MAX, -FLT_MAX);
const uint32_t vertexCount = m_unifiedMesh->vertexCount();
@@ -6992,7 +7351,8 @@ public:
}
#if XA_CHECK_PIECEWISE_CHART_QUALITY
- void evaluateQuality(UniformGrid2 &boundaryGrid) {
+ void evaluateQuality(UniformGrid2 &boundaryGrid)
+ {
m_quality.computeBoundaryIntersection(m_unifiedMesh, boundaryGrid);
#if XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION
m_quality.computeFlippedFaces(m_unifiedMesh, &m_paramFlippedFaces);
@@ -7004,12 +7364,14 @@ public:
}
#endif
- void restoreTexcoords() {
+ void restoreTexcoords()
+ {
memcpy(m_unifiedMesh->texcoords().data, m_backupTexcoords.data(), m_unifiedMesh->vertexCount() * sizeof(Vector2));
}
private:
- void backupTexcoords() {
+ void backupTexcoords()
+ {
m_backupTexcoords.resize(m_unifiedMesh->vertexCount());
memcpy(m_backupTexcoords.data(), m_unifiedMesh->texcoords().data, m_unifiedMesh->vertexCount() * sizeof(Vector2));
}
@@ -7040,7 +7402,8 @@ private:
bool m_isInvalid;
};
-struct CreateAndParameterizeChartTaskGroupArgs {
+struct CreateAndParameterizeChartTaskGroupArgs
+{
Progress *progress;
ThreadLocal<UniformGrid2> *boundaryGrid;
ThreadLocal<ChartCtorBuffers> *chartBuffers;
@@ -7048,7 +7411,8 @@ struct CreateAndParameterizeChartTaskGroupArgs {
ThreadLocal<PiecewiseParam> *pp;
};
-struct CreateAndParameterizeChartTaskArgs {
+struct CreateAndParameterizeChartTaskArgs
+{
const Basis *basis;
Chart *chart; // output
Array<Chart *> charts; // output (if more than one chart)
@@ -7059,7 +7423,8 @@ struct CreateAndParameterizeChartTaskArgs {
uint32_t chartId;
};
-static void runCreateAndParameterizeChartTask(void *groupUserData, void *taskUserData) {
+static void runCreateAndParameterizeChartTask(void *groupUserData, void *taskUserData)
+{
XA_PROFILE_START(createChartMeshAndParameterizeThread)
auto groupArgs = (CreateAndParameterizeChartTaskGroupArgs *)groupUserData;
auto args = (CreateAndParameterizeChartTaskArgs *)taskUserData;
@@ -7130,13 +7495,15 @@ static void runCreateAndParameterizeChartTask(void *groupUserData, void *taskUse
}
// Set of charts corresponding to mesh faces in the same face group.
-class ChartGroup {
+class ChartGroup
+{
public:
- ChartGroup(uint32_t id, const Mesh *sourceMesh, const MeshFaceGroups *sourceMeshFaceGroups, MeshFaceGroups::Handle faceGroup) :
- m_id(id), m_sourceMesh(sourceMesh), m_sourceMeshFaceGroups(sourceMeshFaceGroups), m_faceGroup(faceGroup) {
+ ChartGroup(uint32_t id, const Mesh *sourceMesh, const MeshFaceGroups *sourceMeshFaceGroups, MeshFaceGroups::Handle faceGroup) : m_id(id), m_sourceMesh(sourceMesh), m_sourceMeshFaceGroups(sourceMeshFaceGroups), m_faceGroup(faceGroup)
+ {
}
- ~ChartGroup() {
+ ~ChartGroup()
+ {
for (uint32_t i = 0; i < m_charts.size(); i++) {
m_charts[i]->~Chart();
XA_FREE(m_charts[i]);
@@ -7147,7 +7514,8 @@ public:
Chart *chartAt(uint32_t i) const { return m_charts[i]; }
uint32_t faceCount() const { return m_sourceMeshFaceGroups->faceCount(m_faceGroup); }
- void computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, Progress *progress, segment::Atlas &atlas, ThreadLocal<UniformGrid2> *boundaryGrid, ThreadLocal<ChartCtorBuffers> *chartBuffers, ThreadLocal<PiecewiseParam> *piecewiseParam) {
+ void computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, Progress *progress, segment::Atlas &atlas, ThreadLocal<UniformGrid2> *boundaryGrid, ThreadLocal<ChartCtorBuffers> *chartBuffers, ThreadLocal<PiecewiseParam> *piecewiseParam)
+ {
// This function may be called multiple times, so destroy existing charts.
for (uint32_t i = 0; i < m_charts.size(); i++) {
m_charts[i]->~Chart();
@@ -7291,7 +7659,8 @@ public:
}
private:
- Mesh *createMesh() {
+ Mesh *createMesh()
+ {
XA_DEBUG_ASSERT(m_faceGroup != MeshFaceGroups::kInvalid);
// Create new mesh from the source mesh, using faces that belong to this group.
m_faceToSourceFaceMap.reserve(m_sourceMeshFaceGroups->faceCount(m_faceGroup));
@@ -7345,14 +7714,15 @@ private:
}
const uint32_t m_id;
- const Mesh *const m_sourceMesh;
- const MeshFaceGroups *const m_sourceMeshFaceGroups;
+ const Mesh * const m_sourceMesh;
+ const MeshFaceGroups * const m_sourceMeshFaceGroups;
const MeshFaceGroups::Handle m_faceGroup;
Array<uint32_t> m_faceToSourceFaceMap; // List of faces of the source mesh that belong to this chart group.
Array<Chart *> m_charts;
};
-struct ChartGroupComputeChartsTaskGroupArgs {
+struct ChartGroupComputeChartsTaskGroupArgs
+{
ThreadLocal<segment::Atlas> *atlas;
const ChartOptions *options;
Progress *progress;
@@ -7362,7 +7732,8 @@ struct ChartGroupComputeChartsTaskGroupArgs {
ThreadLocal<PiecewiseParam> *piecewiseParam;
};
-static void runChartGroupComputeChartsTask(void *groupUserData, void *taskUserData) {
+static void runChartGroupComputeChartsTask(void *groupUserData, void *taskUserData)
+{
auto args = (ChartGroupComputeChartsTaskGroupArgs *)groupUserData;
auto chartGroup = (ChartGroup *)taskUserData;
if (args->progress->cancel)
@@ -7372,7 +7743,8 @@ static void runChartGroupComputeChartsTask(void *groupUserData, void *taskUserDa
XA_PROFILE_END(chartGroupComputeChartsThread)
}
-struct MeshComputeChartsTaskGroupArgs {
+struct MeshComputeChartsTaskGroupArgs
+{
ThreadLocal<segment::Atlas> *atlas;
const ChartOptions *options;
Progress *progress;
@@ -7382,7 +7754,8 @@ struct MeshComputeChartsTaskGroupArgs {
ThreadLocal<PiecewiseParam> *piecewiseParam;
};
-struct MeshComputeChartsTaskArgs {
+struct MeshComputeChartsTaskArgs
+{
const Mesh *sourceMesh;
Array<ChartGroup *> *chartGroups; // output
InvalidMeshGeometry *invalidMeshGeometry; // output
@@ -7392,7 +7765,8 @@ struct MeshComputeChartsTaskArgs {
static uint32_t s_faceGroupsCurrentVertex = 0;
#endif
-static void runMeshComputeChartsTask(void *groupUserData, void *taskUserData) {
+static void runMeshComputeChartsTask(void *groupUserData, void *taskUserData)
+{
auto groupArgs = (MeshComputeChartsTaskGroupArgs *)groupUserData;
auto args = (MeshComputeChartsTaskArgs *)taskUserData;
if (groupArgs->progress->cancel)
@@ -7491,12 +7865,13 @@ cleanup:
}
/// An atlas is a set of chart groups.
-class Atlas {
+class Atlas
+{
public:
- Atlas() :
- m_chartsComputed(false) {}
+ Atlas() : m_chartsComputed(false) {}
- ~Atlas() {
+ ~Atlas()
+ {
for (uint32_t i = 0; i < m_meshChartGroups.size(); i++) {
for (uint32_t j = 0; j < m_meshChartGroups[i].size(); j++) {
m_meshChartGroups[i][j]->~ChartGroup();
@@ -7513,11 +7888,13 @@ public:
uint32_t chartGroupCount(uint32_t mesh) const { return m_meshChartGroups[mesh].size(); }
const ChartGroup *chartGroupAt(uint32_t mesh, uint32_t group) const { return m_meshChartGroups[mesh][group]; }
- void addMesh(const Mesh *mesh) {
+ void addMesh(const Mesh *mesh)
+ {
m_meshes.push_back(mesh);
}
- bool computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, ProgressFunc progressFunc, void *progressUserData) {
+ bool computeCharts(TaskScheduler *taskScheduler, const ChartOptions &options, ProgressFunc progressFunc, void *progressUserData)
+ {
XA_PROFILE_START(computeChartsReal)
#if XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS
segment::s_planarRegionsCurrentRegion = segment::s_planarRegionsCurrentVertex = 0;
@@ -7591,7 +7968,7 @@ public:
private:
Array<const Mesh *> m_meshes;
Array<InvalidMeshGeometry> m_invalidMeshGeometry; // 1 per mesh.
- Array<Array<ChartGroup *>> m_meshChartGroups;
+ Array<Array<ChartGroup *> > m_meshChartGroups;
bool m_chartsComputed;
};
@@ -7599,15 +7976,17 @@ private:
namespace pack {
-class AtlasImage {
+class AtlasImage
+{
public:
- AtlasImage(uint32_t width, uint32_t height) :
- m_width(width), m_height(height) {
+ AtlasImage(uint32_t width, uint32_t height) : m_width(width), m_height(height)
+ {
m_data.resize(m_width * m_height);
memset(m_data.data(), 0, sizeof(uint32_t) * m_data.size());
}
- void resize(uint32_t width, uint32_t height) {
+ void resize(uint32_t width, uint32_t height)
+ {
Array<uint32_t> data;
data.resize(width * height);
memset(data.data(), 0, sizeof(uint32_t) * data.size());
@@ -7618,7 +7997,8 @@ public:
data.moveTo(m_data);
}
- void addChart(uint32_t chartIndex, const BitImage *image, const BitImage *imageBilinear, const BitImage *imagePadding, int atlas_w, int atlas_h, int offset_x, int offset_y) {
+ void addChart(uint32_t chartIndex, const BitImage *image, const BitImage *imageBilinear, const BitImage *imagePadding, int atlas_w, int atlas_h, int offset_x, int offset_y)
+ {
const int w = image->width();
const int h = image->height();
for (int y = 0; y < h; y++) {
@@ -7644,13 +8024,15 @@ public:
}
}
- void copyTo(uint32_t *dest, uint32_t destWidth, uint32_t destHeight, int padding) const {
+ void copyTo(uint32_t *dest, uint32_t destWidth, uint32_t destHeight, int padding) const
+ {
for (uint32_t y = 0; y < destHeight; y++)
memcpy(&dest[y * destWidth], &m_data[padding + (y + padding) * m_width], destWidth * sizeof(uint32_t));
}
#if XA_DEBUG_EXPORT_ATLAS_IMAGES
- void writeTga(const char *filename, uint32_t width, uint32_t height) const {
+ void writeTga(const char *filename, uint32_t width, uint32_t height) const
+ {
Array<uint8_t> image;
image.resize(width * height * 3);
for (uint32_t y = 0; y < height; y++) {
@@ -7692,7 +8074,8 @@ private:
Array<uint32_t> m_data;
};
-struct Chart {
+struct Chart
+{
int32_t atlasIndex;
uint32_t material;
ConstArrayView<uint32_t> indices;
@@ -7711,12 +8094,14 @@ struct Chart {
uint32_t uniqueVertexCount() const { return uniqueVertices.isEmpty() ? vertices.length : uniqueVertices.size(); }
};
-struct AddChartTaskArgs {
+struct AddChartTaskArgs
+{
param::Chart *paramChart;
Chart *chart; // out
};
-static void runAddChartTask(void *groupUserData, void *taskUserData) {
+static void runAddChartTask(void *groupUserData, void *taskUserData)
+{
XA_PROFILE_START(packChartsAddChartsThread)
auto boundingBox = (ThreadLocal<BoundingBox2D> *)groupUserData;
auto args = (AddChartTaskArgs *)taskUserData;
@@ -7753,8 +8138,10 @@ static void runAddChartTask(void *groupUserData, void *taskUserData) {
XA_PROFILE_END(packChartsAddChartsThread)
}
-struct Atlas {
- ~Atlas() {
+struct Atlas
+{
+ ~Atlas()
+ {
for (uint32_t i = 0; i < m_atlasImages.size(); i++) {
m_atlasImages[i]->~AtlasImage();
XA_FREE(m_atlasImages[i]);
@@ -7778,7 +8165,8 @@ struct Atlas {
const Array<AtlasImage *> &getImages() const { return m_atlasImages; }
float getUtilization(uint32_t atlas) const { return m_utilization[atlas]; }
- void addCharts(TaskScheduler *taskScheduler, param::Atlas *paramAtlas) {
+ void addCharts(TaskScheduler *taskScheduler, param::Atlas *paramAtlas)
+ {
// Count charts.
uint32_t chartCount = 0;
for (uint32_t i = 0; i < paramAtlas->meshCount(); i++) {
@@ -7819,7 +8207,8 @@ struct Atlas {
m_charts[i] = taskArgs[i].chart;
}
- void addUvMeshCharts(UvMeshInstance *mesh) {
+ void addUvMeshCharts(UvMeshInstance *mesh)
+ {
// Copy texcoords from mesh.
mesh->texcoords.resize(mesh->mesh->texcoords.size());
memcpy(mesh->texcoords.data(), mesh->mesh->texcoords.data(), mesh->texcoords.size() * sizeof(Vector2));
@@ -7882,7 +8271,8 @@ struct Atlas {
}
// Pack charts in the smallest possible rectangle.
- bool packCharts(const PackOptions &options, ProgressFunc progressFunc, void *progressUserData) {
+ bool packCharts(const PackOptions &options, ProgressFunc progressFunc, void *progressUserData)
+ {
if (progressFunc) {
if (!progressFunc(ProgressCategory::PackCharts, 0, progressUserData))
return false;
@@ -8116,7 +8506,8 @@ struct Atlas {
int best_x = 0, best_y = 0;
int best_cw = 0, best_ch = 0;
int best_r = 0;
- for (;;) {
+ for (;;)
+ {
#if XA_DEBUG
bool firstChartInBitImage = false;
#endif
@@ -8152,7 +8543,8 @@ struct Atlas {
if (best_x + best_cw > atlasSizes[currentAtlas].x || best_y + best_ch > atlasSizes[currentAtlas].y) {
for (uint32_t j = 0; j < chartStartPositions.size(); j++)
chartStartPositions[j] = Vector2i(0, 0);
- } else {
+ }
+ else {
chartStartPositions[currentAtlas] = Vector2i(best_x, best_y);
}
}
@@ -8240,7 +8632,8 @@ struct Atlas {
}
if (m_utilization.size() > 1) {
XA_PRINT(" %u: %f%% utilization\n", i, m_utilization[i] * 100.0f);
- } else {
+ }
+ else {
XA_PRINT(" %f%% utilization\n", m_utilization[i] * 100.0f);
}
}
@@ -8259,14 +8652,16 @@ struct Atlas {
}
private:
- bool findChartLocation(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution) {
+ bool findChartLocation(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution)
+ {
const int attempts = 4096;
if (options.bruteForce || attempts >= w * h)
return findChartLocation_bruteForce(options, startPosition, atlasBitImage, chartBitImage, chartBitImageRotated, w, h, best_x, best_y, best_w, best_h, best_r, maxResolution);
return findChartLocation_random(options, atlasBitImage, chartBitImage, chartBitImageRotated, w, h, best_x, best_y, best_w, best_h, best_r, attempts, maxResolution);
}
- bool findChartLocation_bruteForce(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution) {
+ bool findChartLocation_bruteForce(const PackOptions &options, const Vector2i &startPosition, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, uint32_t maxResolution)
+ {
const int stepSize = options.blockAlign ? 4 : 1;
int best_metric = INT_MAX;
// Try two different orientations.
@@ -8311,7 +8706,8 @@ private:
return best_metric != INT_MAX;
}
- bool findChartLocation_random(const PackOptions &options, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int attempts, uint32_t maxResolution) {
+ bool findChartLocation_random(const PackOptions &options, const BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int w, int h, int *best_x, int *best_y, int *best_w, int *best_h, int *best_r, int attempts, uint32_t maxResolution)
+ {
bool result = false;
const int BLOCK_SIZE = 4;
int best_metric = INT_MAX;
@@ -8366,7 +8762,8 @@ private:
return result;
}
- void addChart(BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int atlas_w, int atlas_h, int offset_x, int offset_y, int r) {
+ void addChart(BitImage *atlasBitImage, const BitImage *chartBitImage, const BitImage *chartBitImageRotated, int atlas_w, int atlas_h, int offset_x, int offset_y, int r)
+ {
XA_DEBUG_ASSERT(r == 0 || r == 1);
const BitImage *image = r == 0 ? chartBitImage : chartBitImageRotated;
const int w = image->width();
@@ -8389,7 +8786,8 @@ private:
}
}
- void bilinearExpand(const Chart *chart, BitImage *source, BitImage *dest, BitImage *destRotated, UniformGrid2 &boundaryEdgeGrid) const {
+ void bilinearExpand(const Chart *chart, BitImage *source, BitImage *dest, BitImage *destRotated, UniformGrid2 &boundaryEdgeGrid) const
+ {
boundaryEdgeGrid.reset(chart->vertices, chart->indices);
if (chart->boundaryEdges) {
const uint32_t edgeCount = chart->boundaryEdges->size();
@@ -8444,11 +8842,13 @@ private:
}
}
- struct DrawTriangleCallbackArgs {
+ struct DrawTriangleCallbackArgs
+ {
BitImage *chartBitImage, *chartBitImageRotated;
};
- static bool drawTriangleCallback(void *param, int x, int y) {
+ static bool drawTriangleCallback(void *param, int x, int y)
+ {
auto args = (DrawTriangleCallbackArgs *)param;
args->chartBitImage->set(x, y);
if (args->chartBitImageRotated)
@@ -8471,13 +8871,15 @@ private:
} // namespace internal
// Used to map triangulated polygons back to polygons.
-struct MeshPolygonMapping {
+struct MeshPolygonMapping
+{
internal::Array<uint8_t> faceVertexCount; // Copied from MeshDecl::faceVertexCount.
internal::Array<uint32_t> triangleToPolygonMap; // Triangle index (mesh face index) to polygon index.
internal::Array<uint32_t> triangleToPolygonIndicesMap; // Triangle indices to polygon indices.
};
-struct Context {
+struct Context
+{
Atlas atlas;
internal::Progress *addMeshProgress = nullptr;
internal::TaskGroupHandle addMeshTaskGroup;
@@ -8492,14 +8894,16 @@ struct Context {
bool uvMeshChartsComputed = false;
};
-Atlas *Create() {
+Atlas *Create()
+{
Context *ctx = XA_NEW(internal::MemTag::Default, Context);
memset(&ctx->atlas, 0, sizeof(Atlas));
ctx->taskScheduler = XA_NEW(internal::MemTag::Default, internal::TaskScheduler);
return &ctx->atlas;
}
-static void DestroyOutputMeshes(Context *ctx) {
+static void DestroyOutputMeshes(Context *ctx)
+{
if (!ctx->atlas.meshes)
return;
for (int i = 0; i < (int)ctx->atlas.meshCount; i++) {
@@ -8520,7 +8924,8 @@ static void DestroyOutputMeshes(Context *ctx) {
ctx->atlas.meshes = nullptr;
}
-void Destroy(Atlas *atlas) {
+void Destroy(Atlas *atlas)
+{
XA_DEBUG_ASSERT(atlas);
Context *ctx = (Context *)atlas;
if (atlas->utilization)
@@ -8567,14 +8972,15 @@ void Destroy(Atlas *atlas) {
#endif
}
-static void runAddMeshTask(void *groupUserData, void *taskUserData) {
+static void runAddMeshTask(void *groupUserData, void *taskUserData)
+{
XA_PROFILE_START(addMeshThread)
auto ctx = (Context *)groupUserData;
auto mesh = (internal::Mesh *)taskUserData;
internal::Progress *progress = ctx->addMeshProgress;
if (progress->cancel) {
XA_PROFILE_END(addMeshThread)
- return;
+ return;
}
XA_PROFILE_START(addMeshCreateColocals)
mesh->createColocals();
@@ -8587,32 +8993,37 @@ static void runAddMeshTask(void *groupUserData, void *taskUserData) {
XA_PROFILE_END(addMeshThread)
}
-static internal::Vector3 DecodePosition(const MeshDecl &meshDecl, uint32_t index) {
+static internal::Vector3 DecodePosition(const MeshDecl &meshDecl, uint32_t index)
+{
XA_DEBUG_ASSERT(meshDecl.vertexPositionData);
XA_DEBUG_ASSERT(meshDecl.vertexPositionStride > 0);
return *((const internal::Vector3 *)&((const uint8_t *)meshDecl.vertexPositionData)[meshDecl.vertexPositionStride * index]);
}
-static internal::Vector3 DecodeNormal(const MeshDecl &meshDecl, uint32_t index) {
+static internal::Vector3 DecodeNormal(const MeshDecl &meshDecl, uint32_t index)
+{
XA_DEBUG_ASSERT(meshDecl.vertexNormalData);
XA_DEBUG_ASSERT(meshDecl.vertexNormalStride > 0);
return *((const internal::Vector3 *)&((const uint8_t *)meshDecl.vertexNormalData)[meshDecl.vertexNormalStride * index]);
}
-static internal::Vector2 DecodeUv(const MeshDecl &meshDecl, uint32_t index) {
+static internal::Vector2 DecodeUv(const MeshDecl &meshDecl, uint32_t index)
+{
XA_DEBUG_ASSERT(meshDecl.vertexUvData);
XA_DEBUG_ASSERT(meshDecl.vertexUvStride > 0);
return *((const internal::Vector2 *)&((const uint8_t *)meshDecl.vertexUvData)[meshDecl.vertexUvStride * index]);
}
-static uint32_t DecodeIndex(IndexFormat format, const void *indexData, int32_t offset, uint32_t i) {
+static uint32_t DecodeIndex(IndexFormat format, const void *indexData, int32_t offset, uint32_t i)
+{
XA_DEBUG_ASSERT(indexData);
if (format == IndexFormat::UInt16)
return uint16_t((int32_t)((const uint16_t *)indexData)[i] + offset);
return uint32_t((int32_t)((const uint32_t *)indexData)[i] + offset);
}
-AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint) {
+AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint)
+{
XA_DEBUG_ASSERT(atlas);
if (!atlas) {
XA_PRINT_WARNING("AddMesh: atlas is null.\n");
@@ -8630,7 +9041,8 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
// Don't know how many times AddMesh will be called, so progress needs to adjusted each time.
if (!ctx->addMeshProgress) {
ctx->addMeshProgress = XA_NEW_ARGS(internal::MemTag::Default, internal::Progress, ProgressCategory::AddMesh, ctx->progressFunc, ctx->progressUserData, 1);
- } else {
+ }
+ else {
ctx->addMeshProgress->setMaxValue(internal::max(ctx->meshes.size() + 1, meshCountHint));
}
XA_PROFILE_START(addMeshCopyData)
@@ -8804,7 +9216,8 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
return AddMeshError::Success;
}
-void AddMeshJoin(Atlas *atlas) {
+void AddMeshJoin(Atlas *atlas)
+{
XA_DEBUG_ASSERT(atlas);
if (!atlas) {
XA_PRINT_WARNING("AddMeshJoin: atlas is null.\n");
@@ -8847,7 +9260,8 @@ void AddMeshJoin(Atlas *atlas) {
}
}
-AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl) {
+AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl)
+{
XA_DEBUG_ASSERT(atlas);
if (!atlas) {
XA_PRINT_WARNING("AddUvMesh: atlas is null.\n");
@@ -8948,7 +9362,8 @@ AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl) {
return AddMeshError::Success;
}
-void ComputeCharts(Atlas *atlas, ChartOptions options) {
+void ComputeCharts(Atlas *atlas, ChartOptions options)
+{
if (!atlas) {
XA_PRINT_WARNING("ComputeCharts: atlas is null.\n");
return;
@@ -9136,7 +9551,8 @@ void ComputeCharts(Atlas *atlas, ChartOptions options) {
XA_PRINT_MEM_USAGE
}
-void PackCharts(Atlas *atlas, PackOptions packOptions) {
+void PackCharts(Atlas *atlas, PackOptions packOptions)
+{
// Validate arguments and context state.
if (!atlas) {
XA_PRINT_WARNING("PackCharts: atlas is null.\n");
@@ -9177,7 +9593,8 @@ void PackCharts(Atlas *atlas, PackOptions packOptions) {
if (!ctx->uvMeshInstances.isEmpty()) {
for (uint32_t i = 0; i < ctx->uvMeshInstances.size(); i++)
packAtlas.addUvMeshCharts(ctx->uvMeshInstances[i]);
- } else
+ }
+ else
packAtlas.addCharts(ctx->taskScheduler, &ctx->paramAtlas);
XA_PROFILE_END(packChartsAddCharts)
XA_PROFILE_START(packCharts)
@@ -9455,7 +9872,8 @@ void PackCharts(Atlas *atlas, PackOptions packOptions) {
XA_PRINT_MEM_USAGE
}
-void Generate(Atlas *atlas, ChartOptions chartOptions, PackOptions packOptions) {
+void Generate(Atlas *atlas, ChartOptions chartOptions, PackOptions packOptions)
+{
if (!atlas) {
XA_PRINT_WARNING("Generate: atlas is null.\n");
return;
@@ -9469,7 +9887,8 @@ void Generate(Atlas *atlas, ChartOptions chartOptions, PackOptions packOptions)
PackCharts(atlas, packOptions);
}
-void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc, void *progressUserData) {
+void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc, void *progressUserData)
+{
if (!atlas) {
XA_PRINT_WARNING("SetProgressCallback: atlas is null.\n");
return;
@@ -9479,17 +9898,20 @@ void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc, void *progress
ctx->progressUserData = progressUserData;
}
-void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc) {
+void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc)
+{
internal::s_realloc = reallocFunc;
internal::s_free = freeFunc;
}
-void SetPrint(PrintFunc print, bool verbose) {
+void SetPrint(PrintFunc print, bool verbose)
+{
internal::s_print = print;
internal::s_printVerbose = verbose;
}
-const char *StringForEnum(AddMeshError error) {
+const char *StringForEnum(AddMeshError error)
+{
if (error == AddMeshError::Error)
return "Unspecified error";
if (error == AddMeshError::IndexOutOfRange)
@@ -9501,7 +9923,8 @@ const char *StringForEnum(AddMeshError error) {
return "Success";
}
-const char *StringForEnum(ProgressCategory category) {
+const char *StringForEnum(ProgressCategory category)
+{
if (category == ProgressCategory::AddMesh)
return "Adding mesh(es)";
if (category == ProgressCategory::ComputeCharts)
@@ -9529,76 +9952,93 @@ static_assert(sizeof(xatlas::PackOptions) == sizeof(xatlasPackOptions), "xatlasP
extern "C" {
#endif
-xatlasAtlas *xatlasCreate() {
+xatlasAtlas *xatlasCreate()
+{
return (xatlasAtlas *)xatlas::Create();
}
-void xatlasDestroy(xatlasAtlas *atlas) {
+void xatlasDestroy(xatlasAtlas *atlas)
+{
xatlas::Destroy((xatlas::Atlas *)atlas);
}
-xatlasAddMeshError xatlasAddMesh(xatlasAtlas *atlas, const xatlasMeshDecl *meshDecl, uint32_t meshCountHint) {
+xatlasAddMeshError xatlasAddMesh(xatlasAtlas *atlas, const xatlasMeshDecl *meshDecl, uint32_t meshCountHint)
+{
return (xatlasAddMeshError)xatlas::AddMesh((xatlas::Atlas *)atlas, *(const xatlas::MeshDecl *)meshDecl, meshCountHint);
}
-void xatlasAddMeshJoin(xatlasAtlas *atlas) {
+void xatlasAddMeshJoin(xatlasAtlas *atlas)
+{
xatlas::AddMeshJoin((xatlas::Atlas *)atlas);
}
-xatlasAddMeshError xatlasAddUvMesh(xatlasAtlas *atlas, const xatlasUvMeshDecl *decl) {
+xatlasAddMeshError xatlasAddUvMesh(xatlasAtlas *atlas, const xatlasUvMeshDecl *decl)
+{
return (xatlasAddMeshError)xatlas::AddUvMesh((xatlas::Atlas *)atlas, *(const xatlas::UvMeshDecl *)decl);
}
-void xatlasComputeCharts(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions) {
+void xatlasComputeCharts(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions)
+{
xatlas::ComputeCharts((xatlas::Atlas *)atlas, chartOptions ? *(xatlas::ChartOptions *)chartOptions : xatlas::ChartOptions());
}
-void xatlasPackCharts(xatlasAtlas *atlas, const xatlasPackOptions *packOptions) {
+void xatlasPackCharts(xatlasAtlas *atlas, const xatlasPackOptions *packOptions)
+{
xatlas::PackCharts((xatlas::Atlas *)atlas, packOptions ? *(xatlas::PackOptions *)packOptions : xatlas::PackOptions());
}
-void xatlasGenerate(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions, const xatlasPackOptions *packOptions) {
+void xatlasGenerate(xatlasAtlas *atlas, const xatlasChartOptions *chartOptions, const xatlasPackOptions *packOptions)
+{
xatlas::Generate((xatlas::Atlas *)atlas, chartOptions ? *(xatlas::ChartOptions *)chartOptions : xatlas::ChartOptions(), packOptions ? *(xatlas::PackOptions *)packOptions : xatlas::PackOptions());
}
-void xatlasSetProgressCallback(xatlasAtlas *atlas, xatlasProgressFunc progressFunc, void *progressUserData) {
+void xatlasSetProgressCallback(xatlasAtlas *atlas, xatlasProgressFunc progressFunc, void *progressUserData)
+{
xatlas::ProgressFunc pf;
*(void **)&pf = (void *)progressFunc;
xatlas::SetProgressCallback((xatlas::Atlas *)atlas, pf, progressUserData);
}
-void xatlasSetAlloc(xatlasReallocFunc reallocFunc, xatlasFreeFunc freeFunc) {
+void xatlasSetAlloc(xatlasReallocFunc reallocFunc, xatlasFreeFunc freeFunc)
+{
xatlas::SetAlloc((xatlas::ReallocFunc)reallocFunc, (xatlas::FreeFunc)freeFunc);
}
-void xatlasSetPrint(xatlasPrintFunc print, bool verbose) {
+void xatlasSetPrint(xatlasPrintFunc print, bool verbose)
+{
xatlas::SetPrint((xatlas::PrintFunc)print, verbose);
}
-const char *xatlasAddMeshErrorString(xatlasAddMeshError error) {
+const char *xatlasAddMeshErrorString(xatlasAddMeshError error)
+{
return xatlas::StringForEnum((xatlas::AddMeshError)error);
}
-const char *xatlasProgressCategoryString(xatlasProgressCategory category) {
+const char *xatlasProgressCategoryString(xatlasProgressCategory category)
+{
return xatlas::StringForEnum((xatlas::ProgressCategory)category);
}
-void xatlasMeshDeclInit(xatlasMeshDecl *meshDecl) {
+void xatlasMeshDeclInit(xatlasMeshDecl *meshDecl)
+{
xatlas::MeshDecl init;
memcpy(meshDecl, &init, sizeof(init));
}
-void xatlasUvMeshDeclInit(xatlasUvMeshDecl *uvMeshDecl) {
+void xatlasUvMeshDeclInit(xatlasUvMeshDecl *uvMeshDecl)
+{
xatlas::UvMeshDecl init;
memcpy(uvMeshDecl, &init, sizeof(init));
}
-void xatlasChartOptionsInit(xatlasChartOptions *chartOptions) {
+void xatlasChartOptionsInit(xatlasChartOptions *chartOptions)
+{
xatlas::ChartOptions init;
memcpy(chartOptions, &init, sizeof(init));
}
-void xatlasPackOptionsInit(xatlasPackOptions *packOptions) {
+void xatlasPackOptionsInit(xatlasPackOptions *packOptions)
+{
xatlas::PackOptions init;
memcpy(packOptions, &init, sizeof(init));
}
diff --git a/thirdparty/xatlas/xatlas.h b/thirdparty/xatlas/xatlas.h
index fc40d9d49c..d66a96db21 100644
--- a/thirdparty/xatlas/xatlas.h
+++ b/thirdparty/xatlas/xatlas.h
@@ -36,7 +36,8 @@ Copyright NVIDIA Corporation 2006 -- Ignacio Castano <icastano@nvidia.com>
namespace xatlas {
-enum class ChartType {
+enum class ChartType
+{
Planar,
Ortho,
LSCM,
@@ -45,7 +46,8 @@ enum class ChartType {
};
// A group of connected faces, belonging to a single atlas.
-struct Chart {
+struct Chart
+{
uint32_t *faceArray;
uint32_t atlasIndex; // Sub-atlas index.
uint32_t faceCount;
@@ -54,7 +56,8 @@ struct Chart {
};
// Output vertex.
-struct Vertex {
+struct Vertex
+{
int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas.
int32_t chartIndex; // -1 if the vertex doesn't exist in any chart.
float uv[2]; // Not normalized - values are in Atlas width and height range.
@@ -62,7 +65,8 @@ struct Vertex {
};
// Output mesh.
-struct Mesh {
+struct Mesh
+{
Chart *chartArray;
uint32_t *indexArray;
Vertex *vertexArray;
@@ -77,7 +81,8 @@ static const uint32_t kImageIsBilinearBit = 0x40000000;
static const uint32_t kImageIsPaddingBit = 0x20000000;
// Empty on creation. Populated after charts are packed.
-struct Atlas {
+struct Atlas
+{
uint32_t *image;
Mesh *meshes; // The output meshes, corresponding to each AddMesh call.
float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length.
@@ -94,13 +99,15 @@ Atlas *Create();
void Destroy(Atlas *atlas);
-enum class IndexFormat {
+enum class IndexFormat
+{
UInt16,
UInt32
};
// Input mesh declaration.
-struct MeshDecl {
+struct MeshDecl
+{
const void *vertexPositionData = nullptr;
const void *vertexNormalData = nullptr; // optional
const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
@@ -131,7 +138,8 @@ struct MeshDecl {
float epsilon = 1.192092896e-07F;
};
-enum class AddMeshError {
+enum class AddMeshError
+{
Success, // No error.
Error, // Unspecified error.
IndexOutOfRange, // An index is >= MeshDecl vertexCount.
@@ -145,7 +153,8 @@ AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountH
// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally.
void AddMeshJoin(Atlas *atlas);
-struct UvMeshDecl {
+struct UvMeshDecl
+{
const void *vertexUvData = nullptr;
const void *indexData = nullptr; // optional
const uint32_t *faceMaterialData = nullptr; // Optional. Overlapping UVs should be assigned a different material. Must be indexCount / 3 in length.
@@ -161,7 +170,8 @@ AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl);
// Custom parameterization function. texcoords initial values are an orthogonal parameterization.
typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount);
-struct ChartOptions {
+struct ChartOptions
+{
ParameterizeFunc paramFunc = nullptr;
float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit.
@@ -184,7 +194,8 @@ struct ChartOptions {
// Call after all AddMesh calls. Can be called multiple times to recompute charts with different options.
void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions());
-struct PackOptions {
+struct PackOptions
+{
// Charts larger than this will be scaled down. 0 means no limit.
uint32_t maxChartSize = 0;
@@ -227,7 +238,8 @@ void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions());
void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), PackOptions packOptions = PackOptions());
// Progress tracking.
-enum class ProgressCategory {
+enum class ProgressCategory
+{
AddMesh,
ComputeCharts,
PackCharts,