#include "xatlas.h"
#ifndef XATLAS_C_API
#define XATLAS_C_API …
#endif
#if XATLAS_C_API
#include "xatlas_c.h"
#endif
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <assert.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#define __STDC_LIMIT_MACROS
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifndef XA_DEBUG
#ifdef NDEBUG
#define XA_DEBUG …
#else
#define XA_DEBUG …
#endif
#endif
#ifndef XA_PROFILE
#define XA_PROFILE …
#endif
#if XA_PROFILE
#include <chrono>
#endif
#ifndef XA_MULTITHREADED
#define XA_MULTITHREADED …
#endif
#define XA_STR(x) …
#define XA_XSTR(x) …
#ifndef XA_ASSERT
#define XA_ASSERT(exp) …
#endif
#ifndef XA_DEBUG_ASSERT
#define XA_DEBUG_ASSERT(exp) …
#endif
#ifndef XA_PRINT
#define XA_PRINT(...) …
#endif
#ifndef XA_PRINT_WARNING
#define XA_PRINT_WARNING(...) …
#endif
#define XA_ALLOC(tag, type) …
#define XA_ALLOC_ARRAY(tag, type, num) …
#define XA_REALLOC(tag, ptr, type, num) …
#define XA_REALLOC_SIZE(tag, ptr, size) …
#define XA_FREE(ptr) …
#define XA_NEW(tag, type) …
#define XA_NEW_ARGS(tag, type, ...) …
#ifdef _MSC_VER
#define XA_INLINE …
#else
#define XA_INLINE …
#endif
#if defined(__clang__) || defined(__GNUC__)
#define XA_NODISCARD …
#elif defined(_MSC_VER)
#define XA_NODISCARD …
#else
#define XA_NODISCARD
#endif
#define XA_UNUSED(a) …
#define XA_MERGE_CHARTS …
#define XA_MERGE_CHARTS_MIN_NORMAL_DEVIATION …
#define XA_RECOMPUTE_CHARTS …
#define XA_CHECK_PARAM_WINDING …
#define XA_CHECK_PIECEWISE_CHART_QUALITY …
#define XA_CHECK_T_JUNCTIONS …
#define XA_DEBUG_HEAP …
#define XA_DEBUG_SINGLE_CHART …
#define XA_DEBUG_ALL_CHARTS_INVALID …
#define XA_DEBUG_EXPORT_ATLAS_IMAGES …
#define XA_DEBUG_EXPORT_ATLAS_IMAGES_PER_CHART …
#define XA_DEBUG_EXPORT_BOUNDARY_GRID …
#define XA_DEBUG_EXPORT_TGA …
#define XA_DEBUG_EXPORT_OBJ_FACE_GROUPS …
#define XA_DEBUG_EXPORT_OBJ_CHART_GROUPS …
#define XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS …
#define XA_DEBUG_EXPORT_OBJ_CHARTS …
#define XA_DEBUG_EXPORT_OBJ_TJUNCTION …
#define XA_DEBUG_EXPORT_OBJ_CHARTS_AFTER_PARAMETERIZATION …
#define XA_DEBUG_EXPORT_OBJ_INVALID_PARAMETERIZATION …
#define XA_DEBUG_EXPORT_OBJ_RECOMPUTED_CHARTS …
#define XA_DEBUG_EXPORT_OBJ …
#ifdef _MSC_VER
#define XA_FOPEN …
#define XA_SPRINTF …
#else
#define XA_FOPEN(_file, _filename, _mode) …
#define XA_SPRINTF(_buffer, _size, _format, ...) …
#endif
namespace xatlas {
namespace internal {
static ReallocFunc s_realloc = …;
static FreeFunc s_free = …;
static PrintFunc s_print = …;
static bool s_printVerbose = …;
#if XA_PROFILE
typedef uint64_t Duration;
#define XA_PROFILE_START …
#define XA_PROFILE_END …
#define XA_PROFILE_PRINT_AND_RESET …
#define XA_PROFILE_ALLOC …
struct ProfileData
{
#if XA_PROFILE_ALLOC
std::atomic<Duration> alloc;
#endif
std::chrono::time_point<std::chrono::high_resolution_clock> addMeshRealStart;
Duration addMeshReal;
Duration addMeshCopyData;
std::atomic<Duration> addMeshThread;
std::atomic<Duration> addMeshCreateColocals;
Duration computeChartsReal;
std::atomic<Duration> computeChartsThread;
std::atomic<Duration> createFaceGroups;
std::atomic<Duration> extractInvalidMeshGeometry;
std::atomic<Duration> chartGroupComputeChartsReal;
std::atomic<Duration> chartGroupComputeChartsThread;
std::atomic<Duration> createChartGroupMesh;
std::atomic<Duration> createChartGroupMeshColocals;
std::atomic<Duration> createChartGroupMeshBoundaries;
std::atomic<Duration> buildAtlas;
std::atomic<Duration> buildAtlasInit;
std::atomic<Duration> planarCharts;
std::atomic<Duration> originalUvCharts;
std::atomic<Duration> clusteredCharts;
std::atomic<Duration> clusteredChartsPlaceSeeds;
std::atomic<Duration> clusteredChartsPlaceSeedsBoundaryIntersection;
std::atomic<Duration> clusteredChartsRelocateSeeds;
std::atomic<Duration> clusteredChartsReset;
std::atomic<Duration> clusteredChartsGrow;
std::atomic<Duration> clusteredChartsGrowBoundaryIntersection;
std::atomic<Duration> clusteredChartsMerge;
std::atomic<Duration> clusteredChartsFillHoles;
std::atomic<Duration> copyChartFaces;
std::atomic<Duration> createChartMeshAndParameterizeReal;
std::atomic<Duration> createChartMeshAndParameterizeThread;
std::atomic<Duration> createChartMesh;
std::atomic<Duration> parameterizeCharts;
std::atomic<Duration> parameterizeChartsOrthogonal;
std::atomic<Duration> parameterizeChartsLSCM;
std::atomic<Duration> parameterizeChartsRecompute;
std::atomic<Duration> parameterizeChartsPiecewise;
std::atomic<Duration> parameterizeChartsPiecewiseBoundaryIntersection;
std::atomic<Duration> parameterizeChartsEvaluateQuality;
Duration packCharts;
Duration packChartsAddCharts;
std::atomic<Duration> packChartsAddChartsThread;
std::atomic<Duration> packChartsAddChartsRestoreTexcoords;
Duration packChartsRasterize;
Duration packChartsDilate;
Duration packChartsFindLocation;
Duration packChartsBlit;
Duration buildOutputMeshes;
};
static ProfileData s_profile;
static double durationToMs(Duration c)
{
return (double)c * 0.001;
}
static double durationToSeconds(Duration c)
{
return (double)c * 0.000001;
}
#else
#define XA_PROFILE_START(var) …
#define XA_PROFILE_END(var) …
#define XA_PROFILE_PRINT_AND_RESET(label, var) …
#define XA_PROFILE_ALLOC …
#endif
struct MemTag
{ … };
#if XA_DEBUG_HEAP
struct AllocHeader
{
size_t size;
const char *file;
int line;
int tag;
uint32_t id;
AllocHeader *prev, *next;
bool free;
};
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 constexpr uint32_t kAllocRedzone = 0x12345678;
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;
uint8_t *realPtr = nullptr;
AllocHeader *header = nullptr;
if (ptr) {
realPtr = ((uint8_t *)ptr) - sizeof(AllocHeader);
header = (AllocHeader *)realPtr;
}
if (realPtr && size) {
s_allocTotalSize -= header->size;
s_allocTotalTagSize[header->tag] -= header->size;
if (header->prev)
header->prev->next = header->next;
else
s_allocRoot = header->next;
if (header->next)
header->next->prev = header->prev;
}
if (!size) {
s_allocTotalSize -= header->size;
s_allocTotalTagSize[header->tag] -= header->size;
XA_ASSERT(!header->free);
header->free = true;
return nullptr;
}
size += sizeof(AllocHeader) + sizeof(kAllocRedzone);
uint8_t *newPtr = (uint8_t *)s_realloc(realPtr, size);
if (!newPtr)
return nullptr;
header = (AllocHeader *)newPtr;
header->size = size;
header->file = file;
header->line = line;
header->tag = tag;
header->id = s_allocId++;
header->free = false;
if (!s_allocRoot) {
s_allocRoot = header;
header->prev = header->next = 0;
} else {
header->prev = nullptr;
header->next = s_allocRoot;
s_allocRoot = header;
header->next->prev = header;
}
s_allocTotalCount++;
s_allocTotalSize += size;
if (s_allocTotalSize > s_allocPeakSize)
s_allocPeakSize = s_allocTotalSize;
s_allocCount[tag]++;
s_allocTotalTagSize[tag] += size;
if (s_allocTotalTagSize[tag] > s_allocPeakTagSize[tag])
s_allocPeakTagSize[tag] = s_allocTotalTagSize[tag];
auto redzone = (uint32_t *)(newPtr + size - sizeof(kAllocRedzone));
*redzone = kAllocRedzone;
return newPtr + sizeof(AllocHeader);
}
static void ReportLeaks()
{
printf("Checking for memory leaks...\n");
bool anyLeaks = false;
AllocHeader *header = s_allocRoot;
while (header) {
if (!header->free) {
printf(" Leak: ID %u, %zu bytes, %s %d\n", header->id, header->size, header->file, header->line);
anyLeaks = true;
}
auto redzone = (const uint32_t *)((const uint8_t *)header + header->size - sizeof(kAllocRedzone));
if (*redzone != kAllocRedzone)
printf(" Redzone corrupted: %zu bytes %s %d\n", header->size, header->file, header->line);
header = header->next;
}
if (!anyLeaks)
printf(" No memory leaks\n");
header = s_allocRoot;
while (header) {
AllocHeader *destroy = header;
header = header->next;
s_realloc(destroy, 0);
}
s_allocRoot = nullptr;
s_allocTotalSize = s_allocPeakSize = 0;
for (int i = 0; i < MemTag::Count; i++)
s_allocTotalTagSize[i] = s_allocPeakTagSize[i] = 0;
}
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[] = {
"Default",
"BitImage",
"BVH",
"Matrix",
"Mesh",
"MeshBoundaries",
"MeshColocals",
"MeshEdgeMap",
"MeshIndices",
"MeshNormals",
"MeshPositions",
"MeshTexcoords",
"OpenNL",
"SegmentAtlasChartCandidates",
"SegmentAtlasChartFaces",
"SegmentAtlasMeshData",
"SegmentAtlasPlanarRegions"
};
for (int i = 0; i < MemTag::Count; i++) {
XA_PRINT(" %s: %zu allocations, %0.2fMB current, %0.2fMB peak\n", labels[i], internal::s_allocCount[i], internal::s_allocTotalTagSize[i] / 1024.0f / 1024.0f, internal::s_allocPeakTagSize[i] / 1024.0f / 1024.0f);
}
}
#define XA_PRINT_MEM_USAGE …
#else
static void *Realloc(void *ptr, size_t size, int , const char * , int )
{ … }
#define XA_PRINT_MEM_USAGE
#endif
static constexpr float kPi = …;
static constexpr float kPi2 = …;
static constexpr float kEpsilon = …;
static constexpr float kAreaEpsilon = …;
static constexpr float kNormalEpsilon = …;
static int align(int x, int a)
{ … }
template <typename T>
static T max(const T &a, const T &b)
{ … }
template <typename T>
static T min(const T &a, const T &b)
{ … }
template <typename T>
static T max3(const T &a, const T &b, const T &c)
{ … }
template <typename T>
static T min3(const T &a, const T &b, const T &c)
{ … }
template <typename T>
static T clamp(const T &x, const T &a, const T &b)
{ … }
template <typename T>
static void swap(T &a, T &b)
{ … }
FloatUint32;
static bool isFinite(float f)
{ … }
static bool isNan(float f)
{ … }
static bool equal(const float f0, const float f1, const float epsilon)
{ … }
static int ftoi_ceil(float val)
{ … }
static bool isZero(const float f, const float epsilon)
{ … }
static float square(float f)
{ … }
static uint32_t nextPowerOfTwo(uint32_t x)
{ … }
class Vector2
{ … };
static bool operator==(const Vector2 &a, const Vector2 &b)
{ … }
static bool operator!=(const Vector2 &a, const Vector2 &b)
{ … }
static Vector2 operator-(const Vector2 &a, const Vector2 &b)
{ … }
static Vector2 operator*(const Vector2 &v, float s)
{ … }
static float dot(const Vector2 &a, const Vector2 &b)
{ … }
static float lengthSquared(const Vector2 &v)
{ … }
static float length(const Vector2 &v)
{ … }
#if XA_DEBUG
static bool isNormalized(const Vector2 &v, float epsilon = kNormalEpsilon)
{
return equal(length(v), 1, epsilon);
}
#endif
static Vector2 normalize(const Vector2 &v)
{ … }
static Vector2 normalizeSafe(const Vector2 &v, const Vector2 &fallback)
{ … }
static bool equal(const Vector2 &v1, const Vector2 &v2, float epsilon)
{ … }
static Vector2 min(const Vector2 &a, const Vector2 &b)
{ … }
static Vector2 max(const Vector2 &a, const Vector2 &b)
{ … }
static bool isFinite(const Vector2 &v)
{ … }
static float triangleArea(const Vector2 &a, const Vector2 &b, const Vector2 &c)
{ … }
static bool linesIntersect(const Vector2 &a1, const Vector2 &a2, const Vector2 &b1, const Vector2 &b2, float epsilon)
{ … }
struct Vector2i
{ … };
class Vector3
{ … };
static Vector3 operator+(const Vector3 &a, const Vector3 &b)
{ … }
static Vector3 operator-(const Vector3 &a, const Vector3 &b)
{ … }
static bool operator==(const Vector3 &a, const Vector3 &b)
{ … }
static Vector3 cross(const Vector3 &a, const Vector3 &b)
{ … }
static Vector3 operator*(const Vector3 &v, float s)
{ … }
static Vector3 operator/(const Vector3 &v, float s)
{ … }
static float dot(const Vector3 &a, const Vector3 &b)
{ … }
static float lengthSquared(const Vector3 &v)
{ … }
static float length(const Vector3 &v)
{ … }
static bool isNormalized(const Vector3 &v, float epsilon = kNormalEpsilon)
{ … }
static Vector3 normalize(const Vector3 &v)
{ … }
static Vector3 normalizeSafe(const Vector3 &v, const Vector3 &fallback)
{ … }
static bool equal(const Vector3 &v0, const Vector3 &v1, float epsilon)
{ … }
static Vector3 min(const Vector3 &a, const Vector3 &b)
{ … }
static Vector3 max(const Vector3 &a, const Vector3 &b)
{ … }
#if XA_DEBUG
bool isFinite(const Vector3 &v)
{
return isFinite(v.x) && isFinite(v.y) && isFinite(v.z);
}
#endif
struct Extents2
{ … };
struct AABB
{ … };
struct ArrayBase
{ … };
template<typename T>
class Array
{ … };
template<typename T>
struct ArrayView
{ … };
template<typename T>
struct ConstArrayView
{ … };
struct Basis
{ … };
class BitArray
{ … };
class BitImage
{ … };
class BVH
{ … };
struct Fit
{ … };
static uint32_t sdbmHash(const void *data_in, uint32_t size, uint32_t h = 5381)
{ … }
template <typename T>
static uint32_t hash(const T &t, uint32_t h = 5381)
{ … }
template <typename Key>
struct Hash
{ … };
template <typename Key>
struct PassthroughHash
{ … };
template <typename Key>
struct Equal
{ … };
template<typename Key, typename H = Hash<Key>, typename E = Equal<Key> >
class HashMap
{ … };
template<typename T>
static void insertionSort(T *data, uint32_t length)
{ … }
class KISSRng
{ … };
class RadixSort
{ … };
class BoundingBox2D
{ … };
struct EdgeKey
{ … };
struct EdgeHash
{ … };
static uint32_t meshEdgeFace(uint32_t edge) { … }
static uint32_t meshEdgeIndex0(uint32_t edge) { … }
static uint32_t meshEdgeIndex1(uint32_t edge)
{ … }
struct MeshFlags
{ … };
class Mesh
{ … };
struct MeshFaceGroups
{ … };
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)
{
float tt;
if (!t)
t = &tt;
*t = 0.0f;
if (equal(lineStart, point, epsilon) || equal(lineEnd, point, epsilon))
return false;
const Vector3 v01 = point - lineStart;
const Vector3 v21 = lineEnd - lineStart;
const float l = length(v21);
const float d = length(cross(v01, v21)) / l;
if (!isZero(d, epsilon))
return false;
*t = dot(v01, v21) / (l * l);
return *t > kEpsilon && *t < 1.0f - kEpsilon;
}
static int meshCheckTJunctions(const Mesh &inputMesh)
{
int count = 0;
const uint32_t vertexCount = inputMesh.vertexCount();
const uint32_t edgeCount = inputMesh.edgeCount();
for (uint32_t v = 0; v < vertexCount; v++) {
if (!inputMesh.isBoundaryVertex(v))
continue;
const Vector3 &pos = inputMesh.position(v);
for (uint32_t e = 0; e < edgeCount; e++) {
if (!inputMesh.isBoundaryEdge(e))
continue;
const Vector3 &edgePos1 = inputMesh.position(inputMesh.vertexAt(meshEdgeIndex0(e)));
const Vector3 &edgePos2 = inputMesh.position(inputMesh.vertexAt(meshEdgeIndex1(e)));
float t;
if (lineIntersectsPoint(pos, edgePos1, edgePos2, &t, inputMesh.epsilon()))
count++;
}
}
return count;
}
#endif
struct InvalidMeshGeometry
{ … };
struct Progress
{ … };
struct Spinlock
{ … };
struct TaskGroupHandle
{ … };
struct Task
{ … };
#if XA_MULTITHREADED
class TaskScheduler
{ … };
thread_local uint32_t TaskScheduler::m_threadIndex;
#else
class TaskScheduler
{
public:
~TaskScheduler()
{
for (uint32_t i = 0; i < m_groups.size(); i++)
destroyGroup({ i });
}
uint32_t threadCount() const
{
return 1;
}
TaskGroupHandle createTaskGroup(void *userData = nullptr, uint32_t reserveSize = 0)
{
TaskGroup *group = XA_NEW(MemTag::Default, TaskGroup);
group->queue.reserve(reserveSize);
group->userData = userData;
m_groups.push_back(group);
TaskGroupHandle handle;
handle.value = m_groups.size() - 1;
return handle;
}
void run(TaskGroupHandle handle, Task task)
{
m_groups[handle.value]->queue.push_back(task);
}
void wait(TaskGroupHandle *handle)
{
if (handle->value == UINT32_MAX) {
XA_DEBUG_ASSERT(false);
return;
}
TaskGroup *group = m_groups[handle->value];
for (uint32_t i = 0; i < group->queue.size(); i++)
group->queue[i].func(group->userData, group->queue[i].userData);
group->queue.clear();
destroyGroup(*handle);
handle->value = UINT32_MAX;
}
static uint32_t currentThreadIndex() { return 0; }
private:
void destroyGroup(TaskGroupHandle handle)
{
TaskGroup *group = m_groups[handle.value];
if (group) {
group->~TaskGroup();
XA_FREE(group);
m_groups[handle.value] = nullptr;
}
}
struct TaskGroup
{
Array<Task> queue;
void *userData;
};
Array<TaskGroup *> m_groups;
};
#endif
#if XA_DEBUG_EXPORT_TGA
const uint8_t TGA_TYPE_RGB = 2;
const uint8_t TGA_ORIGIN_UPPER = 0x20;
#pragma pack(push, 1)
struct TgaHeader
{
uint8_t id_length;
uint8_t colormap_type;
uint8_t image_type;
uint16_t colormap_index;
uint16_t colormap_length;
uint8_t colormap_size;
uint16_t x_origin;
uint16_t y_origin;
uint16_t width;
uint16_t height;
uint8_t pixel_size;
uint8_t flags;
enum { Size = 18 };
};
#pragma pack(pop)
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");
if (!f)
return;
TgaHeader tga;
tga.id_length = 0;
tga.colormap_type = 0;
tga.image_type = TGA_TYPE_RGB;
tga.colormap_index = 0;
tga.colormap_length = 0;
tga.colormap_size = 0;
tga.x_origin = 0;
tga.y_origin = 0;
tga.width = (uint16_t)width;
tga.height = (uint16_t)height;
tga.pixel_size = 24;
tga.flags = TGA_ORIGIN_UPPER;
fwrite(&tga, sizeof(TgaHeader), 1, f);
fwrite(data, sizeof(uint8_t), width * height * 3, f);
fclose(f);
}
#endif
template<typename T>
class ThreadLocal
{ … };
struct Triangulator
{ … };
class UniformGrid2
{ … };
struct UvMeshChart
{ … };
struct UvMesh
{ … };
struct UvMeshInstance
{ … };
namespace opennl {
#define NL_NEW(T) …
#define NL_NEW_ARRAY(T,NB) …
#define NL_RENEW_ARRAY(T,x,NB) …
#define NL_DELETE(x) …
#define NL_DELETE_ARRAY(x) …
#define NL_CLEAR(x, T) …
#define NL_CLEAR_ARRAY(T,x,NB) …
#define NL_NEW_VECTOR(dim) …
#define NL_DELETE_VECTOR(ptr) …
struct NLMatrixStruct;
NLMatrix;
NLDestroyMatrixFunc;
NLMultMatrixVectorFunc;
#define NL_MATRIX_SPARSE_DYNAMIC …
#define NL_MATRIX_CRS …
#define NL_MATRIX_OTHER …
struct NLMatrixStruct
{ … };
struct NLCoeff
{ … };
struct NLRowColumn
{ … };
struct NLCRSMatrix
{ … };
struct NLSparseMatrix
{ … };
struct NLBufferBinding
{ … };
#define NL_BUFFER_ITEM(B,i) …
struct NLContext
{ … };
static void nlDeleteMatrix(NLMatrix M)
{ … }
static void nlMultMatrixVector(NLMatrix M, const double* x, double* y)
{ … }
static void nlRowColumnConstruct(NLRowColumn* c)
{ … }
static void nlRowColumnDestroy(NLRowColumn* c)
{ … }
static void nlRowColumnGrow(NLRowColumn* c)
{ … }
static void nlRowColumnAdd(NLRowColumn* c, uint32_t index, double value)
{ … }
static void nlRowColumnAppend(NLRowColumn* c, uint32_t index, double value)
{ … }
static void nlRowColumnZero(NLRowColumn* c)
{ … }
static void nlRowColumnClear(NLRowColumn* c)
{ … }
static int nlCoeffCompare(const void* p1, const void* p2)
{ … }
static void nlRowColumnSort(NLRowColumn* c)
{ … }
static void nlCRSMatrixDestroy(NLCRSMatrix* M)
{ … }
static void nlCRSMatrixMultSlice(NLCRSMatrix* M, const double* x, double* y, uint32_t Ibegin, uint32_t Iend)
{ … }
static void nlCRSMatrixMult(NLCRSMatrix* M, const double* x, double* y)
{ … }
static void nlCRSMatrixConstruct(NLCRSMatrix* M, uint32_t m, uint32_t n, uint32_t nnz, uint32_t nslices)
{ … }
static void nlSparseMatrixDestroyRowColumns(NLSparseMatrix* M)
{ … }
static void nlSparseMatrixDestroy(NLSparseMatrix* M)
{ … }
static void nlSparseMatrixAdd(NLSparseMatrix* M, uint32_t i, uint32_t j, double value)
{ … }
static uint32_t nlSparseMatrixNNZ(NLSparseMatrix* M)
{ … }
static void nlSparseMatrixSort(NLSparseMatrix* M)
{ … }
static void nlSparseMatrix_mult_rows(NLSparseMatrix* A, const double* x, double* y)
{ … }
static void nlSparseMatrixMult(NLSparseMatrix* A, const double* x, double* y)
{ … }
static void nlSparseMatrixConstruct(NLSparseMatrix* M, uint32_t m, uint32_t n)
{ … }
static NLMatrix nlCRSMatrixNewFromSparseMatrix(NLSparseMatrix* M)
{ … }
static void nlMatrixCompress(NLMatrix* M)
{ … }
static NLContext *nlNewContext()
{ … }
static void nlDeleteContext(NLContext *context)
{ … }
static double ddot(int n, const double *x, const double *y)
{ … }
static void daxpy(int n, double a, const double *x, double *y)
{ … }
static void dscal(int n, double a, double *x)
{ … }
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)
{ … }
static uint32_t nlSolveSystemIterative(NLContext *context, NLMatrix M, NLMatrix P, double* b_in, double* x_in, double eps, uint32_t max_iter)
{ … }
static bool nlSolveIterative(NLContext *context)
{ … }
struct NLJacobiPreconditioner
{ … };
static void nlJacobiPreconditionerDestroy(NLJacobiPreconditioner* M)
{ … }
static void nlJacobiPreconditionerMult(NLJacobiPreconditioner* M, const double* x, double* y)
{ … }
static NLMatrix nlNewJacobiPreconditioner(NLMatrix M_in)
{ … }
#define NL_NB_VARIABLES …
#define NL_MAX_ITERATIONS …
static void nlSolverParameteri(NLContext *context, uint32_t pname, int param)
{ … }
static void nlSetVariable(NLContext *context, uint32_t index, double value)
{ … }
static double nlGetVariable(NLContext *context, uint32_t index)
{ … }
static void nlLockVariable(NLContext *context, uint32_t index)
{ … }
static void nlVariablesToVector(NLContext *context)
{ … }
static void nlVectorToVariables(NLContext *context)
{ … }
static void nlCoefficient(NLContext *context, uint32_t index, double value)
{ … }
#define NL_SYSTEM …
#define NL_MATRIX …
#define NL_ROW …
static void nlBegin(NLContext *context, uint32_t prim)
{ … }
static void nlEnd(NLContext *context, uint32_t prim)
{ … }
static bool nlSolve(NLContext *context)
{ … }
}
namespace raster {
class ClippedTriangle
{ … };
SamplingCallback;
struct Triangle
{ … };
static bool drawTriangle(const Vector2 &extents, const Vector2 v[3], SamplingCallback cb, void *param)
{ … }
}
namespace segment {
struct CostQueue
{ … };
struct AtlasData
{ … };
struct OriginalUvCharts
{ … };
#if XA_DEBUG_EXPORT_OBJ_PLANAR_REGIONS
static uint32_t s_planarRegionsCurrentRegion;
static uint32_t s_planarRegionsCurrentVertex;
#endif
struct PlanarCharts
{ … };
struct ClusteredCharts
{ … };
struct ChartGeneratorType
{ … };
struct Atlas
{ … };
struct ComputeUvMeshChartsTaskArgs
{ … };
struct ComputeUvMeshChartsTask
{ … };
static void runComputeUvMeshChartsTask(void * , void *taskUserData)
{ … }
static bool computeUvMeshCharts(TaskScheduler *taskScheduler, ArrayView<UvMesh *> meshes, ProgressFunc progressFunc, void *progressUserData)
{ … }
}
namespace param {
static bool findApproximateDiameterVertices(Mesh *mesh, uint32_t *a, uint32_t *b)
{ … }
static void projectTriangle(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 *z0, Vector2 *z1, Vector2 *z2)
{ … }
static float vec_angle_cos(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
{ … }
static float vec_angle(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3)
{ … }
static void triangle_angles(const Vector3 &v1, const Vector3 &v2, const Vector3 &v3, float *a1, float *a2, float *a3)
{ … }
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 computeLeastSquaresConformalMap(Mesh *mesh)
{ … }
struct PiecewiseParam
{ … };
struct Quality
{ … };
struct ChartCtorBuffers
{ … };
class Chart
{ … };
struct CreateAndParameterizeChartTaskGroupArgs
{ … };
struct CreateAndParameterizeChartTaskArgs
{ … };
static void runCreateAndParameterizeChartTask(void *groupUserData, void *taskUserData)
{ … }
class ChartGroup
{ … };
struct ChartGroupComputeChartsTaskGroupArgs
{ … };
static void runChartGroupComputeChartsTask(void *groupUserData, void *taskUserData)
{ … }
struct MeshComputeChartsTaskGroupArgs
{ … };
struct MeshComputeChartsTaskArgs
{ … };
#if XA_DEBUG_EXPORT_OBJ_FACE_GROUPS
static uint32_t s_faceGroupsCurrentVertex = 0;
#endif
static void runMeshComputeChartsTask(void *groupUserData, void *taskUserData)
{ … }
class Atlas
{ … };
}
namespace pack {
class AtlasImage
{ … };
struct Chart
{ … };
struct AddChartTaskArgs
{ … };
static void runAddChartTask(void *groupUserData, void *taskUserData)
{ … }
struct Atlas
{ … };
}
}
struct MeshPolygonMapping
{ … };
struct Context
{ … };
Atlas *Create()
{ … }
static void DestroyOutputMeshes(Context *ctx)
{ … }
void Destroy(Atlas *atlas)
{ … }
static void runAddMeshTask(void *groupUserData, void *taskUserData)
{ … }
static internal::Vector3 DecodePosition(const MeshDecl &meshDecl, uint32_t index)
{ … }
static internal::Vector3 DecodeNormal(const MeshDecl &meshDecl, uint32_t index)
{ … }
static internal::Vector2 DecodeUv(const MeshDecl &meshDecl, uint32_t index)
{ … }
static uint32_t DecodeIndex(IndexFormat format, const void *indexData, int32_t offset, uint32_t i)
{ … }
AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint)
{ … }
void AddMeshJoin(Atlas *atlas)
{ … }
AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl)
{ … }
void ComputeCharts(Atlas *atlas, ChartOptions options)
{ … }
void PackCharts(Atlas *atlas, PackOptions packOptions)
{ … }
void Generate(Atlas *atlas, ChartOptions chartOptions, PackOptions packOptions)
{ … }
void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc, void *progressUserData)
{ … }
void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc)
{ … }
void SetPrint(PrintFunc print, bool verbose)
{ … }
const char *StringForEnum(AddMeshError error)
{ … }
const char *StringForEnum(ProgressCategory category)
{ … }
}
#if XATLAS_C_API
static_assert(sizeof(xatlas::Chart) == sizeof(xatlasChart), "xatlasChart size mismatch");
static_assert(sizeof(xatlas::Vertex) == sizeof(xatlasVertex), "xatlasVertex size mismatch");
static_assert(sizeof(xatlas::Mesh) == sizeof(xatlasMesh), "xatlasMesh size mismatch");
static_assert(sizeof(xatlas::Atlas) == sizeof(xatlasAtlas), "xatlasAtlas size mismatch");
static_assert(sizeof(xatlas::MeshDecl) == sizeof(xatlasMeshDecl), "xatlasMeshDecl size mismatch");
static_assert(sizeof(xatlas::UvMeshDecl) == sizeof(xatlasUvMeshDecl), "xatlasUvMeshDecl size mismatch");
static_assert(sizeof(xatlas::ChartOptions) == sizeof(xatlasChartOptions), "xatlasChartOptions size mismatch");
static_assert(sizeof(xatlas::PackOptions) == sizeof(xatlasPackOptions), "xatlasPackOptions size mismatch");
#ifdef __cplusplus
extern "C" {
#endif
xatlasAtlas *xatlasCreate()
{
return (xatlasAtlas *)xatlas::Create();
}
void xatlasDestroy(xatlasAtlas *atlas)
{
xatlas::Destroy((xatlas::Atlas *)atlas);
}
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)
{
xatlas::AddMeshJoin((xatlas::Atlas *)atlas);
}
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)
{
xatlas::ComputeCharts((xatlas::Atlas *)atlas, chartOptions ? *(xatlas::ChartOptions *)chartOptions : xatlas::ChartOptions());
}
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)
{
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)
{
xatlas::ProgressFunc pf;
*(void **)&pf = (void *)progressFunc;
xatlas::SetProgressCallback((xatlas::Atlas *)atlas, pf, progressUserData);
}
void xatlasSetAlloc(xatlasReallocFunc reallocFunc, xatlasFreeFunc freeFunc)
{
xatlas::SetAlloc((xatlas::ReallocFunc)reallocFunc, (xatlas::FreeFunc)freeFunc);
}
void xatlasSetPrint(xatlasPrintFunc print, bool verbose)
{
xatlas::SetPrint((xatlas::PrintFunc)print, verbose);
}
const char *xatlasAddMeshErrorString(xatlasAddMeshError error)
{
return xatlas::StringForEnum((xatlas::AddMeshError)error);
}
const char *xatlasProgressCategoryString(xatlasProgressCategory category)
{
return xatlas::StringForEnum((xatlas::ProgressCategory)category);
}
void xatlasMeshDeclInit(xatlasMeshDecl *meshDecl)
{
xatlas::MeshDecl init;
memcpy(meshDecl, &init, sizeof(init));
}
void xatlasUvMeshDeclInit(xatlasUvMeshDecl *uvMeshDecl)
{
xatlas::UvMeshDecl init;
memcpy(uvMeshDecl, &init, sizeof(init));
}
void xatlasChartOptionsInit(xatlasChartOptions *chartOptions)
{
xatlas::ChartOptions init;
memcpy(chartOptions, &init, sizeof(init));
}
void xatlasPackOptionsInit(xatlasPackOptions *packOptions)
{
xatlas::PackOptions init;
memcpy(packOptions, &init, sizeof(init));
}
#ifdef __cplusplus
}
#endif
#endif