utils/RgbTerrainWorker.tstypescript
import { BaseWorker } from "./BaseWorker";
import { Segment } from "../segment/Segment";
import type { IRgbHeightsParams } from "../terrain/rgbTerrainGrid";
import { packRgbHeightsParams } from "../terrain/rgbTerrainGrid";
//@ts-ignore
import RgbTerrainWorkerImpl from "./RgbTerrainWorker.worker.js?worker&inline";

export interface IRgbTerrainWorkerTask {
    segment: Segment;
    bitmap: ImageBitmap;
    params: IRgbHeightsParams;
    callback: (heights: Float32Array | null) => void;
}

type MessageEventExt = MessageEvent & {
    data: {
        id: number;
        heights: Float32Array | null;
    };
};

class RgbTerrainWorker extends BaseWorker<IRgbTerrainWorkerTask> {
    constructor(numWorkers: number = 2) {
        super(numWorkers, RgbTerrainWorkerImpl);
    }

    protected override _onMessage(e: MessageEventExt) {
        let task = this._source.get(e.data.id)!;
        this._source.delete(e.data.id);
        task.callback(e.data.heights);
    }

    public override make(task: IRgbTerrainWorkerTask) {
        if (task.segment.plainReady && task.segment.terrainIsLoading) {
            if (this._workerQueue.length) {
                let w = this._workerQueue.pop()!;

                this._source.set(this._sourceId, task);

                let params = packRgbHeightsParams(this._sourceId, task.params),
                    parentData = task.params.decode.parentData;

                // Parent elevations are still used by the parent segment, so they are copied
                let parentCopy = parentData ? new Float32Array(parentData) : null;

                let transfer: Transferable[] = [params.buffer, task.bitmap];
                if (parentCopy) {
                    transfer.push(parentCopy.buffer);
                }

                w.postMessage(
                    {
                        params: params,
                        parentData: parentCopy,
                        bitmap: task.bitmap
                    },
                    transfer
                );

                this._sourceId++;
            } else {
                this._pendingQueue.push(task);
            }
        } else {
            task.bitmap.close();
            this.check();
        }
    }
}

export { RgbTerrainWorker };