mirror of
https://github.com/alibaba/GCanvas.git
synced 2025-12-08 17:36:42 +00:00
211 lines
5.8 KiB
JavaScript
211 lines
5.8 KiB
JavaScript
const { createCanvas, Image } = require('../../export')
|
|
const fs = require('fs')
|
|
const path = require('path');
|
|
|
|
const out = fs.createWriteStream(path.join(__dirname, "..","..")+ '/stencil.png');
|
|
const canvas = createCanvas(600, 600);
|
|
var gl = canvas.getContext("webgl");
|
|
var width;
|
|
var height;
|
|
var program = null;
|
|
var program2 = null;
|
|
var samplerUniform = null;
|
|
var maskTexture;
|
|
|
|
var shader_fs_2 = "precision highp float;\
|
|
varying vec2 vTextureCoord;\
|
|
uniform sampler2D uSampler;\
|
|
void main(void) {\
|
|
gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));\
|
|
if (gl_FragColor.a == 0.0) {\
|
|
discard;\
|
|
}\
|
|
}"
|
|
|
|
var shader_vs_2 = "precision highp float;\
|
|
attribute vec3 aPos;\
|
|
attribute vec2 aTextureCoords;\
|
|
varying vec2 vTextureCoord;\
|
|
void main(void){\
|
|
gl_Position = vec4(aPos, 1.0);\
|
|
vTextureCoord = aTextureCoords;\
|
|
}"
|
|
|
|
var shader_vs = "precision highp float;\
|
|
attribute vec3 aPos;\
|
|
attribute vec4 aColor;\
|
|
varying vec4 vColor;\
|
|
void main(void){\
|
|
gl_Position = vec4(aPos, 1);\
|
|
vColor = aColor;\
|
|
}"
|
|
|
|
var shader_fs = "precision highp float;\
|
|
varying vec4 vColor;\
|
|
void main(void) {\
|
|
gl_FragColor = vColor;\
|
|
}"
|
|
|
|
function getGLContext() {
|
|
if (gl) {
|
|
gl.clearColor(74 / 255, 115 / 255, 94 / 255, 1.0);
|
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
|
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
gl.enable(gl.STENCIL_TEST);
|
|
}
|
|
}
|
|
|
|
function initShaders(vs_source, fs_source) {
|
|
//compile shaders
|
|
var vertexShader = makeShader(vs_source, gl.VERTEX_SHADER);
|
|
var fragmentShader = makeShader(fs_source, gl.FRAGMENT_SHADER);
|
|
|
|
//create program
|
|
var glProgram = gl.createProgram();
|
|
|
|
//attach and link shaders to the program
|
|
gl.attachShader(glProgram, vertexShader);
|
|
gl.attachShader(glProgram, fragmentShader);
|
|
gl.linkProgram(glProgram);
|
|
|
|
if (!gl.getProgramParameter(glProgram, gl.LINK_STATUS)) {
|
|
alert("Unable to initialize the shader program.");
|
|
}
|
|
|
|
//use program
|
|
// gl.useProgram(glProgram);
|
|
return glProgram;
|
|
}
|
|
|
|
function makeShader(src, type) {
|
|
//compile the vertex shader
|
|
var shader = gl.createShader(type);
|
|
gl.shaderSource(shader, src);
|
|
gl.compileShader(shader);
|
|
|
|
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
alert("Error compiling shader: " + gl.getShaderInfoLog(shader));
|
|
}
|
|
return shader;
|
|
}
|
|
// vertex representing the triangle
|
|
var vertex = [
|
|
-.5, -.2, 0,
|
|
.5, -.2, 0,
|
|
0, .6, 0
|
|
];
|
|
var stencilVertex = [
|
|
-.2, -.5, 0,
|
|
.4, -.5, 0,
|
|
.3, .6, 0
|
|
];
|
|
function setupBufferAndDraw() {
|
|
// draw the mask image as stencil
|
|
gl.useProgram(program2);
|
|
var maskVertex = [
|
|
-1, -1, 0,
|
|
1, -1, 0,
|
|
1, 1, 0,
|
|
-1, -1, 0,
|
|
1, 1, 0,
|
|
-1, 1, 0
|
|
];
|
|
var maskTexCoords = [
|
|
0, 0,
|
|
1, 0,
|
|
1, 1,
|
|
0, 0,
|
|
1, 1,
|
|
0, 1
|
|
];
|
|
var maskBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, maskBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(maskVertex), gl.STATIC_DRAW);
|
|
|
|
var aMaskVertexPosition = gl.getAttribLocation(program2, 'aPos');
|
|
gl.vertexAttribPointer(aMaskVertexPosition, 3, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(aMaskVertexPosition);
|
|
|
|
// texture coordinate data
|
|
var maskTexCoordBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, maskTexCoordBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(maskTexCoords), gl.STATIC_DRAW);
|
|
|
|
var vertexTexCoordAttribute = gl.getAttribLocation(program2, "aTextureCoords");
|
|
gl.enableVertexAttribArray(vertexTexCoordAttribute);
|
|
gl.vertexAttribPointer(vertexTexCoordAttribute, 2, gl.FLOAT, false, 0, 0);
|
|
|
|
// Always pass test
|
|
gl.stencilFunc(gl.ALWAYS, 1, 0xff);
|
|
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
|
|
gl.stencilMask(0xff);
|
|
gl.clear(gl.STENCIL_BUFFER_BIT);
|
|
// No need to display the triangle
|
|
gl.colorMask(0, 0, 0, 0);
|
|
|
|
gl.activeTexture(gl.TEXTURE0);
|
|
gl.bindTexture(gl.TEXTURE_2D, maskTexture);
|
|
gl.uniform1i(samplerUniform, 0);
|
|
|
|
gl.drawArrays(gl.TRIANGLES, 0, maskVertex.length / 3);
|
|
// return;
|
|
gl.useProgram(program);
|
|
// Pass test if stencil value is 1
|
|
gl.stencilFunc(gl.EQUAL, 1, 0xFF);
|
|
gl.stencilMask(0x00);
|
|
gl.colorMask(1, 1, 1, 1);
|
|
// draw the clipped triangle
|
|
var color = [
|
|
1, 0, 0, 1,
|
|
0, 1, 0, 1,
|
|
0, 0, 1, 1
|
|
];
|
|
var colorBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(color), gl.STATIC_DRAW);
|
|
|
|
var aColorPosition = gl.getAttribLocation(program, 'aColor');
|
|
gl.vertexAttribPointer(aColorPosition, 4, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(aColorPosition);
|
|
|
|
var vertexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertex), gl.STATIC_DRAW);
|
|
|
|
var aVertexPosition = gl.getAttribLocation(program, 'aPos');
|
|
gl.vertexAttribPointer(aVertexPosition, 3, gl.FLOAT, false, 0, 0);
|
|
gl.enableVertexAttribArray(aVertexPosition);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
gl.drawArrays(gl.TRIANGLES, 0, vertex.length / 3);
|
|
}
|
|
|
|
function createTexture(source) {
|
|
var texture = gl.createTexture();
|
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, source);
|
|
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
return texture;
|
|
}
|
|
|
|
height = canvas.height;
|
|
width = canvas.width;
|
|
|
|
getGLContext();
|
|
program = initShaders(shader_vs, shader_fs);
|
|
program2 = initShaders(shader_vs_2, shader_fs_2);
|
|
samplerUniform = gl.getUniformLocation(program2, 'uSampler');
|
|
|
|
var img = new Image();
|
|
img.onload = function() {
|
|
maskTexture = createTexture(img);
|
|
setupBufferAndDraw();
|
|
var stream = canvas.createPNGStream();
|
|
stream.on('data', function (chunk) {
|
|
out.write(chunk);
|
|
});
|
|
};
|
|
img.crossOrigin = "";
|
|
img.src = 'https://img.alicdn.com/tfs/TB1edrqL7Y2gK0jSZFgXXc5OFXa-128-128.png'; |