LNXLoader.js 4.12 KB
import { FileLoader, Loader, BufferGeometry, BufferAttribute, Float32BufferAttribute } from 'three';

const intbyte = 4;
const floatbyte = 4;
const charbyte = 1;

const transferToGeometry = (meshstruct) => {
    const { vertex, index } = meshstruct;
    const geometry = new BufferGeometry();
    if (index.length > 0) {
        geometry.setIndex(new BufferAttribute(new Uint32Array(index), 1));
    }
    if (vertex.length > 0) {
        geometry.setAttribute('position', new BufferAttribute(new Float32Array(vertex), 3));
    }
    geometry.setAttribute('uv', new Float32BufferAttribute([], 2));
    geometry.computeVertexNormals();
    return geometry;
};

const ensureBinary = (buf) => {
    if (typeof buf === 'string') {
        const arraybuffer = new Uint8Array(buf.length);
        for (let i = 0; i < buf.length; i++) {
            arraybuffer[i] = buf.charCodeAt(i) & 0xff;
        }
        return arraybuffer.buffer || arraybuffer;
    }
    return buf;
};

class LNXLoader extends Loader {
    constructor(manager) {
        super(manager);
    }

    load = (url, onLoad, onProgress, onError) => {
        const loader = new FileLoader(this.manager);
        loader.setPath(this.path);
        loader.setResponseType('arraybuffer');
        loader.setRequestHeader(this.requestHeader);
        loader.setWithCredentials(this.withCredentials);

        loader.load(
            url,
            function (data) {
                try {
                    onLoad(parseLNXData(data));
                } catch (e) {
                    handleLoadError(e, url, onError);
                }
            },
            onProgress,
            function (error) {
                handleLoadError(error, url, onError);
            }
        );
    };

    parse = (binaryData) => {
        const data = ensureBinary(binaryData);
        const reader = new DataView(data);
        // console.log(data);

        let headerName = '';
        let start = 0;
        const documentNameLength = reader.getUint32(start, true);
        start += intbyte;
        for (let i = 0; i < documentNameLength; i++) {
            const str = reader.getUint8(start, true);
            headerName += String.fromCharCode(str);
            start += charbyte;
        }

        if (headerName !== 'LuxAlign data structure') {
            return {
                type: 'LnxModel',
                geometry: null
            };
        }

        const version = reader.getFloat32(start, true);
        start += floatbyte;

        start += 2; // 'pt' string'

        const numberOfVertex = reader.getUint32(start, true);
        // console.log(numberOfVertex);

        start += intbyte;
        const vertices = [];
        let count = 0;
        while (count < numberOfVertex) {
            const x = reader.getFloat32(start, true);
            start += floatbyte;
            const y = reader.getFloat32(start, true);
            start += floatbyte;
            const z = reader.getFloat32(start, true);
            start += floatbyte;
            vertices.push(x, y, z);
            ++count;
        }

        // console.log(vertices);

        start += 3; // 'tri' string'

        const numberOfIndex = reader.getUint32(start, true);
        // console.log(numberOfIndex);

        start += intbyte;
        const indices = [];
        count = 0;
        while (count < numberOfIndex) {
            const x = reader.getUint32(start, true);
            start += intbyte;
            const y = reader.getUint32(start, true);
            start += intbyte;
            const z = reader.getUint32(start, true);
            start += intbyte;
            indices.push(x, y, z);
            ++count;
        }

        // console.log(indices);

        const geometry = transferToGeometry({
            vertex: vertices,
            index: indices
        });

        return {
            type: 'LnxModel',
            geometry
        };
    };
}

function parseLNXData(data) {
    return new LNXLoader().parse(data);
}

function handleLoadError(error, url, onError) {
    if (onError) {
        onError(error);
    } else {
        console.error(error);
    }

    new LNXLoader().manager.itemError(url);
}

export { LNXLoader };