├── README.md ├── main.cpp ├── xatlas.cpp ├── xatlas.cs └── xatlas.h /README.md: -------------------------------------------------------------------------------- 1 | # xatlasLib 2 | xatlas wrapper used by Bakery (https://geom.io/bakery/wiki/index.php?title=Bakery_-_GPU_Lightmapper) 3 | 4 | This is a simple DLL interface for xatlas: https://github.com/jpcy/xatlas 5 | 6 | Additionally it also adds a "singleChart" option to AddUvMesh to allow packing existing UV layouts without re-arranging them. 7 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "xatlas.h" 2 | #include 3 | #include 4 | 5 | extern "C" 6 | { 7 | _declspec(dllexport) void* _cdecl xatlasCreateAtlas() 8 | { 9 | return (void*)xatlas::Create(); 10 | } 11 | 12 | _declspec(dllexport) int _cdecl xatlasAddMesh(void* atlas, 13 | int vertexCount, float* positions, float* normals, float* uv, 14 | int indexCount, unsigned int* indices32) 15 | { 16 | xatlas::MeshDecl decl; 17 | decl.vertexCount = vertexCount; 18 | decl.vertexPositionData = (void*)positions; 19 | decl.vertexPositionStride = sizeof(float) * 3; 20 | decl.vertexNormalData = (void*)normals; 21 | decl.vertexNormalStride = sizeof(float) * 3; 22 | decl.vertexUvData = uv; 23 | if (uv != 0) decl.vertexUvStride = sizeof(float) * 2; 24 | decl.indexCount = indexCount; 25 | decl.indexData = (void*)indices32; 26 | decl.indexFormat = xatlas::IndexFormat::UInt32; 27 | xatlas::AddMeshError::Enum err = xatlas::AddMesh((xatlas::Atlas*)atlas, decl); 28 | if (err == xatlas::AddMeshError::IndexOutOfRange) 29 | { 30 | return 1; 31 | } 32 | else if (err == xatlas::AddMeshError::InvalidIndexCount) 33 | { 34 | return 2; 35 | } 36 | return 0; 37 | } 38 | 39 | _declspec(dllexport) int _cdecl xatlasAddUVMesh(void* atlas, 40 | int vertexCount, float* uv, int indexCount, unsigned int* indices32, bool allowRotate) 41 | { 42 | xatlas::UvMeshDecl decl; 43 | memset(&decl, 0, sizeof(decl)); 44 | decl.vertexCount = vertexCount; 45 | decl.vertexUvData = uv; 46 | decl.vertexStride = sizeof(float) * 2; 47 | decl.indexCount = indexCount; 48 | decl.indexData = (void*)indices32; 49 | decl.indexFormat = xatlas::IndexFormat::UInt32; 50 | decl.rotateCharts = allowRotate; 51 | decl.singleChart = true; 52 | xatlas::AddMeshError::Enum err = xatlas::AddUvMesh((xatlas::Atlas*)atlas, decl); 53 | if (err == xatlas::AddMeshError::IndexOutOfRange) 54 | { 55 | return 1; 56 | } 57 | else if (err == xatlas::AddMeshError::InvalidIndexCount) 58 | { 59 | return 2; 60 | } 61 | return 0; 62 | } 63 | 64 | _declspec(dllexport) void _cdecl xatlasParametrize(void* atlas) 65 | { 66 | xatlas::ChartOptions options; 67 | xatlas::ComputeCharts((xatlas::Atlas*)atlas, options); 68 | xatlas::ParameterizeCharts((xatlas::Atlas*)atlas); 69 | } 70 | 71 | _declspec(dllexport) void _cdecl xatlasPack(void* atlas, int attempts, float texelsPerUnit, int resolution, 72 | int maxChartSize, int padding, bool bruteForce, bool blockAlign) 73 | { 74 | xatlas::PackOptions options; 75 | //options.attempts = attempts; 76 | options.texelsPerUnit = texelsPerUnit; 77 | options.resolution = resolution; 78 | options.maxChartSize = maxChartSize; 79 | options.blockAlign = blockAlign; 80 | //options.conservative = true; 81 | options.bruteForce = bruteForce; 82 | options.padding = padding; 83 | 84 | xatlas::PackCharts((xatlas::Atlas*)atlas, options); 85 | } 86 | 87 | _declspec(dllexport) int _cdecl xatlasGetAtlasCount(void* atlas) 88 | { 89 | xatlas::Atlas* a = (xatlas::Atlas*)atlas; 90 | return a->atlasCount; 91 | } 92 | 93 | _declspec(dllexport) int _cdecl xatlasGetAtlasIndex(void* atlas, int meshIndex, int chartIndex) 94 | { 95 | xatlas::Atlas* a = (xatlas::Atlas*)atlas; 96 | if (a->meshCount <= meshIndex) return 0; 97 | return a->meshes[meshIndex].chartArray[chartIndex].atlasIndex; 98 | } 99 | 100 | _declspec(dllexport) int _cdecl xatlasGetVertexCount(void* atlas, int meshIndex) 101 | { 102 | xatlas::Atlas* a = (xatlas::Atlas*)atlas; 103 | if (a->meshCount <= meshIndex) return 0; 104 | return a->meshes[meshIndex].vertexCount; 105 | } 106 | 107 | _declspec(dllexport) int _cdecl xatlasGetIndexCount(void* atlas, int meshIndex) 108 | { 109 | xatlas::Atlas* a = (xatlas::Atlas*)atlas; 110 | if (a->meshCount <= meshIndex) return 0; 111 | return a->meshes[meshIndex].indexCount; 112 | } 113 | 114 | struct MinMax2D 115 | { 116 | float minu, minv, maxu, maxv; 117 | float invLenU, invLenV; 118 | 119 | MinMax2D() 120 | { 121 | minu = FLT_MAX; 122 | minv = FLT_MAX; 123 | maxu = -FLT_MAX; 124 | maxv = -FLT_MAX; 125 | } 126 | }; 127 | 128 | unsigned long nextPowerOfTwo(unsigned long v) 129 | { 130 | v--; 131 | v |= v >> 1; 132 | v |= v >> 2; 133 | v |= v >> 4; 134 | v |= v >> 8; 135 | v |= v >> 16; 136 | v++; 137 | return v; 138 | 139 | } 140 | _declspec(dllexport) void _cdecl xatlasNormalize(void* atlas, int* atlasSizes, bool preferDensity) 141 | { 142 | xatlas::Atlas* a = (xatlas::Atlas*)atlas; 143 | 144 | int atlasCount = xatlasGetAtlasCount(atlas); 145 | if (atlasCount == 0) return; 146 | 147 | MinMax2D* bounds = new MinMax2D[atlasCount]; 148 | 149 | for (int meshIndex = 0; meshIndex < a->meshCount; meshIndex++) 150 | { 151 | int atlasIndex = 0; 152 | if (a->meshes[meshIndex].chartCount > 0) 153 | { 154 | atlasIndex = a->meshes[meshIndex].chartArray[0].atlasIndex; 155 | } 156 | xatlas::Vertex* verts = a->meshes[meshIndex].vertexArray; 157 | int numVerts = a->meshes[meshIndex].vertexCount; 158 | for (int i = 0; i < numVerts; i++) 159 | { 160 | float u = verts[i].uv[0]; 161 | float v = verts[i].uv[1]; 162 | if (u < bounds[atlasIndex].minu) bounds[atlasIndex].minu = u; 163 | if (u > bounds[atlasIndex].maxu) bounds[atlasIndex].maxu = u; 164 | if (v < bounds[atlasIndex].minv) bounds[atlasIndex].minv = v; 165 | if (v > bounds[atlasIndex].maxv) bounds[atlasIndex].maxv = v; 166 | } 167 | } 168 | if (atlasSizes != NULL) 169 | { 170 | for (int i = 0; i < atlasCount; i++) 171 | { 172 | float pwidth = bounds[i].maxu - bounds[i].minu; 173 | float pheight = bounds[i].maxv - bounds[i].minv; 174 | float psize = fmax(pwidth, pheight); 175 | unsigned long size = nextPowerOfTwo((unsigned long)psize); 176 | 177 | if (preferDensity) size = max(a->width, a->height); 178 | 179 | size = max(size, 16); 180 | size = min(size, max(a->width, a->height)); 181 | atlasSizes[i] = (int)size; 182 | 183 | if (preferDensity) 184 | { 185 | bounds[i].maxu = size; 186 | bounds[i].maxv = size; 187 | } 188 | } 189 | } 190 | for (int i = 0; i < atlasCount; i++) 191 | { 192 | if (preferDensity) 193 | { 194 | bounds[i].invLenU = 1.0f / (bounds[i].maxu); 195 | bounds[i].invLenV = 1.0f / (bounds[i].maxv); 196 | } 197 | else 198 | { 199 | bounds[i].invLenU = 1.0f / (bounds[i].maxu - bounds[i].minu); 200 | bounds[i].invLenV = 1.0f / (bounds[i].maxv - bounds[i].minv); 201 | } 202 | } 203 | for (int meshIndex = 0; meshIndex < a->meshCount; meshIndex++) 204 | { 205 | int atlasIndex = 0; 206 | if (a->meshes[meshIndex].chartCount > 0) 207 | { 208 | atlasIndex = a->meshes[meshIndex].chartArray[0].atlasIndex; 209 | } 210 | xatlas::Vertex* verts = a->meshes[meshIndex].vertexArray; 211 | int numVerts = a->meshes[meshIndex].vertexCount; 212 | for (int i = 0; i < numVerts; i++) 213 | { 214 | verts[i].uv[0] = (verts[i].uv[0] - bounds[atlasIndex].minu) * bounds[atlasIndex].invLenU; 215 | verts[i].uv[1] = (verts[i].uv[1] - bounds[atlasIndex].minv) * bounds[atlasIndex].invLenV; 216 | } 217 | } 218 | 219 | delete[] bounds; 220 | } 221 | 222 | _declspec(dllexport) void _cdecl xatlasGetData(void* atlas, int meshIndex, float* outUV, int* outRef, int* outIndices) 223 | { 224 | xatlas::Atlas* a = (xatlas::Atlas*)atlas; 225 | if (a->meshCount <= meshIndex) return; 226 | 227 | xatlas::Vertex* verts = a->meshes[meshIndex].vertexArray; 228 | int numVerts = a->meshes[meshIndex].vertexCount; 229 | 230 | for (int i = 0; i < numVerts; i++) 231 | { 232 | outUV[i * 2] = verts[i].uv[0]; 233 | outUV[i * 2 + 1] = verts[i].uv[1]; 234 | 235 | outRef[i] = verts[i].xref; 236 | } 237 | 238 | uint32_t* indices = a->meshes[meshIndex].indexArray; 239 | int numIndices = a->meshes[meshIndex].indexCount; 240 | for (int i = 0; i < numIndices; i++) 241 | { 242 | outIndices[i] = indices[i]; 243 | } 244 | } 245 | 246 | _declspec(dllexport) void _cdecl xatlasClear(void* atlas) 247 | { 248 | xatlas::Destroy((xatlas::Atlas*)atlas); 249 | } 250 | } 251 | 252 | -------------------------------------------------------------------------------- /xatlas.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEditor; 3 | using UnityEditor.SceneManagement; 4 | using System.Collections.Generic; 5 | using System.Runtime.InteropServices; 6 | 7 | public class xatlas 8 | { 9 | //#define UV_HINT 10 | 11 | public static List newUVBuffer; 12 | public static List newXrefBuffer; 13 | 14 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 15 | public static extern System.IntPtr xatlasCreateAtlas(); 16 | 17 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 18 | public static extern int xatlasAddMesh(System.IntPtr atlas, int vertexCount, System.IntPtr positions, System.IntPtr normals, System.IntPtr uv, int indexCount, int[] indices32); 19 | 20 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 21 | public static extern int xatlasAddUVMesh(System.IntPtr atlas, int vertexCount, System.IntPtr uv, int indexCount, int[] indices32, bool allowRotate); 22 | 23 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 24 | public static extern void xatlasParametrize(System.IntPtr atlas); 25 | 26 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 27 | public static extern void xatlasPack(System.IntPtr atlas, int attempts, float texelsPerUnit, int resolution, int maxChartSize, int padding, bool bruteForce);//, bool allowRotate); 28 | 29 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 30 | public static extern void xatlasNormalize(System.IntPtr atlas, int[] atlasSizes); 31 | 32 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 33 | public static extern int xatlasGetAtlasCount(System.IntPtr atlas); 34 | 35 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 36 | public static extern int xatlasGetAtlasIndex(System.IntPtr atlas, int meshIndex, int chartIndex); 37 | 38 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 39 | public static extern int xatlasGetVertexCount(System.IntPtr atlas, int meshIndex); 40 | 41 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 42 | public static extern int xatlasGetIndexCount(System.IntPtr atlas, int meshIndex); 43 | 44 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 45 | public static extern void xatlasGetData(System.IntPtr atlas, int meshIndex, System.IntPtr outUV, System.IntPtr outRef, System.IntPtr outIndices); 46 | 47 | [DllImport ("xatlasLib", CallingConvention=CallingConvention.Cdecl)] 48 | public static extern int xatlasClear(System.IntPtr atlas); 49 | 50 | static T[] FillAtrribute(List xrefArray, T[] origArray) 51 | { 52 | if (origArray == null || origArray.Length == 0) return origArray; 53 | 54 | var arr = new T[xrefArray.Count]; 55 | for(int i=0; i(); 138 | 139 | newUVBuffer = new List(); 140 | newXrefBuffer = new List(); 141 | while(newUVBuffer.Count < m.vertexCount) 142 | { 143 | newUVBuffer.Add(new Vector2(-100, -100)); 144 | newXrefBuffer.Add(0); 145 | } 146 | 147 | xatlasNormalize(atlas, null); 148 | 149 | // Collect UVs/xrefs/indices 150 | for(int i=0; ifinal index mappings 180 | var xatlasIndexToNewIndex = new int[newVertCount]; 181 | for(int j=0; j= 65000;//0xFFFF; 222 | if (is32bit && origIs16bit) 223 | { 224 | Debug.LogError("Unwrap failed: original mesh (" + m.name + ") has 16 bit indices, but unwrapped requires 32 bit."); 225 | return; 226 | } 227 | 228 | // Duplicate attributes 229 | //if (newXrefBuffer.Count > m.vertexCount) // commented because can be also swapped around 230 | { 231 | m.vertices = FillAtrribute(newXrefBuffer, positions); 232 | m.normals = FillAtrribute(newXrefBuffer, normals); 233 | m.boneWeights = FillAtrribute(newXrefBuffer, m.boneWeights); 234 | m.colors32 = FillAtrribute(newXrefBuffer, m.colors32); 235 | m.tangents = FillAtrribute(newXrefBuffer, m.tangents); 236 | m.uv = FillAtrribute(newXrefBuffer, m.uv); 237 | m.uv3 = FillAtrribute(newXrefBuffer, m.uv3); 238 | m.uv4 = FillAtrribute(newXrefBuffer, m.uv4); 239 | #if UNITY_2018_2_OR_NEWER 240 | m.uv5 = FillAtrribute(newXrefBuffer, m.uv5); 241 | m.uv6 = FillAtrribute(newXrefBuffer, m.uv6); 242 | m.uv7 = FillAtrribute(newXrefBuffer, m.uv7); 243 | m.uv8 = FillAtrribute(newXrefBuffer, m.uv8); 244 | #endif 245 | } 246 | 247 | m.uv2 = newUVBuffer.ToArray(); 248 | 249 | 250 | // Set indices 251 | for(int i=0; i 30 | */ 31 | #pragma once 32 | #ifndef XATLAS_H 33 | #define XATLAS_H 34 | #include 35 | 36 | namespace xatlas { 37 | 38 | struct ChartType 39 | { 40 | enum Enum 41 | { 42 | Planar, 43 | Ortho, 44 | LSCM, 45 | Piecewise, 46 | Invalid 47 | }; 48 | }; 49 | 50 | // A group of connected faces, belonging to a single atlas. 51 | struct Chart 52 | { 53 | uint32_t *faceArray; 54 | uint32_t atlasIndex; // Sub-atlas index. 55 | uint32_t faceCount; 56 | ChartType::Enum type; 57 | uint32_t material; 58 | }; 59 | 60 | // Output vertex. 61 | struct Vertex 62 | { 63 | int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas. 64 | int32_t chartIndex; // -1 if the vertex doesn't exist in any chart. 65 | float uv[2]; // Not normalized - values are in Atlas width and height range. 66 | uint32_t xref; // Index of input vertex from which this output vertex originated. 67 | }; 68 | 69 | // Output mesh. 70 | struct Mesh 71 | { 72 | Chart *chartArray; 73 | uint32_t *indexArray; 74 | Vertex *vertexArray; 75 | uint32_t chartCount; 76 | uint32_t indexCount; 77 | uint32_t vertexCount; 78 | }; 79 | 80 | static const uint32_t kImageChartIndexMask = 0x1FFFFFFF; 81 | static const uint32_t kImageHasChartIndexBit = 0x80000000; 82 | static const uint32_t kImageIsBilinearBit = 0x40000000; 83 | static const uint32_t kImageIsPaddingBit = 0x20000000; 84 | 85 | // Empty on creation. Populated after charts are packed. 86 | struct Atlas 87 | { 88 | uint32_t *image; 89 | Mesh *meshes; // The output meshes, corresponding to each AddMesh call. 90 | uint32_t width; // Atlas width in texels. 91 | uint32_t height; // Atlas height in texels. 92 | uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0). 93 | uint32_t chartCount; // Total number of charts in all meshes. 94 | uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called. 95 | float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length. 96 | float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution. 97 | }; 98 | 99 | // Create an empty atlas. 100 | Atlas *Create(); 101 | 102 | void Destroy(Atlas *atlas); 103 | 104 | struct IndexFormat 105 | { 106 | enum Enum 107 | { 108 | UInt16, 109 | UInt32 110 | }; 111 | }; 112 | 113 | // Input mesh declaration. 114 | struct MeshDecl 115 | { 116 | const void *vertexPositionData = nullptr; 117 | const void *vertexNormalData = nullptr; // optional 118 | const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator. 119 | const void *indexData = nullptr; // optional 120 | 121 | // Optional. indexCount / 3 (triangle count) in length. 122 | // Don't atlas faces set to true. Ignored faces still exist in the output meshes, Vertex uv is set to (0, 0) and Vertex atlasIndex to -1. 123 | const bool *faceIgnoreData = nullptr; 124 | 125 | uint32_t vertexCount = 0; 126 | uint32_t vertexPositionStride = 0; 127 | uint32_t vertexNormalStride = 0; // optional 128 | uint32_t vertexUvStride = 0; // optional 129 | uint32_t indexCount = 0; 130 | int32_t indexOffset = 0; // optional. Add this offset to all indices. 131 | IndexFormat::Enum indexFormat = IndexFormat::UInt16; 132 | 133 | // Vertex positions within epsilon distance of each other are considered colocal. 134 | float epsilon = 1.192092896e-07F; 135 | }; 136 | 137 | struct AddMeshError 138 | { 139 | enum Enum 140 | { 141 | Success, // No error. 142 | Error, // Unspecified error. 143 | IndexOutOfRange, // An index is >= MeshDecl vertexCount. 144 | InvalidIndexCount // Not evenly divisible by 3 - expecting triangles. 145 | }; 146 | }; 147 | 148 | // Add a mesh to the atlas. MeshDecl data is copied, so it can be freed after AddMesh returns. 149 | AddMeshError::Enum AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint = 0); 150 | 151 | // Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally. 152 | void AddMeshJoin(Atlas *atlas); 153 | 154 | struct UvMeshDecl 155 | { 156 | const void *vertexUvData = nullptr; 157 | const void *indexData = nullptr; // optional 158 | const uint32_t *faceMaterialData = nullptr; // Optional. Faces with different materials won't be assigned to the same chart. Must be indexCount / 3 in length. 159 | uint32_t vertexCount = 0; 160 | uint32_t vertexStride = 0; 161 | uint32_t indexCount = 0; 162 | int32_t indexOffset = 0; // optional. Add this offset to all indices. 163 | IndexFormat::Enum indexFormat = IndexFormat::UInt16; 164 | bool rotateCharts = true; 165 | bool singleChart = false; // MRF 166 | }; 167 | 168 | AddMeshError::Enum AddUvMesh(Atlas *atlas, const UvMeshDecl &decl); 169 | 170 | struct ChartOptions 171 | { 172 | float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit. 173 | float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit. 174 | 175 | // Weights determine chart growth. Higher weights mean higher cost for that metric. 176 | float proxyFitMetricWeight = 2.0f; // Angle between face and average chart normal. 177 | float roundnessMetricWeight = 0.01f; 178 | float straightnessMetricWeight = 6.0f; 179 | float normalSeamMetricWeight = 4.0f; // If > 1000, normal seams are fully respected. 180 | float textureSeamMetricWeight = 0.5f; 181 | 182 | float maxThreshold = 2.0f; // If total of all metrics * weights > maxThreshold, don't grow chart. Lower values result in more charts. 183 | uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts. 184 | }; 185 | 186 | // Call after all AddMesh calls. Can be called multiple times to recompute charts with different options. 187 | void ComputeCharts(Atlas *atlas, ChartOptions chartOptions = ChartOptions()); 188 | 189 | // Custom parameterization function. texcoords initial values are an orthogonal parameterization. 190 | typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount); 191 | 192 | // Call after ComputeCharts. Can be called multiple times to re-parameterize charts with a different ParameterizeFunc. 193 | void ParameterizeCharts(Atlas *atlas, ParameterizeFunc func = nullptr); 194 | 195 | struct PackOptions 196 | { 197 | // Leave space around charts for texels that would be sampled by bilinear filtering. 198 | bool bilinear = true; 199 | 200 | // Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider. 201 | bool blockAlign = false; 202 | 203 | // Slower, but gives the best result. If false, use random chart placement. 204 | bool bruteForce = false; 205 | 206 | // Create Atlas::image 207 | bool createImage = false; 208 | 209 | // Charts larger than this will be scaled down. 0 means no limit. 210 | uint32_t maxChartSize = 0; 211 | 212 | // Number of pixels to pad charts with. 213 | uint32_t padding = 0; 214 | 215 | // Unit to texel scale. e.g. a 1x1 quad with texelsPerUnit of 32 will take up approximately 32x32 texels in the atlas. 216 | // If 0, an estimated value will be calculated to approximately match the given resolution. 217 | // If resolution is also 0, the estimated value will approximately match a 1024x1024 atlas. 218 | float texelsPerUnit = 0.0f; 219 | 220 | // If 0, generate a single atlas with texelsPerUnit determining the final resolution. 221 | // If not 0, and texelsPerUnit is not 0, generate one or more atlases with that exact resolution. 222 | // If not 0, and texelsPerUnit is 0, texelsPerUnit is estimated to approximately match the resolution. 223 | uint32_t resolution = 0; 224 | 225 | // MRF 226 | //bool rotateCharts = true; 227 | }; 228 | 229 | // Call after ParameterizeCharts. Can be called multiple times to re-pack charts with different options. 230 | void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions()); 231 | 232 | // Equivalent to calling ComputeCharts, ParameterizeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options. 233 | void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), ParameterizeFunc paramFunc = nullptr, PackOptions packOptions = PackOptions()); 234 | 235 | // Progress tracking. 236 | struct ProgressCategory 237 | { 238 | enum Enum 239 | { 240 | AddMesh, 241 | ComputeCharts, 242 | ParameterizeCharts, 243 | PackCharts, 244 | BuildOutputMeshes 245 | }; 246 | }; 247 | 248 | // May be called from any thread. Return false to cancel. 249 | typedef bool (*ProgressFunc)(ProgressCategory::Enum category, int progress, void *userData); 250 | 251 | void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr); 252 | 253 | // Custom memory allocation. 254 | typedef void *(*ReallocFunc)(void *, size_t); 255 | typedef void (*FreeFunc)(void *); 256 | void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc = nullptr); 257 | 258 | // Custom print function. 259 | typedef int (*PrintFunc)(const char *, ...); 260 | void SetPrint(PrintFunc print, bool verbose); 261 | 262 | // Helper functions for error messages. 263 | const char *StringForEnum(AddMeshError::Enum error); 264 | const char *StringForEnum(ProgressCategory::Enum category); 265 | 266 | } // namespace xatlas 267 | 268 | #endif // XATLAS_H 269 | --------------------------------------------------------------------------------