Updated meshoptimizer.
This commit is contained in:
parent
de9f0195cf
commit
5f8326f20a
102
3rdparty/meshoptimizer/demo/tests.cpp
vendored
102
3rdparty/meshoptimizer/demo/tests.cpp
vendored
@ -229,6 +229,79 @@ static void decodeVertexRejectMalformedHeaders()
|
||||
assert(meshopt_decodeVertexBuffer(decoded, vertex_count, sizeof(PV), &brokenbuffer[0], brokenbuffer.size()) < 0);
|
||||
}
|
||||
|
||||
static void decodeVertexBitGroups()
|
||||
{
|
||||
unsigned char data[16 * 4];
|
||||
|
||||
// this tests 0/2/4/8 bit groups in one stream
|
||||
for (size_t i = 0; i < 16; ++i)
|
||||
{
|
||||
data[i * 4 + 0] = 0;
|
||||
data[i * 4 + 1] = (unsigned char)(i * 1);
|
||||
data[i * 4 + 2] = (unsigned char)(i * 2);
|
||||
data[i * 4 + 3] = (unsigned char)(i * 8);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> buffer(meshopt_encodeVertexBufferBound(16, 4));
|
||||
buffer.resize(meshopt_encodeVertexBuffer(&buffer[0], buffer.size(), data, 16, 4));
|
||||
|
||||
unsigned char decoded[16 * 4];
|
||||
assert(meshopt_decodeVertexBuffer(decoded, 16, 4, &buffer[0], buffer.size()) == 0);
|
||||
assert(memcmp(decoded, data, sizeof(data)) == 0);
|
||||
}
|
||||
|
||||
static void decodeVertexBitGroupSentinels()
|
||||
{
|
||||
unsigned char data[16 * 4];
|
||||
|
||||
// this tests 0/2/4/8 bit groups and sentinels in one stream
|
||||
for (size_t i = 0; i < 16; ++i)
|
||||
{
|
||||
if (i == 7 || i == 13)
|
||||
{
|
||||
data[i * 4 + 0] = 42;
|
||||
data[i * 4 + 1] = 42;
|
||||
data[i * 4 + 2] = 42;
|
||||
data[i * 4 + 3] = 42;
|
||||
}
|
||||
else
|
||||
{
|
||||
data[i * 4 + 0] = 0;
|
||||
data[i * 4 + 1] = (unsigned char)(i * 1);
|
||||
data[i * 4 + 2] = (unsigned char)(i * 2);
|
||||
data[i * 4 + 3] = (unsigned char)(i * 8);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> buffer(meshopt_encodeVertexBufferBound(16, 4));
|
||||
buffer.resize(meshopt_encodeVertexBuffer(&buffer[0], buffer.size(), data, 16, 4));
|
||||
|
||||
unsigned char decoded[16 * 4];
|
||||
assert(meshopt_decodeVertexBuffer(decoded, 16, 4, &buffer[0], buffer.size()) == 0);
|
||||
assert(memcmp(decoded, data, sizeof(data)) == 0);
|
||||
}
|
||||
|
||||
static void decodeVertexLarge()
|
||||
{
|
||||
unsigned char data[128 * 4];
|
||||
|
||||
// this tests 0/2/4/8 bit groups in one stream
|
||||
for (size_t i = 0; i < 128; ++i)
|
||||
{
|
||||
data[i * 4 + 0] = 0;
|
||||
data[i * 4 + 1] = (unsigned char)(i * 1);
|
||||
data[i * 4 + 2] = (unsigned char)(i * 2);
|
||||
data[i * 4 + 3] = (unsigned char)(i * 8);
|
||||
}
|
||||
|
||||
std::vector<unsigned char> buffer(meshopt_encodeVertexBufferBound(128, 4));
|
||||
buffer.resize(meshopt_encodeVertexBuffer(&buffer[0], buffer.size(), data, 128, 4));
|
||||
|
||||
unsigned char decoded[128 * 4];
|
||||
assert(meshopt_decodeVertexBuffer(decoded, 128, 4, &buffer[0], buffer.size()) == 0);
|
||||
assert(memcmp(decoded, data, sizeof(data)) == 0);
|
||||
}
|
||||
|
||||
static void clusterBoundsDegenerate()
|
||||
{
|
||||
const float vbd[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
@ -310,6 +383,8 @@ static void customAllocator()
|
||||
// customAlloc & customFree should not get called anymore
|
||||
meshopt_optimizeVertexFetch(vb, ib, 3, vb, 3, 12);
|
||||
assert(allocCount == 6 && freeCount == 6);
|
||||
|
||||
allocCount = freeCount = 0;
|
||||
}
|
||||
|
||||
static void emptyMesh()
|
||||
@ -356,7 +431,7 @@ static void simplifyPointsStuck()
|
||||
assert(meshopt_simplifyPoints(0, vb, 3, 12, 0) == 0);
|
||||
}
|
||||
|
||||
void runTests()
|
||||
static void runTestsOnce()
|
||||
{
|
||||
decodeIndexV0();
|
||||
decodeIndex16();
|
||||
@ -370,6 +445,9 @@ void runTests()
|
||||
decodeVertexMemorySafe();
|
||||
decodeVertexRejectExtraBytes();
|
||||
decodeVertexRejectMalformedHeaders();
|
||||
decodeVertexBitGroups();
|
||||
decodeVertexBitGroupSentinels();
|
||||
decodeVertexLarge();
|
||||
|
||||
clusterBoundsDegenerate();
|
||||
|
||||
@ -381,3 +459,25 @@ void runTests()
|
||||
simplifySloppyStuck();
|
||||
simplifyPointsStuck();
|
||||
}
|
||||
|
||||
namespace meshopt
|
||||
{
|
||||
extern unsigned int cpuid;
|
||||
}
|
||||
|
||||
void runTests()
|
||||
{
|
||||
runTestsOnce();
|
||||
|
||||
#if !(defined(__AVX__) || defined(__SSSE3__)) && (defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__))
|
||||
// When SSSE3/AVX support isn't enabled unconditionally, we use a cpuid-based fallback
|
||||
// It's useful to be able to test scalar code in this case, so we temporarily fake the feature bits
|
||||
// and restore them later
|
||||
unsigned int cpuid = meshopt::cpuid;
|
||||
meshopt::cpuid = 0;
|
||||
|
||||
runTestsOnce();
|
||||
|
||||
meshopt::cpuid = cpuid;
|
||||
#endif
|
||||
}
|
||||
|
1
3rdparty/meshoptimizer/src/allocator.cpp
vendored
1
3rdparty/meshoptimizer/src/allocator.cpp
vendored
@ -1,3 +1,4 @@
|
||||
// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
|
||||
#include "meshoptimizer.h"
|
||||
|
||||
void meshopt_setAllocator(void* (*allocate)(size_t), void (*deallocate)(void*))
|
||||
|
1
3rdparty/meshoptimizer/src/stripifier.cpp
vendored
1
3rdparty/meshoptimizer/src/stripifier.cpp
vendored
@ -1,3 +1,4 @@
|
||||
// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
|
||||
#include "meshoptimizer.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
37
3rdparty/meshoptimizer/src/vertexcodec.cpp
vendored
37
3rdparty/meshoptimizer/src/vertexcodec.cpp
vendored
@ -23,6 +23,14 @@
|
||||
#include <intrin.h> // __cpuid
|
||||
#endif
|
||||
|
||||
// GCC 4.9+ and clang 3.8+ support targeting SIMD instruction sets from individual functions
|
||||
#if !defined(SIMD_SSE) && !defined(SIMD_AVX) && ((defined(__clang__) && __clang_major__ * 100 + __clang_minor__ >= 308) || (defined(__GNUC__) && __GNUC__ * 100 + __GNUC_MINOR__ >= 409)) && (defined(__i386__) || defined(__x86_64__))
|
||||
#define SIMD_SSE
|
||||
#define SIMD_FALLBACK
|
||||
#define SIMD_TARGET __attribute__((target("ssse3")))
|
||||
#include <cpuid.h> // __cpuid
|
||||
#endif
|
||||
|
||||
#if !defined(SIMD_NEON) && defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
|
||||
#define SIMD_NEON
|
||||
#endif
|
||||
@ -32,6 +40,10 @@
|
||||
#define SIMD_WASM
|
||||
#endif
|
||||
|
||||
#ifndef SIMD_TARGET
|
||||
#define SIMD_TARGET
|
||||
#endif
|
||||
|
||||
#ifdef SIMD_SSE
|
||||
#include <tmmintrin.h>
|
||||
#endif
|
||||
@ -446,6 +458,7 @@ static bool gDecodeBytesGroupInitialized = decodeBytesGroupBuildTables();
|
||||
#endif
|
||||
|
||||
#ifdef SIMD_SSE
|
||||
SIMD_TARGET
|
||||
static __m128i decodeShuffleMask(unsigned char mask0, unsigned char mask1)
|
||||
{
|
||||
__m128i sm0 = _mm_loadl_epi64(reinterpret_cast<const __m128i*>(&kDecodeBytesGroupShuffle[mask0]));
|
||||
@ -457,6 +470,7 @@ static __m128i decodeShuffleMask(unsigned char mask0, unsigned char mask1)
|
||||
return _mm_unpacklo_epi64(sm0, sm1r);
|
||||
}
|
||||
|
||||
SIMD_TARGET
|
||||
static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsigned char* buffer, int bitslog2)
|
||||
{
|
||||
switch (bitslog2)
|
||||
@ -814,6 +828,7 @@ static const unsigned char* decodeBytesGroupSimd(const unsigned char* data, unsi
|
||||
#endif
|
||||
|
||||
#if defined(SIMD_SSE) || defined(SIMD_AVX)
|
||||
SIMD_TARGET
|
||||
static void transpose8(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3)
|
||||
{
|
||||
__m128i t0 = _mm_unpacklo_epi8(x0, x1);
|
||||
@ -827,6 +842,7 @@ static void transpose8(__m128i& x0, __m128i& x1, __m128i& x2, __m128i& x3)
|
||||
x3 = _mm_unpackhi_epi16(t1, t3);
|
||||
}
|
||||
|
||||
SIMD_TARGET
|
||||
static __m128i unzigzag8(__m128i v)
|
||||
{
|
||||
__m128i xl = _mm_sub_epi8(_mm_setzero_si128(), _mm_and_si128(v, _mm_set1_epi8(1)));
|
||||
@ -884,6 +900,7 @@ static v128_t unzigzag8(v128_t v)
|
||||
#endif
|
||||
|
||||
#if defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM)
|
||||
SIMD_TARGET
|
||||
static const unsigned char* decodeBytesSimd(const unsigned char* data, const unsigned char* data_end, unsigned char* buffer, size_t buffer_size)
|
||||
{
|
||||
assert(buffer_size % kByteGroupSize == 0);
|
||||
@ -929,6 +946,7 @@ static const unsigned char* decodeBytesSimd(const unsigned char* data, const uns
|
||||
return data;
|
||||
}
|
||||
|
||||
SIMD_TARGET
|
||||
static const unsigned char* decodeVertexBlockSimd(const unsigned char* data, const unsigned char* data_end, unsigned char* vertex_data, size_t vertex_count, size_t vertex_size, unsigned char last_vertex[256])
|
||||
{
|
||||
assert(vertex_count > 0 && vertex_count <= kVertexBlockMaxSize);
|
||||
@ -1027,6 +1045,21 @@ static const unsigned char* decodeVertexBlockSimd(const unsigned char* data, con
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(SIMD_SSE) && defined(SIMD_FALLBACK)
|
||||
static unsigned int getCpuFeatures()
|
||||
{
|
||||
int cpuinfo[4] = {};
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
__cpuid(cpuinfo, 1);
|
||||
#else
|
||||
__cpuid(1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
|
||||
#endif
|
||||
return cpuinfo[2];
|
||||
}
|
||||
|
||||
unsigned int cpuid = getCpuFeatures();
|
||||
#endif
|
||||
|
||||
} // namespace meshopt
|
||||
|
||||
size_t meshopt_encodeVertexBuffer(unsigned char* buffer, size_t buffer_size, const void* vertices, size_t vertex_count, size_t vertex_size)
|
||||
@ -1140,9 +1173,7 @@ int meshopt_decodeVertexBuffer(void* destination, size_t vertex_count, size_t ve
|
||||
const unsigned char* (*decode)(const unsigned char*, const unsigned char*, unsigned char*, size_t, size_t, unsigned char[256]) = 0;
|
||||
|
||||
#if defined(SIMD_SSE) && defined(SIMD_FALLBACK)
|
||||
int cpuinfo[4] = {};
|
||||
__cpuid(cpuinfo, 1);
|
||||
decode = (cpuinfo[2] & (1 << 9)) ? decodeVertexBlockSimd : decodeVertexBlock;
|
||||
decode = (cpuid & (1 << 9)) ? decodeVertexBlockSimd : decodeVertexBlock;
|
||||
#elif defined(SIMD_SSE) || defined(SIMD_AVX) || defined(SIMD_NEON) || defined(SIMD_WASM)
|
||||
decode = decodeVertexBlockSimd;
|
||||
#else
|
||||
|
114
3rdparty/meshoptimizer/tools/basistoktx.cpp
vendored
114
3rdparty/meshoptimizer/tools/basistoktx.cpp
vendored
@ -9,7 +9,66 @@
|
||||
|
||||
#include "basisu_format.h"
|
||||
#include "khr_df.h"
|
||||
#include "ktx2_format.h"
|
||||
|
||||
// KTX Specification: 2. File Structure
|
||||
struct Ktx2Header
|
||||
{
|
||||
uint8_t identifier[12];
|
||||
uint32_t vkFormat;
|
||||
uint32_t typeSize;
|
||||
uint32_t pixelWidth;
|
||||
uint32_t pixelHeight;
|
||||
uint32_t pixelDepth;
|
||||
uint32_t layerCount;
|
||||
uint32_t faceCount;
|
||||
uint32_t levelCount;
|
||||
uint32_t supercompressionScheme;
|
||||
|
||||
uint32_t dfdByteOffset;
|
||||
uint32_t dfdByteLength;
|
||||
uint32_t kvdByteOffset;
|
||||
uint32_t kvdByteLength;
|
||||
uint64_t sgdByteOffset;
|
||||
uint64_t sgdByteLength;
|
||||
};
|
||||
|
||||
struct Ktx2LevelIndex
|
||||
{
|
||||
uint64_t byteOffset;
|
||||
uint64_t byteLength;
|
||||
uint64_t uncompressedByteLength;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
Ktx2SupercompressionSchemeBasis = 1,
|
||||
};
|
||||
|
||||
// KTX Specification: 3.1. identifier
|
||||
static const uint8_t Ktx2FileIdentifier[12] = {
|
||||
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A,
|
||||
};
|
||||
|
||||
// KTX Specification: 3.12.2. Basis Universal Global Data
|
||||
struct Ktx2BasisGlobalHeader
|
||||
{
|
||||
uint32_t globalFlags;
|
||||
uint16_t endpointCount;
|
||||
uint16_t selectorCount;
|
||||
uint32_t endpointsByteLength;
|
||||
uint32_t selectorsByteLength;
|
||||
uint32_t tablesByteLength;
|
||||
uint32_t extendedByteLength;
|
||||
};
|
||||
|
||||
struct Ktx2BasisImageDesc
|
||||
{
|
||||
uint32_t imageFlags;
|
||||
uint32_t rgbSliceByteOffset;
|
||||
uint32_t rgbSliceByteLength;
|
||||
uint32_t alphaSliceByteOffset;
|
||||
uint32_t alphaSliceByteLength;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static void read(const std::string& data, size_t offset, T& result)
|
||||
@ -99,16 +158,17 @@ std::string basisToKtx(const std::string& basis, bool srgb)
|
||||
uint32_t height = slices[0].m_orig_height;
|
||||
uint32_t levels = has_alpha ? uint32_t(slices.size()) / 2 : uint32_t(slices.size());
|
||||
|
||||
KTX_header2 ktx_header = {KTX2_IDENTIFIER_REF};
|
||||
Ktx2Header ktx_header = {};
|
||||
memcpy(ktx_header.identifier, Ktx2FileIdentifier, sizeof(Ktx2FileIdentifier));
|
||||
ktx_header.typeSize = 1;
|
||||
ktx_header.pixelWidth = width;
|
||||
ktx_header.pixelHeight = height;
|
||||
ktx_header.layerCount = 0;
|
||||
ktx_header.faceCount = 1;
|
||||
ktx_header.levelCount = levels;
|
||||
ktx_header.supercompressionScheme = KTX_SUPERCOMPRESSION_BASIS;
|
||||
ktx_header.supercompressionScheme = Ktx2SupercompressionSchemeBasis;
|
||||
|
||||
size_t header_size = sizeof(KTX_header2) + levels * sizeof(ktxLevelIndexEntry);
|
||||
size_t header_size = sizeof(Ktx2Header) + levels * sizeof(Ktx2LevelIndex);
|
||||
|
||||
std::vector<uint32_t> dfd;
|
||||
createDfd(dfd, has_alpha ? 4 : 3, srgb);
|
||||
@ -138,17 +198,17 @@ std::string basisToKtx(const std::string& basis, bool srgb)
|
||||
size_t dfd_size = dfd.size() * sizeof(uint32_t);
|
||||
|
||||
size_t bgd_size =
|
||||
sizeof(ktxBasisGlobalHeader) + sizeof(ktxBasisSliceDesc) * levels +
|
||||
sizeof(Ktx2BasisGlobalHeader) + sizeof(Ktx2BasisImageDesc) * levels +
|
||||
basis_header.m_endpoint_cb_file_size + basis_header.m_selector_cb_file_size + basis_header.m_tables_file_size;
|
||||
|
||||
ktx_header.dataFormatDescriptor.byteOffset = uint32_t(header_size);
|
||||
ktx_header.dataFormatDescriptor.byteLength = uint32_t(dfd_size);
|
||||
ktx_header.dfdByteOffset = uint32_t(header_size);
|
||||
ktx_header.dfdByteLength = uint32_t(dfd_size);
|
||||
|
||||
ktx_header.keyValueData.byteOffset = uint32_t(header_size + dfd_size);
|
||||
ktx_header.keyValueData.byteLength = uint32_t(kvp_size);
|
||||
ktx_header.kvdByteOffset = uint32_t(header_size + dfd_size);
|
||||
ktx_header.kvdByteLength = uint32_t(kvp_size);
|
||||
|
||||
ktx_header.supercompressionGlobalData.byteOffset = (header_size + dfd_size + kvp_size + 7) & ~7;
|
||||
ktx_header.supercompressionGlobalData.byteLength = bgd_size;
|
||||
ktx_header.sgdByteOffset = (header_size + dfd_size + kvp_size + 7) & ~7;
|
||||
ktx_header.sgdByteLength = bgd_size;
|
||||
|
||||
// KTX2 header
|
||||
write(ktx, ktx_header);
|
||||
@ -157,7 +217,7 @@ std::string basisToKtx(const std::string& basis, bool srgb)
|
||||
|
||||
for (size_t i = 0; i < levels; ++i)
|
||||
{
|
||||
ktxLevelIndexEntry le = {}; // This will be patched later
|
||||
Ktx2LevelIndex le = {}; // This will be patched later
|
||||
write(ktx, le);
|
||||
}
|
||||
|
||||
@ -170,7 +230,7 @@ std::string basisToKtx(const std::string& basis, bool srgb)
|
||||
ktx.resize((ktx.size() + 7) & ~7);
|
||||
|
||||
// supercompression global data
|
||||
ktxBasisGlobalHeader sgd_header = {};
|
||||
Ktx2BasisGlobalHeader sgd_header = {};
|
||||
sgd_header.globalFlags = basis_header.m_flags;
|
||||
sgd_header.endpointCount = uint16_t(basis_header.m_total_endpoints);
|
||||
sgd_header.selectorCount = uint16_t(basis_header.m_total_selectors);
|
||||
@ -185,8 +245,8 @@ std::string basisToKtx(const std::string& basis, bool srgb)
|
||||
|
||||
for (size_t i = 0; i < levels; ++i)
|
||||
{
|
||||
ktxBasisSliceDesc sgd_slice = {}; // This will be patched later
|
||||
write(ktx, sgd_slice);
|
||||
Ktx2BasisImageDesc sgd_image = {}; // This will be patched later
|
||||
write(ktx, sgd_image);
|
||||
}
|
||||
|
||||
ktx.append(basis.substr(basis_header.m_endpoint_cb_file_ofs, basis_header.m_endpoint_cb_file_size));
|
||||
@ -199,12 +259,14 @@ std::string basisToKtx(const std::string& basis, bool srgb)
|
||||
// mip levels
|
||||
for (size_t i = 0; i < levels; ++i)
|
||||
{
|
||||
size_t slice_index = (levels - i - 1) * (has_alpha + 1);
|
||||
size_t level_index = levels - i - 1;
|
||||
size_t slice_index = level_index * (has_alpha + 1);
|
||||
|
||||
const basist::basis_slice_desc& slice = slices[slice_index];
|
||||
const basist::basis_slice_desc* slice_alpha = has_alpha ? &slices[slice_index + 1] : 0;
|
||||
|
||||
assert(slice.m_image_index == 0);
|
||||
assert(slice.m_level_index == levels - i - 1);
|
||||
assert(slice.m_level_index == level_index);
|
||||
|
||||
size_t file_offset = ktx.size();
|
||||
|
||||
@ -213,29 +275,31 @@ std::string basisToKtx(const std::string& basis, bool srgb)
|
||||
if (slice_alpha)
|
||||
ktx.append(basis.substr(slice_alpha->m_file_ofs, slice_alpha->m_file_size));
|
||||
|
||||
ktxLevelIndexEntry le = {};
|
||||
Ktx2LevelIndex le = {};
|
||||
le.byteOffset = file_offset;
|
||||
le.byteLength = ktx.size() - file_offset;
|
||||
le.uncompressedByteLength = 0;
|
||||
|
||||
write(ktx, ktx_level_offset + i * sizeof(ktxLevelIndexEntry), le);
|
||||
write(ktx, ktx_level_offset + level_index * sizeof(Ktx2LevelIndex), le);
|
||||
|
||||
ktxBasisSliceDesc sgd_slice = {};
|
||||
sgd_slice.sliceByteOffset = 0;
|
||||
sgd_slice.sliceByteLength = slice.m_file_size;
|
||||
Ktx2BasisImageDesc sgd_image = {};
|
||||
sgd_image.rgbSliceByteOffset = 0;
|
||||
sgd_image.rgbSliceByteLength = slice.m_file_size;
|
||||
|
||||
if (slice_alpha)
|
||||
{
|
||||
sgd_slice.alphaSliceByteOffset = slice.m_file_size;
|
||||
sgd_slice.alphaSliceByteLength = slice_alpha->m_file_size;
|
||||
sgd_image.alphaSliceByteOffset = slice.m_file_size;
|
||||
sgd_image.alphaSliceByteLength = slice_alpha->m_file_size;
|
||||
}
|
||||
|
||||
write(ktx, sgd_level_offset + i * sizeof(ktxBasisSliceDesc), sgd_slice);
|
||||
write(ktx, sgd_level_offset + level_index * sizeof(Ktx2BasisImageDesc), sgd_image);
|
||||
|
||||
if (i + 1 != levels)
|
||||
ktx.resize((ktx.size() + 7) & ~7);
|
||||
}
|
||||
|
||||
ktx.resize((ktx.size() + 7) & ~7);
|
||||
|
||||
return ktx;
|
||||
}
|
||||
|
||||
|
22
3rdparty/meshoptimizer/tools/cgltf.h
vendored
22
3rdparty/meshoptimizer/tools/cgltf.h
vendored
@ -125,6 +125,7 @@ typedef enum cgltf_result
|
||||
cgltf_result_file_not_found,
|
||||
cgltf_result_io_error,
|
||||
cgltf_result_out_of_memory,
|
||||
cgltf_result_legacy_gltf,
|
||||
} cgltf_result;
|
||||
|
||||
typedef enum cgltf_buffer_view_type
|
||||
@ -763,7 +764,7 @@ cgltf_result cgltf_parse(const cgltf_options* options, const void* data, cgltf_s
|
||||
uint32_t version = tmp;
|
||||
if (version != GlbVersion)
|
||||
{
|
||||
return cgltf_result_unknown_format;
|
||||
return version < GlbVersion ? cgltf_result_legacy_gltf : cgltf_result_unknown_format;
|
||||
}
|
||||
|
||||
// Total length
|
||||
@ -1707,6 +1708,7 @@ cgltf_size cgltf_accessor_read_index(const cgltf_accessor* accessor, cgltf_size
|
||||
|
||||
#define CGLTF_ERROR_JSON -1
|
||||
#define CGLTF_ERROR_NOMEM -2
|
||||
#define CGLTF_ERROR_LEGACY -3
|
||||
|
||||
#define CGLTF_CHECK_TOKTYPE(tok_, type_) if ((tok_).type != (type_)) { return CGLTF_ERROR_JSON; }
|
||||
#define CGLTF_CHECK_KEY(tok_) if ((tok_).type != JSMN_STRING || (tok_).size == 0) { return CGLTF_ERROR_JSON; } /* checking size for 0 verifies that a value follows the key */
|
||||
@ -1826,7 +1828,10 @@ static int cgltf_parse_json_string(cgltf_options* options, jsmntok_t const* toke
|
||||
static int cgltf_parse_json_array(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, size_t element_size, void** out_array, cgltf_size* out_size)
|
||||
{
|
||||
(void)json_chunk;
|
||||
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
|
||||
if (tokens[i].type != JSMN_ARRAY)
|
||||
{
|
||||
return tokens[i].type == JSMN_OBJECT ? CGLTF_ERROR_LEGACY : CGLTF_ERROR_JSON;
|
||||
}
|
||||
if (*out_array)
|
||||
{
|
||||
return CGLTF_ERROR_JSON;
|
||||
@ -4049,6 +4054,11 @@ static int cgltf_parse_json_asset(cgltf_options* options, jsmntok_t const* token
|
||||
}
|
||||
}
|
||||
|
||||
if (out_asset->version && atof(out_asset->version) < 2)
|
||||
{
|
||||
return CGLTF_ERROR_LEGACY;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -4315,7 +4325,13 @@ cgltf_result cgltf_parse_json(cgltf_options* options, const uint8_t* json_chunk,
|
||||
if (i < 0)
|
||||
{
|
||||
cgltf_free(data);
|
||||
return (i == CGLTF_ERROR_NOMEM) ? cgltf_result_out_of_memory : cgltf_result_invalid_gltf;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case CGLTF_ERROR_NOMEM: return cgltf_result_out_of_memory;
|
||||
case CGLTF_ERROR_LEGACY: return cgltf_result_legacy_gltf;
|
||||
default: return cgltf_result_invalid_gltf;
|
||||
}
|
||||
}
|
||||
|
||||
if (cgltf_fixup_pointers(data) < 0)
|
||||
|
104
3rdparty/meshoptimizer/tools/gltfpack.cpp
vendored
104
3rdparty/meshoptimizer/tools/gltfpack.cpp
vendored
@ -177,12 +177,12 @@ struct BufferView
|
||||
size_t bytes;
|
||||
};
|
||||
|
||||
const char* getError(cgltf_result result)
|
||||
const char* getError(cgltf_result result, cgltf_data* data)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case cgltf_result_file_not_found:
|
||||
return "file not found";
|
||||
return data ? "resource not found" : "file not found";
|
||||
|
||||
case cgltf_result_io_error:
|
||||
return "I/O error";
|
||||
@ -196,6 +196,15 @@ const char* getError(cgltf_result result)
|
||||
case cgltf_result_out_of_memory:
|
||||
return "out of memory";
|
||||
|
||||
case cgltf_result_legacy_gltf:
|
||||
return "legacy GLTF";
|
||||
|
||||
case cgltf_result_data_too_short:
|
||||
return data ? "buffer too short" : "not a GLTF file";
|
||||
|
||||
case cgltf_result_unknown_format:
|
||||
return data ? "unknown resource format" : "not a GLTF file";
|
||||
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
@ -776,29 +785,18 @@ void mergeMeshes(Mesh& target, const Mesh& mesh)
|
||||
|
||||
void mergeMeshes(std::vector<Mesh>& meshes, const Settings& settings)
|
||||
{
|
||||
size_t write = 0;
|
||||
|
||||
for (size_t i = 0; i < meshes.size(); ++i)
|
||||
{
|
||||
if (meshes[i].streams.empty())
|
||||
Mesh& target = meshes[i];
|
||||
|
||||
if (target.streams.empty())
|
||||
continue;
|
||||
|
||||
Mesh& target = meshes[write];
|
||||
|
||||
if (i != write)
|
||||
{
|
||||
Mesh& mesh = meshes[i];
|
||||
|
||||
// note: this copy is expensive; we could use move in C++11 or swap manually which is a bit painful...
|
||||
target = mesh;
|
||||
|
||||
mesh.streams.clear();
|
||||
mesh.indices.clear();
|
||||
}
|
||||
|
||||
size_t target_vertices = target.streams[0].data.size();
|
||||
size_t target_indices = target.indices.size();
|
||||
|
||||
size_t last_merged = i;
|
||||
|
||||
for (size_t j = i + 1; j < meshes.size(); ++j)
|
||||
{
|
||||
Mesh& mesh = meshes[j];
|
||||
@ -807,6 +805,7 @@ void mergeMeshes(std::vector<Mesh>& meshes, const Settings& settings)
|
||||
{
|
||||
target_vertices += mesh.streams[0].data.size();
|
||||
target_indices += mesh.indices.size();
|
||||
last_merged = j;
|
||||
}
|
||||
}
|
||||
|
||||
@ -815,7 +814,7 @@ void mergeMeshes(std::vector<Mesh>& meshes, const Settings& settings)
|
||||
|
||||
target.indices.reserve(target_indices);
|
||||
|
||||
for (size_t j = i + 1; j < meshes.size(); ++j)
|
||||
for (size_t j = i + 1; j <= last_merged; ++j)
|
||||
{
|
||||
Mesh& mesh = meshes[j];
|
||||
|
||||
@ -830,6 +829,39 @@ void mergeMeshes(std::vector<Mesh>& meshes, const Settings& settings)
|
||||
|
||||
assert(target.streams[0].data.size() == target_vertices);
|
||||
assert(target.indices.size() == target_indices);
|
||||
}
|
||||
}
|
||||
|
||||
void filterEmptyMeshes(std::vector<Mesh>& meshes)
|
||||
{
|
||||
size_t write = 0;
|
||||
|
||||
for (size_t i = 0; i < meshes.size(); ++i)
|
||||
{
|
||||
Mesh& mesh = meshes[i];
|
||||
|
||||
if (mesh.streams.empty())
|
||||
continue;
|
||||
|
||||
if (mesh.streams[0].data.empty())
|
||||
continue;
|
||||
|
||||
if (mesh.type == cgltf_primitive_type_triangles && mesh.indices.empty())
|
||||
continue;
|
||||
|
||||
if (i != write)
|
||||
{
|
||||
// the following code is roughly equivalent to meshes[write] = std::move(mesh)
|
||||
std::vector<Stream> streams;
|
||||
streams.swap(mesh.streams);
|
||||
|
||||
std::vector<unsigned int> indices;
|
||||
indices.swap(mesh.indices);
|
||||
|
||||
meshes[write] = mesh;
|
||||
meshes[write].streams.swap(streams);
|
||||
meshes[write].indices.swap(indices);
|
||||
}
|
||||
|
||||
write++;
|
||||
}
|
||||
@ -2940,7 +2972,7 @@ void writeImage(std::string& json, std::vector<BufferView>& views, const cgltf_i
|
||||
if (settings.texture_basis)
|
||||
{
|
||||
std::string full_path = getFullPath(image.uri, input_path);
|
||||
std::string basis_path = getFileName(image.uri) + (settings.texture_ktx2 ? ".ktx" : ".basis");
|
||||
std::string basis_path = getFileName(image.uri) + (settings.texture_ktx2 ? ".ktx2" : ".basis");
|
||||
std::string basis_full_path = getFullPath(basis_path.c_str(), output_path);
|
||||
|
||||
if (readFile(full_path.c_str(), img_data))
|
||||
@ -3693,6 +3725,7 @@ void process(cgltf_data* data, const char* input_path, const char* output_path,
|
||||
|
||||
mergeMeshMaterials(data, meshes);
|
||||
mergeMeshes(meshes, settings);
|
||||
filterEmptyMeshes(meshes);
|
||||
|
||||
markNeededNodes(data, nodes, meshes, settings);
|
||||
|
||||
@ -3710,6 +3743,8 @@ void process(cgltf_data* data, const char* input_path, const char* output_path,
|
||||
processMesh(meshes[i], settings);
|
||||
}
|
||||
|
||||
filterEmptyMeshes(meshes); // some meshes may become empty after processing
|
||||
|
||||
if (settings.verbose)
|
||||
{
|
||||
printMeshStats(meshes, "output");
|
||||
@ -4106,6 +4141,29 @@ std::string getBufferSpec(const char* bin_path, size_t bin_size, const char* fal
|
||||
return json;
|
||||
}
|
||||
|
||||
bool needsDummyBuffers(cgltf_data* data)
|
||||
{
|
||||
for (size_t i = 0; i < data->accessors_count; ++i)
|
||||
{
|
||||
cgltf_accessor* accessor = &data->accessors[i];
|
||||
|
||||
if (accessor->buffer_view && accessor->buffer_view->buffer->data == NULL)
|
||||
return true;
|
||||
|
||||
if (accessor->is_sparse)
|
||||
{
|
||||
cgltf_accessor_sparse* sparse = &accessor->sparse;
|
||||
|
||||
if (sparse->indices_buffer_view->buffer->data == NULL)
|
||||
return true;
|
||||
if (sparse->values_buffer_view->buffer->data == NULL)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int gltfpack(const char* input, const char* output, const Settings& settings)
|
||||
{
|
||||
cgltf_data* data = 0;
|
||||
@ -4117,17 +4175,19 @@ int gltfpack(const char* input, const char* output, const Settings& settings)
|
||||
{
|
||||
cgltf_options options = {};
|
||||
cgltf_result result = cgltf_parse_file(&options, input, &data);
|
||||
result = (result == cgltf_result_success) ? cgltf_validate(data) : result;
|
||||
result = (result == cgltf_result_success) ? cgltf_load_buffers(&options, data, input) : result;
|
||||
result = (result == cgltf_result_success) ? cgltf_validate(data) : result;
|
||||
|
||||
const char* error = NULL;
|
||||
|
||||
if (result != cgltf_result_success)
|
||||
error = getError(result);
|
||||
error = getError(result, data);
|
||||
else if (requiresExtension(data, "KHR_draco_mesh_compression"))
|
||||
error = "file requires Draco mesh compression support";
|
||||
else if (requiresExtension(data, "MESHOPT_compression"))
|
||||
error = "file has already been compressed using gltfpack";
|
||||
else if (needsDummyBuffers(data))
|
||||
error = "buffer has no data";
|
||||
|
||||
if (error)
|
||||
{
|
||||
|
125
3rdparty/meshoptimizer/tools/ktx2_format.h
vendored
125
3rdparty/meshoptimizer/tools/ktx2_format.h
vendored
@ -1,125 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010-2018 The Khronos Group Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Author: Mark Callow from original code by Georg Kolling
|
||||
*/
|
||||
|
||||
/*
|
||||
* Converted from ktxint.h + basis_sgd.h by extracting meaningful structures for gltfpack
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define KTX2_IDENTIFIER_REF { 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A }
|
||||
#define KTX2_HEADER_SIZE (80)
|
||||
|
||||
typedef enum ktxSupercmpScheme {
|
||||
KTX_SUPERCOMPRESSION_NONE = 0, /*!< No supercompression. */
|
||||
KTX_SUPERCOMPRESSION_BASIS = 1, /*!< Basis Universal supercompression. */
|
||||
KTX_SUPERCOMPRESSION_LZMA = 2, /*!< LZMA supercompression. */
|
||||
KTX_SUPERCOMPRESSION_ZLIB = 3, /*!< Zlib supercompression. */
|
||||
KTX_SUPERCOMPRESSION_ZSTD = 4, /*!< ZStd supercompression. */
|
||||
KTX_SUPERCOMPRESSION_BEGIN_RANGE = KTX_SUPERCOMPRESSION_NONE,
|
||||
KTX_SUPERCOMPRESSION_END_RANGE = KTX_SUPERCOMPRESSION_ZSTD,
|
||||
KTX_SUPERCOMPRESSION_BEGIN_VENDOR_RANGE = 0x10000,
|
||||
KTX_SUPERCOMPRESSION_END_VENDOR_RANGE = 0x1ffff,
|
||||
KTX_SUPERCOMPRESSION_BEGIN_RESERVED = 0x20000,
|
||||
} ktxSupercmpScheme;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief 32-bit KTX 2 index entry.
|
||||
*/
|
||||
typedef struct ktxIndexEntry32 {
|
||||
uint32_t byteOffset; /*!< Offset of item from start of file. */
|
||||
uint32_t byteLength; /*!< Number of bytes of data in the item. */
|
||||
} ktxIndexEntry32;
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief 64-bit KTX 2 index entry.
|
||||
*/
|
||||
typedef struct ktxIndexEntry64 {
|
||||
uint64_t byteOffset; /*!< Offset of item from start of file. */
|
||||
uint64_t byteLength; /*!< Number of bytes of data in the item. */
|
||||
} ktxIndexEntry64;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief KTX 2 file header.
|
||||
*
|
||||
* See the KTX 2 specification for descriptions.
|
||||
*/
|
||||
typedef struct KTX_header2 {
|
||||
uint8_t identifier[12];
|
||||
uint32_t vkFormat;
|
||||
uint32_t typeSize;
|
||||
uint32_t pixelWidth;
|
||||
uint32_t pixelHeight;
|
||||
uint32_t pixelDepth;
|
||||
uint32_t layerCount;
|
||||
uint32_t faceCount;
|
||||
uint32_t levelCount;
|
||||
uint32_t supercompressionScheme;
|
||||
ktxIndexEntry32 dataFormatDescriptor;
|
||||
ktxIndexEntry32 keyValueData;
|
||||
ktxIndexEntry64 supercompressionGlobalData;
|
||||
} KTX_header2;
|
||||
|
||||
/* This will cause compilation to fail if the struct size doesn't match */
|
||||
typedef int KTX_header2_SIZE_ASSERT [sizeof(KTX_header2) == KTX2_HEADER_SIZE];
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @~English
|
||||
* @brief KTX 2 level index entry.
|
||||
*/
|
||||
typedef struct ktxLevelIndexEntry {
|
||||
uint64_t byteOffset; /*!< Offset of level from start of file. */
|
||||
uint64_t byteLength;
|
||||
/*!< Number of bytes of compressed image data in the level. */
|
||||
uint64_t uncompressedByteLength;
|
||||
/*!< Number of bytes of uncompressed image data in the level. */
|
||||
} ktxLevelIndexEntry;
|
||||
|
||||
typedef struct ktxBasisGlobalHeader {
|
||||
uint32_t globalFlags;
|
||||
uint16_t endpointCount;
|
||||
uint16_t selectorCount;
|
||||
uint32_t endpointsByteLength;
|
||||
uint32_t selectorsByteLength;
|
||||
uint32_t tablesByteLength;
|
||||
uint32_t extendedByteLength;
|
||||
} ktxBasisGlobalHeader;
|
||||
|
||||
// This header is followed by imageCount "slice" descriptions.
|
||||
|
||||
// 1, or 2 slices per image (i.e. layer, face & slice).
|
||||
// These offsets are relative to start of a mip level as given by the
|
||||
// main levelIndex.
|
||||
typedef struct ktxBasisSliceDesc {
|
||||
uint32_t sliceFlags;
|
||||
uint32_t sliceByteOffset;
|
||||
uint32_t sliceByteLength;
|
||||
uint32_t alphaSliceByteOffset;
|
||||
uint32_t alphaSliceByteLength;
|
||||
} ktxBasisSliceDesc;
|
Loading…
x
Reference in New Issue
Block a user