@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
122 lines (107 loc) • 3.98 kB
text/typescript
import {CoreUserAgent} from './../../../../core/UserAgent';
import {Mapping, PixelFormat, WebGLRenderer} from 'three';
import {WebGLRenderTarget} from 'three';
import {DataTexture} from 'three';
import {TypeAssert} from '../../../poly/Assert';
import {Texture} from 'three';
// import {CoreImage} from '../../../../core/Image';
export enum DataTextureControllerBufferType {
Uint8Array = 'Uint8Array',
Uint8ClampedArray = 'Uint8ClampedArray',
Uint16Array = 'Uint16Array',
Float32Array = 'Float32Array',
}
export class DataTextureController {
private _dataTexture: DataTexture | undefined;
private bufferType: DataTextureControllerBufferType;
constructor(bufferType?: DataTextureControllerBufferType) {
this.bufferType =
bufferType ||
(CoreUserAgent.isiOS()
? DataTextureControllerBufferType.Uint16Array
: DataTextureControllerBufferType.Float32Array);
}
fromRenderTarget(renderer: WebGLRenderer, renderTarget: WebGLRenderTarget) {
if (!this._dataTexture || !this._sameDimensions(renderTarget.texture)) {
this._dataTexture = this._createDataTexture(renderTarget.texture);
}
this._copyToDataTexture(renderer, renderTarget);
return this._dataTexture;
}
// fromTexture(texture: Texture): DataTexture {
// const src_data = CoreImage.data_from_image(texture.image);
// if (!this._data_texture || !this._same_dimensions(texture)) {
// this._data_texture = this._create_data_texture(texture);
// }
// const length = src_data.width * src_data.height;
// const src_tex_data = src_data.data;
// const dest_ext_data = this._data_texture.image.data;
// const stride = 4;
// const l4 = length * stride;
// for (let i = 0; i < l4; i++) {
// dest_ext_data[i] = src_tex_data[i];
// // dest_ext_data[i + 1] = src_tex_data[i + 1];
// // dest_ext_data[i + 2] = src_tex_data[i + 2];
// // dest_ext_data[i + 3] = src_tex_data[i + 3];
// }
// return this._data_texture;
// }
// dataTexture() {
// return this._dataTexture;
// }
reset() {
this._dataTexture = undefined;
}
private _copyToDataTexture(renderer: WebGLRenderer, renderTarget: WebGLRenderTarget) {
const image = renderTarget.texture.image;
this._dataTexture = this._dataTexture || this._createDataTexture(renderTarget.texture);
renderer.readRenderTargetPixels(renderTarget, 0, 0, image.width, image.height, this._dataTexture.image.data);
this._dataTexture.needsUpdate = true;
}
private _createDataTexture(texture: Texture) {
const image = texture.image;
const pixelBuffer = this._createPixelBuffer(image.width, image.height);
const dataTexture = new DataTexture(
pixelBuffer,
image.width,
image.height,
texture.format as PixelFormat,
texture.type,
texture.mapping as Mapping,
texture.wrapS,
texture.wrapT,
texture.magFilter,
texture.minFilter,
texture.anisotropy,
texture.colorSpace
);
return dataTexture;
}
private _createPixelBuffer(width: number, height: number) {
const size = width * height * 4;
// for env maps:
// Uint8Array, Uint8ClampedArray
// using Float32 array gives the following error when calling readRenderTargetPixels:
// WebGL: INVALID_OPERATION: texImage2D: type UNSIGNED_BYTE but ArrayBufferView not Uint8Array or Uint8ClampedArray
switch (this.bufferType) {
case DataTextureControllerBufferType.Uint8Array:
return new Uint8Array(size);
case DataTextureControllerBufferType.Uint8ClampedArray:
return new Uint8ClampedArray(size);
case DataTextureControllerBufferType.Uint16Array:
return new Uint16Array(size);
case DataTextureControllerBufferType.Float32Array:
return new Float32Array(size);
}
TypeAssert.unreachable(this.bufferType);
}
private _sameDimensions(texture: Texture): boolean {
if (this._dataTexture) {
const sameW = this._dataTexture.image.width == texture.image.width;
const sameH = this._dataTexture.image.height == texture.image.height;
return sameW && sameH;
} else {
return true;
}
}
}