|
@@ -1,176 +1,254 @@
|
|
|
-// This code is in the public domain -- [email protected]
|
|
|
+/*
|
|
|
+MIT License
|
|
|
+
|
|
|
+Copyright (c) 2018-2019 Jonathan Young
|
|
|
+
|
|
|
+Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
+of this software and associated documentation files (the "Software"), to deal
|
|
|
+in the Software without restriction, including without limitation the rights
|
|
|
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
+copies of the Software, and to permit persons to whom the Software is
|
|
|
+furnished to do so, subject to the following conditions:
|
|
|
+
|
|
|
+The above copyright notice and this permission notice shall be included in all
|
|
|
+copies or substantial portions of the Software.
|
|
|
+
|
|
|
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
+SOFTWARE.
|
|
|
+*/
|
|
|
+/*
|
|
|
+thekla_atlas
|
|
|
+MIT License
|
|
|
+https://github.com/Thekla/thekla_atlas
|
|
|
+Copyright (c) 2013 Thekla, Inc
|
|
|
+Copyright NVIDIA Corporation 2006 -- Ignacio Castano <[email protected]>
|
|
|
+*/
|
|
|
#pragma once
|
|
|
#ifndef XATLAS_H
|
|
|
#define XATLAS_H
|
|
|
-#include <float.h> // FLT_MAX
|
|
|
-// -- GODOT start --
|
|
|
-#include <limits.h> // INT_MAX, UINT_MAX
|
|
|
-// -- GODOT end --
|
|
|
+#include <stdint.h>
|
|
|
|
|
|
namespace xatlas {
|
|
|
|
|
|
-typedef void (*PrintFunc)(const char *, ...);
|
|
|
+struct ChartFlags
|
|
|
+{
|
|
|
+ enum
|
|
|
+ {
|
|
|
+ Invalid = 1 << 0
|
|
|
+ };
|
|
|
+};
|
|
|
|
|
|
-struct Atlas;
|
|
|
+// A group of connected faces, belonging to a single atlas.
|
|
|
+struct Chart
|
|
|
+{
|
|
|
+ uint32_t atlasIndex; // Sub-atlas index.
|
|
|
+ uint32_t flags;
|
|
|
+ uint32_t *indexArray;
|
|
|
+ uint32_t indexCount;
|
|
|
+ uint32_t material;
|
|
|
+};
|
|
|
|
|
|
-struct CharterOptions
|
|
|
+// Output vertex.
|
|
|
+struct Vertex
|
|
|
{
|
|
|
- float proxyFitMetricWeight;
|
|
|
- float roundnessMetricWeight;
|
|
|
- float straightnessMetricWeight;
|
|
|
- float normalSeamMetricWeight;
|
|
|
- float textureSeamMetricWeight;
|
|
|
- float maxChartArea;
|
|
|
- float maxBoundaryLength;
|
|
|
-
|
|
|
- CharterOptions()
|
|
|
- {
|
|
|
- // These are the default values we use on The Witness.
|
|
|
- proxyFitMetricWeight = 2.0f;
|
|
|
- roundnessMetricWeight = 0.01f;
|
|
|
- straightnessMetricWeight = 6.0f;
|
|
|
- normalSeamMetricWeight = 4.0f;
|
|
|
- textureSeamMetricWeight = 0.5f;
|
|
|
- /*
|
|
|
- proxyFitMetricWeight = 1.0f;
|
|
|
- roundnessMetricWeight = 0.1f;
|
|
|
- straightnessMetricWeight = 0.25f;
|
|
|
- normalSeamMetricWeight = 1.0f;
|
|
|
- textureSeamMetricWeight = 0.1f;
|
|
|
- */
|
|
|
- maxChartArea = FLT_MAX;
|
|
|
- maxBoundaryLength = FLT_MAX;
|
|
|
- }
|
|
|
+ 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.
|
|
|
+ uint32_t xref; // Index of input vertex from which this output vertex originated.
|
|
|
};
|
|
|
|
|
|
-struct PackMethod
|
|
|
+// Output mesh.
|
|
|
+struct Mesh
|
|
|
{
|
|
|
- enum Enum
|
|
|
- {
|
|
|
- TexelArea, // texel_area determines resolution
|
|
|
- ApproximateResolution, // guess texel_area to approximately match desired resolution
|
|
|
- ExactResolution // run the packer multiple times to exactly match the desired resolution (slow)
|
|
|
- };
|
|
|
+ Chart *chartArray;
|
|
|
+ uint32_t chartCount;
|
|
|
+ uint32_t *indexArray;
|
|
|
+ uint32_t indexCount;
|
|
|
+ Vertex *vertexArray;
|
|
|
+ uint32_t vertexCount;
|
|
|
};
|
|
|
|
|
|
-struct PackerOptions
|
|
|
+static const uint32_t kImageChartIndexMask = 0x3FFFFFFF;
|
|
|
+static const uint32_t kImageHasChartIndexBit = 0x40000000;
|
|
|
+static const uint32_t kImageIsPaddingBit = 0x80000000;
|
|
|
+
|
|
|
+// Empty on creation. Populated after charts are packed.
|
|
|
+struct Atlas
|
|
|
{
|
|
|
- PackMethod::Enum method;
|
|
|
-
|
|
|
- // 0 - brute force
|
|
|
- // 1 - 4096 attempts
|
|
|
- // 2 - 2048
|
|
|
- // 3 - 1024
|
|
|
- // 4 - 512
|
|
|
- // other - 256
|
|
|
- // Avoid brute force packing, since it can be unusably slow in some situations.
|
|
|
- int quality;
|
|
|
-
|
|
|
- float texelArea; // This is not really texel area, but 1 / texel width?
|
|
|
- uint32_t resolution;
|
|
|
- bool blockAlign; // Align charts to 4x4 blocks.
|
|
|
- bool conservative; // Pack charts with extra padding.
|
|
|
- int padding;
|
|
|
-
|
|
|
- PackerOptions()
|
|
|
- {
|
|
|
- method = PackMethod::ApproximateResolution;
|
|
|
- quality = 1;
|
|
|
- texelArea = 8;
|
|
|
- resolution = 512;
|
|
|
- blockAlign = false;
|
|
|
- conservative = false;
|
|
|
- padding = 0;
|
|
|
- }
|
|
|
+ uint32_t width; // Atlas width in texels.
|
|
|
+ uint32_t height; // Atlas height in texels.
|
|
|
+ uint32_t atlasCount; // Number of sub-atlases. Equal to 0 unless PackOptions resolution is changed from default (0).
|
|
|
+ uint32_t chartCount; // Total number of charts in all meshes.
|
|
|
+ uint32_t meshCount; // Number of output meshes. Equal to the number of times AddMesh was called.
|
|
|
+ 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.
|
|
|
+ float texelsPerUnit; // Equal to PackOptions texelsPerUnit if texelsPerUnit > 0, otherwise an estimated value to match PackOptions resolution.
|
|
|
+ uint32_t *image;
|
|
|
};
|
|
|
|
|
|
-struct AddMeshErrorCode
|
|
|
+// Create an empty atlas.
|
|
|
+Atlas *Create();
|
|
|
+
|
|
|
+void Destroy(Atlas *atlas);
|
|
|
+
|
|
|
+struct IndexFormat
|
|
|
{
|
|
|
enum Enum
|
|
|
{
|
|
|
- Success,
|
|
|
- AlreadyAddedEdge, // index0 and index1 are the edge indices
|
|
|
- DegenerateColocalEdge, // index0 and index1 are the edge indices
|
|
|
- DegenerateEdge, // index0 and index1 are the edge indices
|
|
|
- DuplicateEdge, // index0 and index1 are the edge indices
|
|
|
- IndexOutOfRange, // index0 is the index
|
|
|
- InvalidIndexCount, // not evenly divisible by 3 - expecting triangles
|
|
|
- ZeroAreaFace,
|
|
|
- ZeroLengthEdge // index0 and index1 are the edge indices
|
|
|
+ UInt16,
|
|
|
+ UInt32
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-struct AddMeshError
|
|
|
+// Input mesh declaration.
|
|
|
+struct MeshDecl
|
|
|
{
|
|
|
- AddMeshErrorCode::Enum code;
|
|
|
- uint32_t face;
|
|
|
- uint32_t index0, index1;
|
|
|
+ uint32_t vertexCount = 0;
|
|
|
+ const void *vertexPositionData = nullptr;
|
|
|
+ uint32_t vertexPositionStride = 0;
|
|
|
+ const void *vertexNormalData = nullptr; // optional
|
|
|
+ uint32_t vertexNormalStride = 0; // optional
|
|
|
+ const void *vertexUvData = nullptr; // optional. The input UVs are provided as a hint to the chart generator.
|
|
|
+ uint32_t vertexUvStride = 0; // optional
|
|
|
+ uint32_t indexCount = 0;
|
|
|
+ const void *indexData = nullptr; // optional
|
|
|
+ int32_t indexOffset = 0; // optional. Add this offset to all indices.
|
|
|
+ IndexFormat::Enum indexFormat = IndexFormat::UInt16;
|
|
|
+
|
|
|
+ // Optional. indexCount / 3 (triangle count) in length.
|
|
|
+ // 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.
|
|
|
+ const bool *faceIgnoreData = nullptr;
|
|
|
+
|
|
|
+ // Vertex positions within epsilon distance of each other are considered colocal.
|
|
|
+ float epsilon = 1.192092896e-07F;
|
|
|
};
|
|
|
|
|
|
-struct IndexFormat
|
|
|
+struct AddMeshError
|
|
|
{
|
|
|
enum Enum
|
|
|
{
|
|
|
- HalfFloat,
|
|
|
- Float
|
|
|
+ Success, // No error.
|
|
|
+ Error, // Unspecified error.
|
|
|
+ IndexOutOfRange, // An index is >= MeshDecl vertexCount.
|
|
|
+ InvalidIndexCount // Not evenly divisible by 3 - expecting triangles.
|
|
|
};
|
|
|
};
|
|
|
|
|
|
-struct InputMesh
|
|
|
-{
|
|
|
- uint32_t vertexCount;
|
|
|
- const void *vertexPositionData;
|
|
|
- uint32_t vertexPositionStride;
|
|
|
- const void *vertexNormalData; // optional
|
|
|
- uint32_t vertexNormalStride; // optional
|
|
|
-
|
|
|
- // optional
|
|
|
- // The input UVs are provided as a hint to the chart generator.
|
|
|
- const void *vertexUvData;
|
|
|
- uint32_t vertexUvStride;
|
|
|
+// Add a mesh to the atlas. MeshDecl data is copied, so it can be freed after AddMesh returns.
|
|
|
+AddMeshError::Enum AddMesh(Atlas *atlas, const MeshDecl &meshDecl, uint32_t meshCountHint = 0);
|
|
|
|
|
|
- uint32_t indexCount;
|
|
|
- const void *indexData;
|
|
|
- IndexFormat::Enum indexFormat;
|
|
|
+// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally.
|
|
|
+void AddMeshJoin(Atlas *atlas);
|
|
|
|
|
|
- // optional. indexCount / 3 in length.
|
|
|
- // Charter also uses material boundaries as a hint to cut charts.
|
|
|
- const uint16_t *faceMaterialData;
|
|
|
+struct UvMeshDecl
|
|
|
+{
|
|
|
+ uint32_t vertexCount = 0;
|
|
|
+ uint32_t vertexStride = 0;
|
|
|
+ const void *vertexUvData = nullptr;
|
|
|
+ uint32_t indexCount = 0;
|
|
|
+ const void *indexData = nullptr; // optional
|
|
|
+ int32_t indexOffset = 0; // optional. Add this offset to all indices.
|
|
|
+ IndexFormat::Enum indexFormat = IndexFormat::UInt16;
|
|
|
+ const uint32_t *faceMaterialData = nullptr; // Optional. Faces with different materials won't be assigned to the same chart. Must be indexCount / 3 in length.
|
|
|
+ bool rotateCharts = true;
|
|
|
};
|
|
|
|
|
|
-struct OutputChart
|
|
|
+AddMeshError::Enum AddUvMesh(Atlas *atlas, const UvMeshDecl &decl);
|
|
|
+
|
|
|
+struct ChartOptions
|
|
|
{
|
|
|
- uint32_t *indexArray;
|
|
|
- uint32_t indexCount;
|
|
|
+ float maxChartArea = 0.0f; // Don't grow charts to be larger than this. 0 means no limit.
|
|
|
+ float maxBoundaryLength = 0.0f; // Don't grow charts to have a longer boundary than this. 0 means no limit.
|
|
|
+
|
|
|
+ // Weights determine chart growth. Higher weights mean higher cost for that metric.
|
|
|
+ float proxyFitMetricWeight = 2.0f; // Angle between face and average chart normal.
|
|
|
+ float roundnessMetricWeight = 0.01f;
|
|
|
+ float straightnessMetricWeight = 6.0f;
|
|
|
+ float normalSeamMetricWeight = 4.0f; // If > 1000, normal seams are fully respected.
|
|
|
+ float textureSeamMetricWeight = 0.5f;
|
|
|
+
|
|
|
+ float maxThreshold = 2.0f; // If total of all metrics * weights > maxThreshold, don't grow chart. Lower values result in more charts.
|
|
|
+ uint32_t growFaceCount = 32; // Grow this many faces at a time.
|
|
|
+ uint32_t maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts.
|
|
|
};
|
|
|
|
|
|
-struct OutputVertex
|
|
|
+// Call after all AddMesh calls. Can be called multiple times to recompute charts with different options.
|
|
|
+void ComputeCharts(Atlas *atlas, ChartOptions chartOptions = ChartOptions());
|
|
|
+
|
|
|
+// 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);
|
|
|
+
|
|
|
+// Call after ComputeCharts. Can be called multiple times to re-parameterize charts with a different ParameterizeFunc.
|
|
|
+void ParameterizeCharts(Atlas *atlas, ParameterizeFunc func = nullptr);
|
|
|
+
|
|
|
+struct PackOptions
|
|
|
{
|
|
|
- float uv[2];
|
|
|
- uint32_t xref; // Index of input vertex from which this output vertex originated.
|
|
|
+ // Slower, but gives the best result. If false, use random chart placement.
|
|
|
+ bool bruteForce = false;
|
|
|
+
|
|
|
+ // Create Atlas::image
|
|
|
+ bool createImage = false;
|
|
|
+
|
|
|
+ // Unit to texel scale. e.g. a 1x1 quad with texelsPerUnit of 32 will take up approximately 32x32 texels in the atlas.
|
|
|
+ // If 0, an estimated value will be calculated to approximately match the given resolution.
|
|
|
+ // If resolution is also 0, the estimated value will approximately match a 1024x1024 atlas.
|
|
|
+ float texelsPerUnit = 0.0f;
|
|
|
+
|
|
|
+ // If 0, generate a single atlas with texelsPerUnit determining the final resolution.
|
|
|
+ // If not 0, and texelsPerUnit is not 0, generate one or more atlases with that exact resolution.
|
|
|
+ // If not 0, and texelsPerUnit is 0, texelsPerUnit is estimated to approximately match the resolution.
|
|
|
+ uint32_t resolution = 0;
|
|
|
+
|
|
|
+ // Charts larger than this will be scaled down.
|
|
|
+ uint32_t maxChartSize = 1024;
|
|
|
+
|
|
|
+ // Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider.
|
|
|
+ bool blockAlign = false;
|
|
|
+
|
|
|
+ // Number of pixels to pad charts with.
|
|
|
+ uint32_t padding = 0;
|
|
|
};
|
|
|
|
|
|
-struct OutputMesh
|
|
|
+// Call after ParameterizeCharts. Can be called multiple times to re-pack charts with different options.
|
|
|
+void PackCharts(Atlas *atlas, PackOptions packOptions = PackOptions());
|
|
|
+
|
|
|
+// Equivalent to calling ComputeCharts, ParameterizeCharts and PackCharts in sequence. Can be called multiple times to regenerate with different options.
|
|
|
+void Generate(Atlas *atlas, ChartOptions chartOptions = ChartOptions(), ParameterizeFunc paramFunc = nullptr, PackOptions packOptions = PackOptions());
|
|
|
+
|
|
|
+// Progress tracking.
|
|
|
+struct ProgressCategory
|
|
|
{
|
|
|
- OutputChart *chartArray;
|
|
|
- uint32_t chartCount;
|
|
|
- uint32_t *indexArray;
|
|
|
- uint32_t indexCount;
|
|
|
- OutputVertex *vertexArray;
|
|
|
- uint32_t vertexCount;
|
|
|
+ enum Enum
|
|
|
+ {
|
|
|
+ AddMesh,
|
|
|
+ ComputeCharts,
|
|
|
+ ParameterizeCharts,
|
|
|
+ PackCharts,
|
|
|
+ BuildOutputMeshes
|
|
|
+ };
|
|
|
};
|
|
|
|
|
|
-void SetPrint(PrintFunc print);
|
|
|
-Atlas *Create();
|
|
|
-void Destroy(Atlas *atlas);
|
|
|
-// useColocalVertices - generates fewer charts (good), but is more sensitive to bad geometry.
|
|
|
-AddMeshError AddMesh(Atlas *atlas, const InputMesh &mesh, bool useColocalVertices = true);
|
|
|
-void Generate(Atlas *atlas, CharterOptions charterOptions = CharterOptions(), PackerOptions packerOptions = PackerOptions());
|
|
|
-uint32_t GetWidth(const Atlas *atlas);
|
|
|
-uint32_t GetHeight(const Atlas *atlas);
|
|
|
-uint32_t GetNumCharts(const Atlas *atlas);
|
|
|
-const OutputMesh * const *GetOutputMeshes(const Atlas *atlas);
|
|
|
-const char *StringForEnum(AddMeshErrorCode::Enum error);
|
|
|
+// May be called from any thread. Return false to cancel.
|
|
|
+typedef bool (*ProgressFunc)(ProgressCategory::Enum category, int progress, void *userData);
|
|
|
+
|
|
|
+void SetProgressCallback(Atlas *atlas, ProgressFunc progressFunc = nullptr, void *progressUserData = nullptr);
|
|
|
+
|
|
|
+// Custom memory allocation.
|
|
|
+typedef void *(*ReallocFunc)(void *, size_t);
|
|
|
+void SetRealloc(ReallocFunc reallocFunc);
|
|
|
+
|
|
|
+// Custom print function.
|
|
|
+typedef int (*PrintFunc)(const char *, ...);
|
|
|
+void SetPrint(PrintFunc print, bool verbose);
|
|
|
+
|
|
|
+// Helper functions for error messages.
|
|
|
+const char *StringForEnum(AddMeshError::Enum error);
|
|
|
+const char *StringForEnum(ProgressCategory::Enum category);
|
|
|
|
|
|
} // namespace xatlas
|
|
|
|