threepipe
Version:
A 3D viewer framework built on top of three.js in TypeScript with a focus on quality rendering, modularity and extensibility.
115 lines • 4.46 kB
JavaScript
import { DataUtils, FloatType, HalfFloatType, LinearSRGBColorSpace, UnsignedByteType, } from 'three';
import { canvasFlipY, LinearToSRGB } from 'ts-browser-helpers';
export function getTextureDataType(renderer) {
if (!renderer)
return UnsignedByteType;
const halfFloatSupport = renderer.extensions.has('EXT_color_buffer_half_float') || renderer.capabilities.isWebGL2 && renderer.extensions.has('EXT_color_buffer_float');
const floatSupport = renderer.capabilities.isWebGL2 || renderer.extensions.has('OES_texture_float') || renderer.extensions.has('WEBGL_color_buffer_float');
return halfFloatSupport ? HalfFloatType : floatSupport ? FloatType : UnsignedByteType;
}
export function textureDataToImageData(imgData, colorSpace, outData) {
const data = outData?.data ?? new Uint8ClampedArray(imgData.height * imgData.width * 4);
const isFloat32 = imgData.data instanceof Float32Array;
const isUint16 = imgData.data instanceof Uint16Array;
for (let i = 0; i < data.length; i++) {
if (isFloat32) { // Float32
data[i] = imgData.data[i] * 255;
}
else if (isUint16) { // Uint16 (half float)
data[i] = DataUtils.fromHalfFloat(imgData.data[i]) * 255;
}
else { // Uint8
data[i] = imgData.data[i];
}
if (colorSpace === LinearSRGBColorSpace) {
data[i] = LinearToSRGB(data[i] / 255.0) * 255;
}
// todo: rgbm?
}
return outData ?? new ImageData(data, imgData.width, imgData.height);
}
/**
*
* @param texture
* @param maxWidth
* @param flipY
* @param canvas
*/
export function textureToCanvas(texture, maxWidth, flipY = false) {
let img;
if (texture.isDataTexture)
img = textureDataToImageData(texture.image, texture.colorSpace);
else
img = texture.image;
return texImageToCanvas(img, maxWidth, flipY);
}
export function texImageToCanvas(image, maxWidth, flipY = false) {
let width, height;
if (!window.VideoFrame)
window.VideoFrame = HTMLVideoElement;
if (image instanceof window.VideoFrame) {
width = image.displayWidth;
height = image.displayHeight;
}
else {
width = image.width;
height = image.height;
}
if (window.VideoFrame === HTMLVideoElement)
delete window.VideoFrame;
const canvas = document.createElement('canvas');
// resize it to the size of our image
canvas.width = Math.min(maxWidth, width);
canvas.height = Math.floor(1.0 + canvas.width * height / width);
const ctx = canvas.getContext('2d');
if (!ctx) {
console.error('textureToDataUrl: could not get canvas context');
return canvas;
}
if (flipY === true) {
ctx.translate(0, canvas.height);
ctx.scale(1, -1);
}
let needsFlipY = false;
if (image.data !== undefined) { // THREE.DataTexture
const imageData = image;
if (width !== canvas.width || height !== canvas.height) {
const tempCanvas = document.createElement('canvas');
tempCanvas.width = width;
tempCanvas.height = height;
const tempCtx = tempCanvas.getContext('2d');
if (!tempCtx) {
console.error('textureToDataUrl: could not get temp canvas context');
ctx.putImageData(imageData, 0, 0);
}
else {
tempCtx.putImageData(imageData, 0, 0); // for resize
ctx.drawImage(tempCanvas, 0, 0, canvas.width, canvas.height);
}
}
else {
ctx.putImageData(imageData, 0, 0);
if (flipY)
needsFlipY = true; // because of putImageData
}
}
else {
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
}
return !needsFlipY ? canvas : canvasFlipY(canvas);
}
export function textureToDataUrl(texture, maxWidth, flipY, mimeType, quality) {
return textureToCanvas(texture, maxWidth, flipY).toDataURL(mimeType, quality);
}
export async function textureToBlob(texture, maxWidth, flipY, mimeType, quality) {
const canvas = textureToCanvas(texture, maxWidth, flipY);
return new Promise((resolve, reject) => {
canvas.toBlob(blob => {
if (blob)
resolve(blob);
else
reject(new Error('Failed to create blob'));
}, mimeType, quality);
});
}
//# sourceMappingURL=texture.js.map