Files
speckle-server/packages/frontend-2/lib/viewer/extensions/PassReader.ts
T
Kristaps Fabians Geikins 83d8035dc2 chore: upgrade to eslint 9 (#2348)
* root + server

* frontend

* frontend-2

* dui3

* dui3

* tailwind theme

* ui-components

* preview service

* viewer

* viewer-sandbox

* fileimport-service

* webhook service

* objectloader

* shared

* ui-components-nuxt

* WIP full config

* WIP full linter

* eslint projectwide util

* minor fix

* removing redundant ci

* clean up test errors

* fixed prettier formatting

* CI improvements

* TSC lint fix

* 'buildBatch' needs to be async since some batch types (like Text) require it. Removed a disabled liniting rule from ObjLoader

* removed unnecessary void

---------

Co-authored-by: AlexandruPopovici <alexandrupopoviciioan@gmail.com>
2024-06-12 14:38:02 +03:00

98 lines
3.1 KiB
TypeScript

import { type SpecklePass } from '@speckle/viewer'
import { Extension } from '@speckle/viewer'
import type SpeckleRenderer from '@speckle/viewer/dist/modules/SpeckleRenderer'
import type { WebGLRenderTarget } from 'three'
import { Vector3, Vector4 } from 'three'
export class PassReader extends Extension {
private outputBuffer: Uint8Array = new Uint8Array()
private renderTarget: WebGLRenderTarget | undefined = undefined
private needsRead: boolean = false
private readbackExecutor: ((arg: string) => void) | null = null
public async read(): Promise<string> {
return new Promise<string>((resolve, reject) => {
const renderer: SpeckleRenderer = this.viewer.getRenderer()
const dephPass: SpecklePass = renderer.pipeline.composer
.passes[0] as unknown as SpecklePass
// o_0
this.renderTarget = dephPass.outputRenderTarget
if (!this.renderTarget) {
reject('Issue with depth pass render target')
return
}
const bufferSize = this.renderTarget.width * this.renderTarget.height * 4
if (this.outputBuffer.length !== bufferSize)
this.outputBuffer = new Uint8Array(bufferSize)
this.needsRead = true
this.readbackExecutor = resolve
})
}
public onRender(): void {
if (!this.needsRead || this.renderTarget === undefined) return
this.viewer
.getRenderer()
.renderer.readRenderTargetPixels(
this.renderTarget,
0,
0,
this.renderTarget.width,
this.renderTarget.height,
this.outputBuffer
)
const UnpackDownscale = 255 / 256
const PackFactors = new Vector3(256 * 256 * 256, 256 * 256, 256)
const UnpackFactors = new Vector4(
UnpackDownscale / PackFactors.x,
UnpackDownscale / PackFactors.y,
UnpackDownscale / PackFactors.z,
1
)
const v4 = new Vector4()
for (let k = 0; k < this.outputBuffer.length; k += 4) {
v4.set(
this.outputBuffer[k] / 255,
this.outputBuffer[k + 1] / 255,
this.outputBuffer[k + 2] / 255,
this.outputBuffer[k + 3] / 255
)
const res = v4.dot(UnpackFactors)
this.outputBuffer[k] = res * 255
this.outputBuffer[k + 1] = res * 255
this.outputBuffer[k + 2] = res * 255
this.outputBuffer[k + 3] = 255
}
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
if (!ctx) return
canvas.width = this.renderTarget.width
canvas.height = this.renderTarget.height
// create imageData object
const idata = ctx.createImageData(this.renderTarget.width, this.renderTarget.height)
// set our buffer as source
idata.data.set(this.outputBuffer)
// update canvas with new data
ctx.putImageData(idata, 0, 0)
ctx.save()
/** Flipping the image by drawing it on itself
*/
ctx.globalCompositeOperation = 'copy'
ctx.scale(1, -1)
ctx.drawImage(canvas, 0, 0, this.renderTarget.width, -this.renderTarget.height)
ctx.restore()
if (this.readbackExecutor) this.readbackExecutor(canvas.toDataURL())
this.needsRead = false
}
}