UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

102 lines (101 loc) 3.69 kB
import { ShaderUtils } from "../../scene/shader-lib/shader-utils.js"; import { Texture } from "../../platform/graphics/texture.js"; import { BlendState } from "../../platform/graphics/blend-state.js"; import { drawQuadWithShader } from "../../scene/graphics/quad-render-utils.js"; import { RenderTarget } from "../../platform/graphics/render-target.js"; import { FILTER_LINEAR, ADDRESS_CLAMP_TO_EDGE, isCompressedPixelFormat, PIXELFORMAT_RGBA8, SEMANTIC_POSITION } from "../../platform/graphics/constants.js"; class CoreExporter { // eslint-disable-next-line no-useless-constructor constructor() { } textureToCanvas(texture, options = {}) { const image = texture.getSource(); if (typeof HTMLImageElement !== "undefined" && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== "undefined" && image instanceof HTMLCanvasElement || typeof OffscreenCanvas !== "undefined" && image instanceof OffscreenCanvas || typeof ImageBitmap !== "undefined" && image instanceof ImageBitmap) { const { width: width2, height: height2 } = this.calcTextureSize(image.width, image.height, options.maxTextureSize); const canvas = document.createElement("canvas"); canvas.width = width2; canvas.height = height2; const context = canvas.getContext("2d"); if (context === null) { return Promise.resolve(void 0); } context.drawImage(image, 0, 0, canvas.width, canvas.height); if (options.color) { const { r, g, b } = options.color; const imagedata = context.getImageData(0, 0, width2, height2); const data = imagedata.data; for (let i = 0; i < data.length; i += 4) { data[i + 0] = data[i + 0] * r; data[i + 1] = data[i + 1] * g; data[i + 2] = data[i + 2] * b; } context.putImageData(imagedata, 0, 0); } return Promise.resolve(canvas); } const device = texture.device; const { width, height } = this.calcTextureSize(texture.width, texture.height, options.maxTextureSize); const format = isCompressedPixelFormat(texture.format) ? PIXELFORMAT_RGBA8 : texture.format; const dstTexture = new Texture(device, { name: "ExtractedTexture", width, height, format, cubemap: false, mipmaps: false, minFilter: FILTER_LINEAR, magFilter: FILTER_LINEAR, addressU: ADDRESS_CLAMP_TO_EDGE, addressV: ADDRESS_CLAMP_TO_EDGE }); const renderTarget = new RenderTarget({ colorBuffer: dstTexture, depth: false }); const shader = ShaderUtils.createShader(device, { uniqueName: "ShaderCoreExporterBlit", attributes: { vertex_position: SEMANTIC_POSITION }, vertexChunk: "fullscreenQuadVS", fragmentChunk: "outputTex2DPS" }); device.scope.resolve("source").setValue(texture); device.setBlendState(BlendState.NOBLEND); drawQuadWithShader(device, renderTarget, shader); return dstTexture.read(0, 0, width, height, { renderTarget, immediate: true }).then((textureData) => { dstTexture.destroy(); renderTarget.destroy(); const pixels = new Uint8ClampedArray(width * height * 4); pixels.set(textureData); const newImage = new ImageData(pixels, width, height); const canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; const newContext = canvas.getContext("2d"); if (!newContext) { return Promise.resolve(void 0); } newContext.putImageData(newImage, 0, 0); return Promise.resolve(canvas); }); } calcTextureSize(width, height, maxTextureSize) { if (maxTextureSize) { const scale = Math.min(maxTextureSize / Math.max(width, height), 1); width = Math.round(width * scale); height = Math.round(height * scale); } return { width, height }; } } export { CoreExporter };