// loaders.gl // SPDX-License-Identifier: MIT // Copyright (c) vis.gl contributors import { getMeshBoundingBox } from '@loaders.gl/schema'; import decode, { DECODING_STEPS } from "./decode-quantized-mesh.js"; import { addSkirt } from "./helpers/skirt.js"; export function parseQuantizedMesh(arrayBuffer, options = {}) { const { bounds } = options; // Don't parse edge indices or format extensions const { header, vertexData, triangleIndices: originalTriangleIndices, westIndices, northIndices, eastIndices, southIndices } = decode(arrayBuffer, DECODING_STEPS.triangleIndices); let triangleIndices = originalTriangleIndices; let attributes = getMeshAttributes(vertexData, header, bounds); // Compute bounding box before adding skirt so that z values are not skewed // TODO: Find bounding box from header, instead of doing extra pass over // vertices. const boundingBox = getMeshBoundingBox(attributes); if (options?.skirtHeight) { const { attributes: newAttributes, triangles: newTriangles } = addSkirt(attributes, triangleIndices, options.skirtHeight, { westIndices, northIndices, eastIndices, southIndices }); attributes = newAttributes; triangleIndices = newTriangles; } return { // Data return by this loader implementation loaderData: { header: {} }, header: { // @ts-ignore vertexCount: triangleIndices.length, boundingBox }, // TODO schema: undefined, topology: 'triangle-list', mode: 4, // TRIANGLES indices: { value: triangleIndices, size: 1 }, attributes }; } function getMeshAttributes(vertexData, header, bounds) { const { minHeight, maxHeight } = header; const [minX, minY, maxX, maxY] = bounds || [0, 0, 1, 1]; const xScale = maxX - minX; const yScale = maxY - minY; const zScale = maxHeight - minHeight; const nCoords = vertexData.length / 3; // vec3. x, y defined by bounds, z in meters const positions = new Float32Array(nCoords * 3); // vec2. 1 to 1 relationship with position. represents the uv on the texture image. 0,0 to 1,1. const texCoords = new Float32Array(nCoords * 2); // Data is not interleaved; all u, then all v, then all heights for (let i = 0; i < nCoords; i++) { const x = vertexData[i] / 32767; const y = vertexData[i + nCoords] / 32767; const z = vertexData[i + nCoords * 2] / 32767; positions[3 * i + 0] = x * xScale + minX; positions[3 * i + 1] = y * yScale + minY; positions[3 * i + 2] = z * zScale + minHeight; texCoords[2 * i + 0] = x; texCoords[2 * i + 1] = y; } return { POSITION: { value: positions, size: 3 }, TEXCOORD_0: { value: texCoords, size: 2 } // TODO: Parse normals if they exist in the file // NORMAL: {}, - optional, but creates the high poly look with lighting }; }