playcanvas
Version:
PlayCanvas WebGL game engine
122 lines (119 loc) • 5.87 kB
JavaScript
import { createShaderFromCode } from '../../scene/shader-lib/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 { isCompressedPixelFormat, PIXELFORMAT_RGBA8, FILTER_LINEAR, ADDRESS_CLAMP_TO_EDGE } from '../../platform/graphics/constants.js';
/**
* @import { Color } from '../../core/math/color.js'
*/ var textureBlitVertexShader = "\n attribute vec2 vertex_position;\n varying vec2 uv0;\n void main(void) {\n gl_Position = vec4(vertex_position, 0.5, 1.0);\n uv0 = vertex_position.xy * 0.5 + 0.5;\n }";
var textureBlitFragmentShader = "\n varying vec2 uv0;\n uniform sampler2D blitTexture;\n void main(void) {\n gl_FragColor = texture2D(blitTexture, uv0);\n }";
/**
* The base class for the exporters, implementing shared functionality.
*
* @category Exporter
* @ignore
*/ class CoreExporter {
/**
* Converts a texture to a canvas.
*
* @param {Texture} texture - The source texture to be converted.
* @param {object} options - Object for passing optional arguments.
* @param {Color} [options.color] - The tint color to modify the texture with.
* @param {number} [options.maxTextureSize] - Maximum texture size. Texture is resized if over the size.
* @returns {Promise<HTMLCanvasElement>|Promise<undefined>} - The canvas element containing the image.
*
* @ignore
*/ textureToCanvas(texture, options) {
if (options === undefined) options = {};
var 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) {
// texture dimensions
var { width, height } = this.calcTextureSize(image.width, image.height, options.maxTextureSize);
// convert to a canvas
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var context = canvas.getContext('2d');
if (context === null) {
return Promise.resolve(undefined);
}
context.drawImage(image, 0, 0, canvas.width, canvas.height);
// tint the texture by specified color
if (options.color) {
var { r, g, b } = options.color;
var imagedata = context.getImageData(0, 0, width, height);
var data = imagedata.data;
for(var 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);
}
// for other image sources, for example compressed textures, we extract the data by rendering the texture to a render target
var device = texture.device;
var { width: width1, height: height1 } = this.calcTextureSize(texture.width, texture.height, options.maxTextureSize);
var format = isCompressedPixelFormat(texture.format) ? PIXELFORMAT_RGBA8 : texture.format;
var dstTexture = new Texture(device, {
name: 'ExtractedTexture',
width: width1,
height: height1,
format: format,
cubemap: false,
mipmaps: false,
minFilter: FILTER_LINEAR,
magFilter: FILTER_LINEAR,
addressU: ADDRESS_CLAMP_TO_EDGE,
addressV: ADDRESS_CLAMP_TO_EDGE
});
var renderTarget = new RenderTarget({
colorBuffer: dstTexture,
depth: false
});
// render to a render target using a blit shader
var shader = createShaderFromCode(device, textureBlitVertexShader, textureBlitFragmentShader, 'ShaderCoreExporterBlit');
device.scope.resolve('blitTexture').setValue(texture);
device.setBlendState(BlendState.NOBLEND);
drawQuadWithShader(device, renderTarget, shader);
// async read back the pixels of the texture
return dstTexture.read(0, 0, width1, height1, {
renderTarget: renderTarget,
immediate: true
}).then((textureData)=>{
dstTexture.destroy();
renderTarget.destroy();
var pixels = new Uint8ClampedArray(width1 * height1 * 4);
pixels.set(textureData);
// copy pixels to a canvas
var newImage = new ImageData(pixels, width1, height1);
var canvas = document.createElement('canvas');
canvas.width = width1;
canvas.height = height1;
var newContext = canvas.getContext('2d');
if (!newContext) {
return Promise.resolve(undefined);
}
newContext.putImageData(newImage, 0, 0);
return Promise.resolve(canvas);
});
}
calcTextureSize(width, height, maxTextureSize) {
if (maxTextureSize) {
var scale = Math.min(maxTextureSize / Math.max(width, height), 1);
width = Math.round(width * scale);
height = Math.round(height * scale);
}
return {
width,
height
};
}
/**
* Create a new instance of the exporter.
*/ // eslint-disable-next-line no-useless-constructor
constructor(){}
}
export { CoreExporter };