1 | /* |
2 | MIT License |
3 | |
4 | Copyright (c) 2018-2020 Jonathan Young |
5 | |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | of this software and associated documentation files (the "Software"), to deal |
8 | in the Software without restriction, including without limitation the rights |
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | copies of the Software, and to permit persons to whom the Software is |
11 | furnished to do so, subject to the following conditions: |
12 | |
13 | The above copyright notice and this permission notice shall be included in all |
14 | copies or substantial portions of the Software. |
15 | |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
22 | SOFTWARE. |
23 | */ |
24 | /* |
25 | thekla_atlas |
26 | MIT License |
27 | https://github.com/Thekla/thekla_atlas |
28 | Copyright (c) 2013 Thekla, Inc |
29 | Copyright NVIDIA Corporation 2006 -- Ignacio Castano <icastano@nvidia.com> |
30 | */ |
31 | #pragma once |
32 | #ifndef XATLAS_H |
33 | #define XATLAS_H |
34 | #include <stddef.h> |
35 | #include <stdint.h> |
36 | |
37 | namespace xatlas { |
38 | |
39 | enum class ChartType |
40 | { |
41 | Planar, |
42 | Ortho, |
43 | LSCM, |
44 | Piecewise, |
45 | Invalid |
46 | }; |
47 | |
48 | // A group of connected faces, belonging to a single atlas. |
49 | struct Chart |
50 | { |
51 | uint32_t *faceArray; |
52 | uint32_t atlasIndex; // Sub-atlas index. |
53 | uint32_t faceCount; |
54 | ChartType type; |
55 | uint32_t material; |
56 | }; |
57 | |
58 | // Output vertex. |
59 | struct Vertex |
60 | { |
61 | int32_t atlasIndex; // Sub-atlas index. -1 if the vertex doesn't exist in any atlas. |
62 | int32_t chartIndex; // -1 if the vertex doesn't exist in any chart. |
63 | float uv[2]; // Not normalized - values are in Atlas width and height range. |
64 | uint32_t xref; // Index of input vertex from which this output vertex originated. |
65 | }; |
66 | |
67 | // Output mesh. |
68 | struct Mesh |
69 | { |
70 | Chart *chartArray; |
71 | uint32_t *indexArray; |
72 | Vertex *vertexArray; |
73 | uint32_t chartCount; |
74 | uint32_t indexCount; |
75 | uint32_t vertexCount; |
76 | }; |
77 | |
78 | static const uint32_t kImageChartIndexMask = 0x1FFFFFFF; |
79 | static const uint32_t kImageHasChartIndexBit = 0x80000000; |
80 | static const uint32_t kImageIsBilinearBit = 0x40000000; |
81 | static const uint32_t kImageIsPaddingBit = 0x20000000; |
82 | |
83 | // Empty on creation. Populated after charts are packed. |
84 | struct Atlas |
85 | { |
86 | uint32_t *image; |
87 | Mesh *meshes; // The output meshes, corresponding to each AddMesh call. |
88 | float *utilization; // Normalized atlas texel utilization array. E.g. a value of 0.8 means 20% empty space. atlasCount in length. |
89 | uint32_t width; // Atlas width in texels. |
90 | uint32_t height; // Atlas height in texels. |
91 | uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0). |
92 | uint32_t chartCount; // Total number of charts in all meshes. |
93 | uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called. |
94 | float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution. |
95 | }; |
96 | |
97 | // Create an empty atlas. |
98 | Atlas *Create(); |
99 | |
100 | void Destroy(Atlas *atlas); |
101 | |
102 | enum class IndexFormat |
103 | { |
104 | UInt16, |
105 | UInt32 |
106 | }; |
107 | |
108 | // Input mesh declaration. |
109 | struct MeshDecl |
110 | { |
111 | const void *vertexPositionData = nullptr; |
112 | const void *vertexNormalData = nullptr; // optional |
113 | const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator. |
114 | const void *indexData = nullptr; // optional |
115 | |
116 | // Optional. Must be faceCount in length. |
117 | // 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. |
118 | const bool *faceIgnoreData = nullptr; |
119 | |
120 | // Optional. Must be faceCount in length. |
121 | // Only faces with the same material will be assigned to the same chart. |
122 | const uint32_t *faceMaterialData = nullptr; |
123 | |
124 | // Optional. Must be faceCount in length. |
125 | // Polygon / n-gon support. Faces are assumed to be triangles if this is null. |
126 | const uint8_t *faceVertexCount = nullptr; |
127 | |
128 | uint32_t vertexCount = 0; |
129 | uint32_t vertexPositionStride = 0; |
130 | uint32_t vertexNormalStride = 0; // optional |
131 | uint32_t vertexUvStride = 0; // optional |
132 | uint32_t indexCount = 0; |
133 | int32_t indexOffset = 0; // optional. Add this offset to all indices. |
134 | uint32_t faceCount = 0; // Optional if faceVertexCount is null. Otherwise assumed to be indexCount / 3. |
135 | IndexFormat indexFormat = IndexFormat::UInt16; |
136 | |
137 | // Vertex positions within epsilon distance of each other are considered colocal. |
138 | float epsilon = 1.192092896e-07F; |
139 | }; |
140 | |
141 | enum class AddMeshError |
142 | { |
143 | Success, // No error. |
144 | Error, // Unspecified error. |
145 | IndexOutOfRange, // An index is >= MeshDecl vertexCount. |
146 | InvalidFaceVertexCount, // Must be >= 3. |
147 | InvalidIndexCount // Not evenly divisible by 3 - expecting triangles. |
148 | }; |
149 | |
150 | // Add a mesh to the atlas. MeshDecl data is copied, so it can be freed after AddMesh returns. |
151 | AddMeshError AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint = 0); |
152 | |
153 | // Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally. |
154 | void AddMeshJoin(Atlas *atlas); |
155 | |
156 | struct UvMeshDecl |
157 | { |
158 | const void *vertexUvData = nullptr; |
159 | const void *indexData = nullptr; // optional |
160 | const uint32_t *faceMaterialData = nullptr; // Optional. Overlapping UVs should be assigned a different material. Must be indexCount / 3 in length. |
161 | uint32_t vertexCount = 0; |
162 | uint32_t vertexStride = 0; |
163 | uint32_t indexCount = 0; |
164 | int32_t indexOffset = 0; // optional. Add this offset to all indices. |
165 | IndexFormat indexFormat = IndexFormat::UInt16; |
166 | }; |
167 | |
168 | AddMeshError AddUvMesh(Atlas *atlas, const UvMeshDecl &decl); |
169 | |
170 | // Custom parameterization function. texcoords initial values are an orthogonal parameterization. |
171 | typedef void (*ParameterizeFunc)(const float *positions, float *texcoords, uint32_t vertexCount, const uint32_t *indices, uint32_t indexCount); |
172 | |
173 | struct ChartOptions |
174 | { |
175 | ParameterizeFunc paramFunc = nullptr; |
176 | |
177 | float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit. |
178 | float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit. |
179 | |
180 | // Weights determine chart growth. Higher weights mean higher cost for that metric. |
181 | float normalDeviationWeight = 2.0f; // Angle between face and average chart normal. |
182 | float roundnessWeight = 0.01f; |
183 | float straightnessWeight = 6.0f; |
184 | float normalSeamWeight = 4.0f; // If > 1000, normal seams are fully respected. |
185 | float textureSeamWeight = 0.5f; |
186 | |
187 | float maxCost = 2.0f; // If total of all metrics * weights > maxCost, don't grow chart. Lower values result in more charts. |
188 | uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts. |
189 | |
190 | bool useInputMeshUvs = false; // Use MeshDecl::vertexUvData for charts. |
191 | bool fixWinding = false; // Enforce consistent texture coordinate winding. |
192 | }; |
193 | |
194 | // Call after all AddMesh calls. Can be called multiple times to recompute charts with different options. |
195 | void ComputeCharts(Atlas *atlas, ChartOptions options = ChartOptions()); |
196 | |
197 | struct PackOptions |
198 | { |
199 | // Charts larger than this will be scaled down. 0 means no limit. |
200 | uint32_t maxChartSize = 0; |
201 | |
202 | // Number of pixels to pad charts with. |
203 | uint32_t padding = 0; |
204 | |
205 | // Unit to texel scale. e.g. a 1x1 quad with texelsPerUnit of 32 will take up approximately 32x32 texels in the atlas. |
206 | // If 0, an estimated value will be calculated to approximately match the given resolution. |
207 | // If resolution is also 0, the estimated value will approximately match a 1024x1024 atlas. |
208 | float texelsPerUnit = 0.0f; |
209 | |
210 | // If 0, generate a single atlas with texelsPerUnit determining the final resolution. |
211 | // If not 0, and texelsPerUnit is not 0, generate one or more atlases with that exact resolution. |
212 | // If not 0, and texelsPerUnit is 0, texelsPerUnit is estimated to approximately match the resolution. |
213 | uint32_t resolution = 0; |
214 | |
215 | // Leave space around charts for texels that would be sampled by bilinear filtering. |
216 | bool bilinear = true; |
217 | |
218 | // Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider. |
219 | bool blockAlign = false; |
220 | |
221 | // Slower, but gives the best result. If false, use random chart placement. |
222 | bool bruteForce = false; |
223 | |
224 | // Create Atlas::image |
225 | bool createImage = false; |
226 | |
227 | // Rotate charts to the axis of their convex hull. |
228 | bool rotateChartsToAxis = true; |
229 | |
230 | // Rotate charts to improve packing. |
231 | bool rotateCharts = true; |
232 | }; |
233 | |
234 | // Call after ComputeCharts. Can be called multiple times to re-pack charts with different options. |
235 | void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions()); |
236 | |
237 | // Equivalent to calling ComputeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options. |
238 | void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), PackOptions packOptions = PackOptions()); |
239 | |
240 | // Progress tracking. |
241 | enum class ProgressCategory |
242 | { |
243 | AddMesh, |
244 | ComputeCharts, |
245 | PackCharts, |
246 | BuildOutputMeshes |
247 | }; |
248 | |
249 | // May be called from any thread. Return false to cancel. |
250 | typedef bool (*ProgressFunc)(ProgressCategory category, int progress, void *userData); |
251 | |
252 | void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr); |
253 | |
254 | // Custom memory allocation. |
255 | typedef void *(*ReallocFunc)(void *, size_t); |
256 | typedef void (*FreeFunc)(void *); |
257 | void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc = nullptr); |
258 | |
259 | // Custom print function. |
260 | typedef int (*PrintFunc)(const char *, ...); |
261 | void SetPrint(PrintFunc print, bool verbose); |
262 | |
263 | // Helper functions for error messages. |
264 | const char *StringForEnum(AddMeshError error); |
265 | const char *StringForEnum(ProgressCategory category); |
266 | |
267 | } // namespace xatlas |
268 | |
269 | #endif // XATLAS_H |
270 | |