1#include "MeshoptDecompressor.h"
4#include "Foundation/Logging/Logger.h"
5#include "Resources/MeshManager.h"
11#define DEBUG_MESHOPT 0
21 bvd.originalBufferViewIdx = bufferViewIdx;
26 if (!properties.HasMember(
"buffer")) {
27 LOG_ERROR(logger,
"EXT_meshopt_compression does not contain a 'buffer' property");
30 bvd.bufferIdx = properties[
"buffer"].GetInt();
32 if (!properties.HasMember(
"byteLength")) {
33 LOG_ERROR(logger,
"EXT_meshopt_compression does not contain a 'byteLength' property");
36 bvd.byteLength = properties[
"byteLength"].GetInt();
38 if (!properties.HasMember(
"byteStride")) {
39 LOG_ERROR(logger,
"EXT_meshopt_compression does not contain a 'byteStride' property");
42 bvd.byteStride = properties[
"byteStride"].GetInt();
44 if (!properties.HasMember(
"count")) {
45 LOG_ERROR(logger,
"EXT_meshopt_compression does not contain a 'count' property");
48 bvd.count = properties[
"count"].GetInt();
50 if (!properties.HasMember(
"mode")) {
51 LOG_ERROR(logger,
"EXT_meshopt_compression does not contain a 'mode' property");
54 std::string m = properties[
"mode"].GetString();
55 if (m ==
"ATTRIBUTES") { bvd.mode = Mode::ATTRIBUTES; }
56 else if (m ==
"TRIANGLES") { bvd.mode = Mode::TRIANGLES; }
57 else if (m ==
"INDICES") { bvd.mode = Mode::INDICES; }
59 LOG_ERROR(logger,
"Unknown 'mode' in glTF: '%s'", m.c_str());
66 if (properties.HasMember(
"byteOffset")) {
67 bvd.byteOffset = properties[
"byteOffset"].GetInt();
70 if (properties.HasMember(
"filter")) {
71 std::string f = properties[
"filter"].GetString();
72 if (f ==
"OCTAHEDRAL") { bvd.filter = Filter::OCTAHEDRAL; }
73 else if (f ==
"QUATERNION") { bvd.filter = Filter::QUATERNION; }
74 else if (f ==
"EXPONENTIAL") { bvd.filter = Filter::EXPONENTIAL; }
76 LOG_ERROR(logger,
"Unknown 'filter' in glTF: '%s'", f.c_str());
85 if (bvd.mode == Mode::ATTRIBUTES && (bvd.byteStride % 4 != 0 || bvd.byteStride > 255)) {
86 LOG_ERROR(logger,
"When mode is ATTRIBUTES then byteStride must divisible by 4 and less than 256");
90 if (bvd.mode == Mode::TRIANGLES && (bvd.count % 3 != 0)) {
91 LOG_ERROR(logger,
"When mode is TRIANGLES then count must divisible by 3");
95 if (bvd.mode == Mode::INDICES || bvd.mode == Mode::TRIANGLES) {
96 if (bvd.byteStride != 2 && bvd.byteStride != 4) {
97 LOG_ERROR(logger,
"When mode is INDICES or TRIANGLES then byteStride must be 2 or 4 (is %d)", bvd.byteStride);
100 if (bvd.filter != Filter::NONE) {
101 LOG_ERROR(logger,
"When mode is INDICES or TRIANGLES then FITLER must be NONE or omitted");
106 if (bvd.filter == Filter::OCTAHEDRAL && (bvd.byteStride != 4 && bvd.byteStride != 8)) {
107 LOG_ERROR(logger,
"When FILTER is OCTAHEDRAL then byteStride must be 4 or 8 (is %d)", bvd.byteStride);
111 if (bvd.filter == Filter::QUATERNION && bvd.byteStride != 8) {
112 LOG_ERROR(logger,
"When FILTER is QUATERNION then byteStride must be 8 (is %d)", bvd.byteStride);
116 if (bvd.filter == Filter::EXPONENTIAL && (bvd.byteStride % 4 != 0)) {
117 LOG_ERROR(logger,
"When FILTER is EXPONENTIAL then byteStride must divisible by 4");
122 LOG_DEBUG(logger,
"EXT_meshopt_decompressor registered for BufferView %d", bufferViewIdx);
123 LOG_DEBUG(logger,
" SrcBuffer=%d, len=%d, stride=%d, count=%d, offset=%d, filter=%d",
124 bvd.bufferIdx, bvd.byteLength, bvd.byteStride, bvd.count, bvd.byteOffset, bvd.filter);
127 assert(!this->bufferViewDecomps.contains(bufferViewIdx) &&
"Bufferview already registered");
128 this->bufferViewDecomps[bufferViewIdx] = bvd;
135 uint32_t bufferViewIdx = getBufferViewIdxFromAccessorIdx(loadData, accessorIdx);
136 return this->bufferViewDecomps.contains(bufferViewIdx);
142 uint32_t bufferViewIdx = getBufferViewIdxFromAccessorIdx(loadData, accessorIdx);
143 assert(this->bufferViewDecomps.contains(bufferViewIdx) &&
"BufferView not registered as Meshopt compressed");
144 BufferViewDecomp & bvd = this->bufferViewDecomps[bufferViewIdx];
147 case Mode::ATTRIBUTES:
return this->processAttributes(bvd, loadData, accessorIdx);
148 case Mode::INDICES:
return this->processIndices(bvd, loadData, accessorIdx);
149 case Mode::TRIANGLES:
return this->processTriangles(bvd, loadData, accessorIdx);
151 LOG_ERROR(logger,
"Unknown 'EXT_meshopt_compression' mode: %d",
int(bvd.mode));
162 return accessor.bufferView;
168 switch (accessor.componentType) {
169 case GltfLoader::AccessorComponentType::UnsignedByte:
170 accessor.min.s_float[idx] = accessor.min.s_float[idx] / 255.0f;
171 accessor.max.s_float[idx] = accessor.max.s_float[idx] / 255.0f;
173 case GltfLoader::AccessorComponentType::Byte:
174 accessor.min.s_float[idx] = std::fmax(accessor.min.s_float[idx] / 127.0f, -1.0f);
175 accessor.max.s_float[idx] = std::fmax(accessor.max.s_float[idx] / 127.0f, -1.0f);
177 case GltfLoader::AccessorComponentType::UnsignedShort:
178 accessor.min.s_float[idx] = accessor.min.s_float[idx] / 65335.0f;
179 accessor.max.s_float[idx] = accessor.max.s_float[idx] / 65335.0f;
181 case GltfLoader::AccessorComponentType::Short:
182 accessor.min.s_float[idx] = std::fmax(accessor.min.s_float[idx] / 32767.0f, -1.0f);
183 accessor.max.s_float[idx] = std::fmax(accessor.max.s_float[idx] / 32767.0f, -1.0f);
185 case GltfLoader::AccessorComponentType::UnsignedInt:
186 accessor.min.s_float[idx] = accessor.min.s_float[idx] / float(0xFFFFFFFF);
187 accessor.max.s_float[idx] = accessor.max.s_float[idx] / float(0xFFFFFFFF);
190 LOG_ERROR(logger,
"Unhandled accessor type: %s", GltfLoader::accessorTypeName[
int(accessor.componentType)]);
198 if (accessor.minCount == 0 || accessor.maxCount == 0 || accessor.componentType == GltfLoader::AccessorComponentType::Float) {
202 if (accessor.componentType == GltfLoader::AccessorComponentType::UnsignedByte ||
203 accessor.componentType == GltfLoader::AccessorComponentType::UnsignedShort ||
204 accessor.componentType == GltfLoader::AccessorComponentType::UnsignedInt) {
205 accessor.min.s_float[0] = float(accessor.min.s_uint[0]);
206 accessor.max.s_float[0] = float(accessor.max.s_uint[0]);
208 else if (accessor.componentType == GltfLoader::AccessorComponentType::Byte ||
209 accessor.componentType == GltfLoader::AccessorComponentType::Short) {
210 accessor.min.s_float[0] = float(accessor.min.s_int[0]);
211 accessor.max.s_float[0] = float(accessor.max.s_int[0]);
214 assert(
false &&
"Unsupported component type");
217 if (accessor.normalized) {
218 normalizeBBoxValue(accessor, 0);
229 LOG_DEBUG(logger,
" accessor(%d): bufferView=%d, byteOffset=%d, cType=%s, count=%d, normalized=%s",
230 accessorIdx, accessor.bufferView, accessor.byteOffset, GltfLoader::accessorComponentTypeName[
int(accessor.componentType)], accessor.count, accessor.normalized ?
"TRUE" :
"FALSE");
231 LOG_DEBUG(logger,
" Already decompressed: %s", this->decompressedBufferViews.contains(accessor.bufferView) ?
"TRUE" :
"FALSE");
235 if (!this->decompressedBufferViews.contains(accessor.bufferView)) {
239 membuf->resize(bvd.count * bvd.byteStride);
240 uint8_t * targetBuffer =
static_cast<uint8_t*
>(membuf->data());
242 const unsigned char* vbuf = &(loadData.buffer_data[bvd.bufferIdx].data())[bvd.byteOffset];
243 int err = meshopt_decodeVertexBuffer(targetBuffer, bvd.count, bvd.byteStride, vbuf, bvd.byteLength);
245 LOG_ERROR(logger,
"The meshopt lib failed decoding the vertex buffer. Return value: %d", err);
247 case -1: LOG_ERROR(logger,
" -> error(-1): Illegal header data");
break;
248 case -2: LOG_ERROR(logger,
" -> error(-2): Index out of bounds");
break;
249 case -3: LOG_ERROR(logger,
" -> error(-3): Could not process all data");
break;
255 if (bvd.filter != Filter::NONE) {
256 int filterSize = bvd.count;
257 bool ok = this->transformData(targetBuffer, filterSize, bvd.byteStride, bvd.filter);
259 LOG_ERROR(logger,
"Error filtering vertices");
266 int newStride = bvd.byteStride;
268 if (accessor.componentType != GltfLoader::AccessorComponentType::Float) {
271 convertedMemBuf = &this->memoryBuffers.back();
273 if (accessor.type == GltfLoader::AccessorType::Vec3) {
274 newBDV = GltfLoader::convertVecBufferToFloats<glm::vec3>(tmpBufferDataView, accessor.componentType, convertedMemBuf, accessor.normalized);
276 else if (accessor.type == GltfLoader::AccessorType::Vec2) {
277 newBDV = GltfLoader::convertVecBufferToFloats<glm::vec2>(tmpBufferDataView, accessor.componentType, convertedMemBuf, accessor.normalized);
279 else if (accessor.type == GltfLoader::AccessorType::Vec4) {
280 newBDV = GltfLoader::convertVecBufferToFloats<glm::vec4>(tmpBufferDataView, accessor.componentType, convertedMemBuf, accessor.normalized);
283 newStride = newBDV.stride;
287 this->decompressedBufferViews.insert(accessor.bufferView);
290 assert(convertedMemBuf->size() > 0);
291 size_t newBufferIdx = loadData.buffer_data.size();
292 loadData.buffer_data.push_back(std::span<const uint8_t>(
static_cast<uint8_t*
>(convertedMemBuf->data()),
static_cast<uint8_t*
>(convertedMemBuf->data()) + convertedMemBuf->size()));
293 loadData.buffer_views[accessor.bufferView].buffer = uint32_t(newBufferIdx);
294 loadData.buffer_views[accessor.bufferView].byteOffset = 0;
295 loadData.buffer_views[accessor.bufferView].byteLength = uint32_t(convertedMemBuf->size());
296 loadData.buffer_views[accessor.bufferView].byteStride = newStride;
300 if (accessor.type == GltfLoader::AccessorType::Vec3) {
301 this->convertVecAccessorBBoxToFloat<glm::vec3>(accessor);
303 else if (accessor.type == GltfLoader::AccessorType::Vec2) {
304 this->convertVecAccessorBBoxToFloat<glm::vec2>(accessor);
306 else if (accessor.type == GltfLoader::AccessorType::Vec4) {
307 this->convertVecAccessorBBoxToFloat<glm::vec4>(accessor);
309 else if (accessor.type == GltfLoader::AccessorType::Scalar) {
310 this->convertScalarAccessorBBoxToFloat(accessor);
313 LOG_WARNING(logger,
"Unknown bbox type: %s", GltfLoader::accessorTypeName[
int(accessor.type)]);
317 const int newOffset = (accessor.byteOffset / bvd.byteStride) * loadData.buffer_views[accessor.bufferView].byteStride;
318 loadData.accessors[accessorIdx].byteOffset = newOffset;
319 loadData.accessors[accessorIdx].componentType = GltfLoader::AccessorComponentType::Float;
330 LOG_DEBUG(logger,
"processIndices (bufferIdx=%d, count=%d, stride=%d, offset=%d, byteLen=%d, filter=%d)", bvd.bufferIdx, bvd.count, bvd.byteStride, bvd.byteOffset, bvd.byteLength, bvd.filter);
331 LOG_DEBUG(logger,
" accessor: bufferView=%d, byteOffset=%d, cType=%s, count=%d, normalized=%s",
332 accessor.bufferView, accessor.byteOffset, GltfLoader::accessorComponentTypeName[
int(accessor.componentType)], accessor.count, accessor.normalized ?
"TRUE" :
"FALSE");
333 LOG_DEBUG(logger,
" Already decompressed: %s", this->decompressedBufferViews.contains(accessor.bufferView) ?
"TRUE" :
"FALSE");
337 if (!this->decompressedBufferViews.contains(accessor.bufferView)) {
339 const unsigned char* ibuf = &(loadData.buffer_data[bvd.bufferIdx].data())[bvd.byteOffset];
344 membuf->resize(bvd.count * bvd.byteStride);
345 uint8_t* targetBuffer =
static_cast<uint8_t*
>(membuf->data());
347 int err = meshopt_decodeIndexSequence(
reinterpret_cast<uint32_t*
>(targetBuffer), bvd.count, ibuf, bvd.byteLength);
349 LOG_ERROR(logger,
"The meshopt lib failed decoding the index sequence. Return value: %d", err);
351 case -1: LOG_ERROR(logger,
" -> error(-1): Illegal header data");
break;
352 case -2: LOG_ERROR(logger,
" -> error(-2): Index out of bounds");
break;
353 case -3: LOG_ERROR(logger,
" -> error(-3): Could not process all the data");
break;
360 this->decompressedBufferViews.insert(accessor.bufferView);
363 size_t newBufferIdx = loadData.buffer_data.size();
364 loadData.buffer_data.push_back(std::span<const uint8_t>(
static_cast<uint8_t*
>(membuf->data()),
static_cast<uint8_t*
>(membuf->data()) + membuf->size()));
365 loadData.buffer_views[accessor.bufferView].buffer = uint32_t(newBufferIdx);
366 loadData.buffer_views[accessor.bufferView].byteOffset = 0;
367 loadData.buffer_views[accessor.bufferView].byteLength = uint32_t(membuf->size());
368 loadData.buffer_views[accessor.bufferView].byteStride = bvd.byteStride;
372 const int newOffset = (accessor.byteOffset / bvd.byteStride) * loadData.buffer_views[accessor.bufferView].byteStride;
373 loadData.accessors[accessorIdx].byteOffset = newOffset;
384 LOG_DEBUG(logger,
"processTriangles (bufferIdx=%d, count=%d, stride=%d, offset=%d, byteLen=%d, filter=%d). accessorIdx=%d",
385 bvd.bufferIdx, bvd.count, bvd.byteStride, bvd.byteOffset, bvd.byteLength, bvd.filter, accessorIdx);
386 LOG_DEBUG(logger,
" accessor: bufferView=%d, byteOffset=%d, cType=%s, count=%d, normalized=%s",
387 accessor.bufferView, accessor.byteOffset, GltfLoader::accessorComponentTypeName[(
int)accessor.componentType], accessor.count, accessor.normalized ?
"TRUE" :
"FALSE");
388 LOG_DEBUG(logger,
" Already decompressed: %s", this->decompressedBufferViews.contains(accessor.bufferView) ?
"TRUE" :
"FALSE");
392 if (!this->decompressedBufferViews.contains(accessor.bufferView)) {
393 const unsigned char* ibuf = &(loadData.buffer_data[bvd.bufferIdx].data())[bvd.byteOffset];
397 membuf->resize(bvd.count * bvd.byteStride);
398 uint8_t * targetBuffer =
static_cast<uint8_t*
>(membuf->data());
401 switch (bvd.byteStride) {
403 err = meshopt_decodeIndexBuffer(
reinterpret_cast<uint16_t*
>(targetBuffer), bvd.count, ibuf, bvd.byteLength);
406 err = meshopt_decodeIndexBuffer(
reinterpret_cast<uint32_t*
>(targetBuffer), bvd.count, ibuf, bvd.byteLength);
409 LOG_ERROR(logger,
"Illegal byte-stride for compressed indices: %d. Must be 2 or 4.", bvd.byteStride);
414 LOG_ERROR(logger,
"The meshopt lib failed decoding the triangles/index buffer. Error code: %d", err);
416 case -1: LOG_ERROR(logger,
" error(-1): Illegal header data");
break;
417 case -2: LOG_ERROR(logger,
" error(-2): Index out of bounds");
break;
418 case -3: LOG_ERROR(logger,
" error(-3): Could not process all the data");
break;
425 this->decompressedBufferViews.insert(accessor.bufferView);
428 size_t newBufferIdx = loadData.buffer_data.size();
429 loadData.buffer_data.push_back(std::span<const uint8_t>(
static_cast<uint8_t*
>(membuf->data()),
static_cast<uint8_t*
>(membuf->data()) + membuf->size()));
430 loadData.buffer_views[accessor.bufferView].buffer = uint32_t(newBufferIdx);
431 loadData.buffer_views[accessor.bufferView].byteOffset = 0;
432 loadData.buffer_views[accessor.bufferView].byteLength = uint32_t(membuf->size());
433 loadData.buffer_views[accessor.bufferView].byteStride = bvd.byteStride;
437 const int newOffset = (accessor.byteOffset / bvd.byteStride) * loadData.buffer_views[accessor.bufferView].byteStride;
438 loadData.accessors[accessorIdx].byteOffset = newOffset;
bool registerBufferViewCompression(uint32_t bufferViewIdx, const GltfLoader::Object &properties)
Returns false if something failed.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept