diff options
Diffstat (limited to 'thirdparty/xatlas/xatlas.h')
-rw-r--r-- | thirdparty/xatlas/xatlas.h | 351 |
1 files changed, 225 insertions, 126 deletions
diff --git a/thirdparty/xatlas/xatlas.h b/thirdparty/xatlas/xatlas.h index 4140429fee..7be165e7e5 100644 --- a/thirdparty/xatlas/xatlas.h +++ b/thirdparty/xatlas/xatlas.h @@ -1,159 +1,258 @@ -// This code is in the public domain -- castanyo@yahoo.es +/* +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 <icastano@nvidia.com> +*/ #pragma once #ifndef XATLAS_H #define XATLAS_H -#include <float.h> // FLT_MAX -#include <limits.h> #include <stdint.h> + namespace xatlas { -typedef void (*PrintFunc)(const char *, ...); - -struct Atlas; - -struct CharterOptions { - 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; - } +struct ChartFlags +{ + enum + { + Invalid = 1 << 0 + }; }; -struct PackMethod { - 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) - }; +// A group of connected faces, belonging to a single atlas. +struct Chart +{ + uint32_t atlasIndex; // Sub-atlas index. + uint32_t flags; + uint32_t *faceArray; + uint32_t faceCount; + uint32_t material; }; -struct PackerOptions { - 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; - } +// Output 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. + uint32_t xref; // Index of input vertex from which this output vertex originated. }; -struct AddMeshErrorCode { - 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 - }; +// Output mesh. +struct Mesh +{ + Chart *chartArray; + uint32_t chartCount; + uint32_t *indexArray; + uint32_t indexCount; + Vertex *vertexArray; + uint32_t vertexCount; }; -struct AddMeshError { - AddMeshErrorCode::Enum code; - uint32_t face; - uint32_t index0, index1; +static const uint32_t kImageChartIndexMask = 0x1FFFFFFF; +static const uint32_t kImageHasChartIndexBit = 0x80000000; +static const uint32_t kImageIsBilinearBit = 0x40000000; +static const uint32_t kImageIsPaddingBit = 0x20000000; + +// Empty on creation. Populated after charts are packed. +struct Atlas +{ + 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 IndexFormat { - enum Enum { - HalfFloat, - Float +// Create an empty atlas. +Atlas *Create(); + +void Destroy(Atlas *atlas); + +struct IndexFormat +{ + enum Enum + { + UInt16, + UInt32 }; }; -struct InputMesh { - uint32_t vertexCount; - const void *vertexPositionData; - uint32_t vertexPositionStride; - const void *vertexNormalData; // optional - uint32_t vertexNormalStride; // optional +// Input mesh declaration. +struct MeshDecl +{ + 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; - // optional - // The input UVs are provided as a hint to the chart generator. - const void *vertexUvData; - uint32_t vertexUvStride; + // Vertex positions within epsilon distance of each other are considered colocal. + float epsilon = 1.192092896e-07F; +}; - uint32_t indexCount; - const void *indexData; - IndexFormat::Enum indexFormat; +struct AddMeshError +{ + enum Enum + { + Success, // No error. + Error, // Unspecified error. + IndexOutOfRange, // An index is >= MeshDecl vertexCount. + InvalidIndexCount // Not evenly divisible by 3 - expecting triangles. + }; +}; + +// 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); - // optional. indexCount / 3 in length. - // Charter also uses material boundaries as a hint to cut charts. - const uint16_t *faceMaterialData; +// Wait for AddMesh async processing to finish. ComputeCharts / Generate call this internally. +void AddMeshJoin(Atlas *atlas); + +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 { - uint32_t *indexArray; - uint32_t indexCount; +AddMeshError::Enum AddUvMesh(Atlas *atlas, const UvMeshDecl &decl); + +struct ChartOptions +{ + 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 maxIterations = 1; // Number of iterations of the chart growing and seeding phases. Higher values result in better charts. }; -struct OutputVertex { - float uv[2]; - uint32_t xref; // Index of input vertex from which this output vertex originated. +// 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 +{ + // Leave space around charts for texels that would be sampled by bilinear filtering. + bool bilinear = true; + + // Align charts to 4x4 blocks. Also improves packing speed, since there are fewer possible chart locations to consider. + bool blockAlign = false; + + // Slower, but gives the best result. If false, use random chart placement. + bool bruteForce = false; + + // Create Atlas::image + bool createImage = false; + + // Charts larger than this will be scaled down. 0 means no limit. + uint32_t maxChartSize = 0; + + // Number of pixels to pad charts with. + uint32_t padding = 0; + + // 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; }; -struct OutputMesh { - OutputChart *chartArray; - uint32_t chartCount; - uint32_t *indexArray; - uint32_t indexCount; - OutputVertex *vertexArray; - uint32_t vertexCount; +// 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 +{ + 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); +typedef void (*FreeFunc)(void *); +void SetAlloc(ReallocFunc reallocFunc, FreeFunc freeFunc = nullptr); + +// 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 |