Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@typescript-eslint/eslint-plugin": "^8.53.0",
"@typescript-eslint/parser": "^8.53.0",
"babel-loader": "^10.0.0",
"brotli": "^1.3.3",
"circular-dependency-plugin": "^5.2.2",
"commitizen": "^4.3.1",
"css-loader": "^7.1.2",
Expand Down
132 changes: 132 additions & 0 deletions src/loading2/brotli-decoder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import { BufferAttribute, BufferGeometry } from 'three';
import { XhrRequest } from '../loading/types';
import { DecodedGeometry, GeometryDecoder } from './geometry-decoder';
import { OctreeGeometryNode } from './octree-geometry-node';
import { LoadingContext, Metadata } from './octree-loader';
import { WorkerType } from './worker-pool';

// Buffer files for DEFAULT encoding
export const HIERARCHY_FILE = 'hierarchy.bin';
export const OCTREE_FILE = 'octree.bin';

export class BrotliDecoder implements GeometryDecoder {
public readonly workerType = WorkerType.DECODER_WORKER_BROTLI;
private _metadata: Metadata;

constructor(
public metadata: Metadata,
private context: LoadingContext,
) {
this._metadata = metadata;
}

async decode(node: OctreeGeometryNode, worker: Worker): Promise<DecodedGeometry> {
const { byteOffset, byteSize } = node;

if (byteOffset === undefined || byteSize === undefined) {
throw new Error('byteOffset and byteSize are required');
}

if (byteSize === BigInt(0)) {
// If bytesize is zero, skip the worker step and return empty DecodedGeometry
return {
buffer: new ArrayBuffer(0),
geometry: new BufferGeometry(),
data: {
tightBoundingBox: { min: [0, 0, 0], max: [0, 0, 0] },
},
};
}

const urlOctree = await this.getUrl(this.octreePath);

const first = byteOffset;
const last = byteOffset + byteSize - BigInt(1);

const headers = { Range: `bytes=${first}-${last}` };
const response = await this.xhrRequest(urlOctree, { headers });

const buffer = await response.arrayBuffer();

const pointAttributes = node.octreeGeometry.pointAttributes;
const scale = node.octreeGeometry.scale;

const box = node.boundingBox;
const min = node.octreeGeometry.offset.clone().add(box.min);
const size = box.max.clone().sub(box.min);
const max = min.clone().add(size);
const numPoints = node.numPoints;

const offset = this._metadata.offset;

const message = {
name: node.name,
buffer: buffer,
pointAttributes: pointAttributes,
scale: scale,
min: min,
max: max,
size: size,
offset: offset,
numPoints: numPoints,
};

worker.postMessage(message, [message.buffer]);

const doneEvent = await new Promise<MessageEvent<any>>((res) => {
worker.onmessage = res;
});

return this.readSuccessMessage(doneEvent, buffer);
}

private get getUrl() {
return this.context.getUrl;
}

private get xhrRequest(): XhrRequest {
return this.context.xhrRequest;
}

private get octreePath() {
return this.context.octreePath;
}

private readSuccessMessage(e: MessageEvent<any>, buffer: ArrayBuffer) {
const data = e.data;
const buffers = data.attributeBuffers;
const geometry = new BufferGeometry();

for (const property in buffers) {

Check warning on line 100 in src/loading2/brotli-decoder.ts

View workflow job for this annotation

GitHub Actions / lint

Using 'ForInStatement' is not allowed
const buffer = buffers[property].buffer;

if (property === 'position') {
geometry.setAttribute('position', new BufferAttribute(new Float32Array(buffer), 3));
} else if (property === 'rgba') {
geometry.setAttribute('rgba', new BufferAttribute(new Uint8Array(buffer), 4, true));
} else if (property === 'NORMAL') {
geometry.setAttribute('normal', new BufferAttribute(new Float32Array(buffer), 3));
} else if (property === 'INDICES') {
const bufferAttribute = new BufferAttribute(new Uint8Array(buffer), 4);
bufferAttribute.normalized = true;
geometry.setAttribute('indices', bufferAttribute);
} else {
const bufferAttribute: BufferAttribute & {
potree?: object;
} = new BufferAttribute(new Float32Array(buffer), 1);

const batchAttribute = buffers[property].attribute;
bufferAttribute.potree = {
offset: buffers[property].offset,
scale: buffers[property].scale,
preciseBuffer: buffers[property].preciseBuffer,
range: batchAttribute.range,
};

geometry.setAttribute(property, bufferAttribute);
}
}

return { data, buffer, geometry };
}
}
Loading
Loading