зеркало из https://github.com/mozilla/shumway.git
Put shaders in their own separate files, implement glow and drop shadow in webgl.
This commit is contained in:
Родитель
f564b7ca36
Коммит
1fe394805a
|
@ -4,8 +4,12 @@
|
|||
<title></title>
|
||||
</head>
|
||||
<body style="background-color: #2c2c2c">
|
||||
<script>
|
||||
SHUMWAY_ROOT = "../../src/";
|
||||
</script>
|
||||
<script src="../../src/avm2/util.js"></script>
|
||||
<script src="../../src/swf/filter.js"></script>
|
||||
<script src="../../src/swf/filters/gl.js"></script>
|
||||
<script src="../../src/swf/filters/filter.js"></script>
|
||||
<style TYPE="text/css">
|
||||
body {
|
||||
color: white;
|
||||
|
@ -65,6 +69,9 @@
|
|||
<td>
|
||||
GL Glow
|
||||
</td>
|
||||
<td>
|
||||
GL Shadow
|
||||
</td>
|
||||
<td>
|
||||
GL Color
|
||||
</td>
|
||||
|
@ -79,6 +86,9 @@
|
|||
<td>
|
||||
<canvas width="256" height="256" id="glow-canvas-gl"></canvas>
|
||||
</td>
|
||||
<td>
|
||||
<canvas width="256" height="256" id="shadow-canvas-gl"></canvas>
|
||||
</td>
|
||||
<td>
|
||||
<canvas width="256" height="256" id="color-canvas-gl"></canvas>
|
||||
</td>
|
||||
|
@ -86,65 +96,6 @@
|
|||
</table>
|
||||
|
||||
<img src="firefox.png" id="firefox" style="visibility: hidden;">
|
||||
<script id="2d-vertex-shader" type="x-shader/x-vertex">
|
||||
attribute vec2 a_position;
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_flipY;
|
||||
attribute vec2 a_textureCoordinate;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
vec2 p = (a_position / u_resolution) * 2.0 - 1.0;
|
||||
gl_Position = vec4(p * vec2(1, u_flipY), 0, 1);
|
||||
v_texCoord = a_textureCoordinate;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="2d-blur-fragment-shader-h" type="x-shader/x-fragment">
|
||||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform vec2 u_textureSize;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
const int sampleRadius = 9;
|
||||
const int samples = sampleRadius * 2 + 1;
|
||||
vec2 one = vec2(1.0, 1.0) / u_textureSize;
|
||||
vec4 color = vec4(0, 0, 0, 0);
|
||||
for (int i = -sampleRadius; i <= sampleRadius; i++) {
|
||||
color += texture2D(u_image, v_texCoord + vec2(float(i) * one.x, 0));
|
||||
}
|
||||
color /= float(samples);
|
||||
gl_FragColor = color;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="2d-blur-fragment-shader-v" type="x-shader/x-fragment">
|
||||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform vec2 u_textureSize;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
const int sampleRadius = 9;
|
||||
const int samples = sampleRadius * 2 + 1;
|
||||
vec2 one = vec2(1.0, 1.0) / u_textureSize;
|
||||
vec4 color = vec4(0, 0, 0, 0);
|
||||
for (int i = -sampleRadius; i <= sampleRadius; i++) {
|
||||
color += texture2D(u_image, v_texCoord + vec2(0, float(i) * one.y));
|
||||
}
|
||||
color /= float(samples);
|
||||
gl_FragColor = color;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="2d-color-fragment-shader" type="x-shader/x-fragment">
|
||||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform mat4 u_matrix;
|
||||
uniform vec4 u_vector;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
gl_FragColor = u_matrix * texture2D(u_image, v_texCoord) + u_vector;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="filter_driver.js"></script>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ function drawShape(ctx, length, x, y) {
|
|||
ctx.fillStyle = '#ff0000';
|
||||
ctx.strokeStyle = 'green';
|
||||
ctx.translate(x, y);
|
||||
ctx.rotate(r += 0.01);
|
||||
ctx.rotate(r += 0.02);
|
||||
ctx.rotate((Math.PI * 1 / 10));
|
||||
ctx.beginPath();
|
||||
for (var i = 5; i--;) {
|
||||
|
@ -28,20 +28,6 @@ function drawShape(ctx, length, x, y) {
|
|||
|
||||
var colorMatrix4x5 = new Float32Array([0.748939, 1.044984, -0.793923, 0.000000, 0.000000, -0.008795, 0.713845, 0.294950, 0.000000, 0.000000, 0.827417, -0.240804, 0.413387, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000]);
|
||||
|
||||
function transpose(r, c, m) {
|
||||
var result = new Float32Array(16);
|
||||
for (var i = 0; i < r; i++) {
|
||||
for (var j = 0; j < c; j++) {
|
||||
result[j * r + i] = m[i * c + j];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
var colorMatrix5x4 = transpose(4, 5, colorMatrix4x5);
|
||||
var colorMatrix4x4 = colorMatrix5x4.subarray(0, 16);
|
||||
var colorMatrixVector = colorMatrix5x4.subarray(16, 20);
|
||||
|
||||
var blurCanvasJS = document.getElementById("blur-canvas-js");
|
||||
var blurCanvasGL = document.getElementById("blur-canvas-gl");
|
||||
|
||||
|
@ -55,73 +41,14 @@ var colorCanvasJS = document.getElementById("color-canvas-js");
|
|||
var colorCanvasGL = document.getElementById("color-canvas-gl");
|
||||
|
||||
var glCanvas = document.getElementById("canvas-gl");
|
||||
|
||||
var glFilters = new WebGLFilters(glCanvas);
|
||||
|
||||
var gl = new WebGLCanvas(glCanvas);
|
||||
|
||||
var vShader = gl.createShaderFromElement("2d-vertex-shader");
|
||||
var blurFragmentShaderH = gl.createShaderFromElement("2d-blur-fragment-shader-h");
|
||||
var blurFragmentShaderV = gl.createShaderFromElement("2d-blur-fragment-shader-v");
|
||||
var colorFragmentShader = gl.createShaderFromElement("2d-color-fragment-shader");
|
||||
|
||||
var blurProgramH = gl.createProgram([vShader, blurFragmentShaderH]);
|
||||
var blurProgramV = gl.createProgram([vShader, blurFragmentShaderV]);
|
||||
var colorProgram = gl.createProgram([vShader, colorFragmentShader]);
|
||||
|
||||
var texture = gl.createTexture();
|
||||
var vertices = gl.createVertexBuffer(gl.rectangleVertices(width, height));
|
||||
var textureCoordinates = gl.createVertexBuffer(gl.rectangleTextureCoordinates());
|
||||
|
||||
gl.useProgram(blurProgramH);
|
||||
gl.setUniform2f(blurProgramH, "u_resolution", width, height);
|
||||
gl.setUniform2f(blurProgramH, "u_textureSize", width, height);
|
||||
gl.setUniform1f(blurProgramH, "u_flipY", 1);
|
||||
gl.setVertexAttribute(blurProgramH, "a_position", vertices);
|
||||
gl.setVertexAttribute(blurProgramH, "a_textureCoordinate", textureCoordinates);
|
||||
|
||||
gl.useProgram(blurProgramV);
|
||||
gl.setUniform2f(blurProgramV, "u_resolution", width, height);
|
||||
gl.setUniform2f(blurProgramV, "u_textureSize", width, height);
|
||||
gl.setUniform1f(blurProgramV, "u_flipY", -1);
|
||||
gl.setVertexAttribute(blurProgramV, "a_textureCoordinate", textureCoordinates);
|
||||
gl.setVertexAttribute(blurProgramV, "a_position", vertices);
|
||||
|
||||
|
||||
|
||||
gl.useProgram(colorProgram);
|
||||
gl.setUniform2f(colorProgram, "u_resolution", width, height);
|
||||
gl.setUniformMatrix4fv(colorProgram, "u_matrix", colorMatrix4x4);
|
||||
gl.setUniform4fv(colorProgram, "u_vector", colorMatrixVector);
|
||||
// gl.setUniform2f(colorProgram, "u_textureSize", canvas.width, canvas.height);
|
||||
|
||||
gl.setUniform1f(colorProgram, "u_flipY", -1);
|
||||
gl.setVertexAttribute(colorProgram, "a_textureCoordinate", textureCoordinates);
|
||||
gl.setVertexAttribute(colorProgram, "a_position", vertices);
|
||||
|
||||
var framebuffer = gl.createFramebuffer();
|
||||
|
||||
var firefoxImage = document.getElementById("firefox");
|
||||
|
||||
|
||||
function blurGL(data, width, height) {
|
||||
gl.initializeTexture(texture, width, height, new Uint8Array(data.buffer));
|
||||
gl.useProgram(blurProgramH);
|
||||
gl.bindTexture(texture);
|
||||
gl.bindFramebuffer(framebuffer);
|
||||
gl.drawTriangles(0, 6);
|
||||
|
||||
gl.useProgram(blurProgramV);
|
||||
gl.bindTexture(framebuffer.texture);
|
||||
gl.bindFramebuffer(null);
|
||||
gl.drawTriangles(0, 6);
|
||||
}
|
||||
|
||||
function colorGL(data, width, height) {
|
||||
gl.initializeTexture(texture, width, height, new Uint8Array(data.buffer));
|
||||
gl.useProgram(colorProgram);
|
||||
gl.bindTexture(texture);
|
||||
gl.bindFramebuffer(null);
|
||||
gl.drawTriangles(0, 6);
|
||||
}
|
||||
|
||||
function getImageData(straightAlpha) {
|
||||
var imageData = context.getImageData(0, 0, width, height);
|
||||
if (!straightAlpha) {
|
||||
|
@ -137,26 +64,29 @@ function putImageData(imageData, context, straightAlpha) {
|
|||
context.putImageData(imageData, 0, 0);
|
||||
}
|
||||
|
||||
var runJS = true;
|
||||
var runGL = true;
|
||||
|
||||
var run = {
|
||||
blur: {
|
||||
js: false,
|
||||
gl: false
|
||||
js: runJS && true,
|
||||
gl: runGL && true
|
||||
},
|
||||
glow: {
|
||||
js: false,
|
||||
gl: false
|
||||
js: runJS && true,
|
||||
gl: runGL && true
|
||||
},
|
||||
shadow: {
|
||||
js: true,
|
||||
gl: false
|
||||
js: runJS && true,
|
||||
gl: runGL && true
|
||||
},
|
||||
color: {
|
||||
js: false,
|
||||
gl: false
|
||||
js: runJS && true,
|
||||
gl: runGL && true
|
||||
}
|
||||
};
|
||||
|
||||
var k = 0;
|
||||
var frameCount = 0;
|
||||
|
||||
setInterval(function () {
|
||||
|
||||
|
@ -164,37 +94,54 @@ setInterval(function () {
|
|||
context.fillStyle = "white";
|
||||
// context.fillRect(0, 0, 256, 256);
|
||||
context.clearRect(0, 0, 256, 256);
|
||||
drawShape(context, 50, 120, 120);
|
||||
drawShape(context, 50, 140, 140);
|
||||
context.drawImage(firefoxImage, 40, 40);
|
||||
|
||||
var imageData;
|
||||
|
||||
var blurX = 10, blurY = 10;
|
||||
|
||||
if (run.blur.js) {
|
||||
// Run JS Blur Filter
|
||||
imageData = getImageData();
|
||||
blurFilter(imageData.data, width, height, 10, 10);
|
||||
blurFilter(imageData.data, width, height, blurX, blurY);
|
||||
putImageData(imageData, blurCanvasJS.getContext('2d'));
|
||||
}
|
||||
|
||||
if (run.blur.gl) {
|
||||
// Run WebGL Blur Filter
|
||||
imageData = getImageData(true);
|
||||
blurGL(imageData.data, width, height);
|
||||
glFilters.blurFilter(imageData.data, width, height);
|
||||
drawImage(glCanvas, blurCanvasGL);
|
||||
}
|
||||
|
||||
if (run.glow.js) {
|
||||
imageData = getImageData();
|
||||
glowFilter(imageData.data, width, height, [0, 0, 255, 0], 20, 20, 1);
|
||||
glowFilter(imageData.data, width, height, [0, 0, 255, 0], blurX, blurY, 1);
|
||||
putImageData(imageData, glowCanvasJS.getContext('2d'));
|
||||
}
|
||||
|
||||
if (run.glow.gl) {
|
||||
imageData = getImageData(true);
|
||||
glFilters.glowFilter(imageData.data, width, height, [0, 0, 255, 255], blurX, blurY, 1);
|
||||
drawImage(glCanvas, glowCanvasGL);
|
||||
|
||||
}
|
||||
|
||||
if (run.shadow.js) {
|
||||
imageData = getImageData();
|
||||
dropShadowFilter(imageData.data, width, height, [0, 0, 0, 0], 5, 5, Math.PI / 4, 10, 0.5);
|
||||
dropShadowFilter(imageData.data, width, height, [0, 0, 255, 0], blurX, blurY, Math.PI / 4, 20, 0.5);
|
||||
putImageData(imageData, shadowCanvasJS.getContext('2d'));
|
||||
}
|
||||
|
||||
if (run.shadow.gl) {
|
||||
imageData = getImageData();
|
||||
glFilters.dropShadowFilter(imageData.data, width, height, [0, 0, 255, 255], blurX, blurY, Math.PI / 4, 20, 0.5);
|
||||
drawImage(glCanvas, shadowCanvasGL);
|
||||
}
|
||||
|
||||
colorMatrix4x5[0] = Math.sin(frameCount / 100);
|
||||
|
||||
if (run.color.js) {
|
||||
// Run JS Color Filter
|
||||
imageData = getImageData();
|
||||
|
@ -205,10 +152,12 @@ setInterval(function () {
|
|||
if (run.color.gl) {
|
||||
// Run WebGL Color Filter
|
||||
imageData = getImageData();
|
||||
colorGL(imageData.data, width, height);
|
||||
glFilters.colorFilter(imageData.data, width, height, colorMatrix4x5);
|
||||
drawImage(glCanvas, colorCanvasGL);
|
||||
}
|
||||
|
||||
frameCount ++;
|
||||
|
||||
}, 1000 / 60);
|
||||
|
||||
function drawImage(src, dst) {
|
||||
|
|
|
@ -5,6 +5,17 @@
|
|||
* Resources: http://www.m2osw.com/swf_struct_any_filter#swf_filter_colormatrix
|
||||
*/
|
||||
|
||||
function transpose(r, c, m) {
|
||||
assert (r * c === m.length);
|
||||
var result = new Float32Array(m.length);
|
||||
for (var i = 0; i < r; i++) {
|
||||
for (var j = 0; j < c; j++) {
|
||||
result[j * r + i] = m[i * c + j];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a blur box-filter, averaging pixel values in a box with radius (blurX x blurY).
|
||||
*
|
||||
|
@ -148,7 +159,7 @@ function blurFilterV(buffer, w, h, blurY) {
|
|||
}
|
||||
}
|
||||
|
||||
function getAlphaChannel(buffer, color) {
|
||||
function alphaFilter(buffer, color) {
|
||||
if (!color) {
|
||||
color = [0, 0, 0, 0];
|
||||
}
|
||||
|
@ -232,7 +243,7 @@ function panFilter(buffer, w, h, angle, distance) {
|
|||
}
|
||||
|
||||
function dropShadowFilter(buffer, w, h, color, blurX, blurY, angle, distance, strength) {
|
||||
var tmp = getAlphaChannel(buffer, color);
|
||||
var tmp = alphaFilter(buffer, color);
|
||||
panFilter(tmp, w, h, angle, distance);
|
||||
blurFilter(tmp, w, h, blurX, blurY);
|
||||
scaleAlphaChannel(tmp, strength);
|
||||
|
@ -240,6 +251,10 @@ function dropShadowFilter(buffer, w, h, color, blurX, blurY, angle, distance, st
|
|||
buffer.set(tmp);
|
||||
}
|
||||
|
||||
function clamp(n) {
|
||||
return (((255 - n) >> 31) | n) & 0xFF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a color transformation. The |matrix| is a 5x5 matrix whose
|
||||
* last row is always [0, 0, 0, 0, 1]. The |matrix| is specified in row-major order;
|
||||
|
@ -252,10 +267,6 @@ function dropShadowFilter(buffer, w, h, color, blurX, blurY, angle, distance, st
|
|||
*
|
||||
*/
|
||||
|
||||
function clamp(n) {
|
||||
return (((255 - n) >> 31) | n) & 0xFF;
|
||||
}
|
||||
|
||||
function colorFilter(buffer, w, h, matrix) {
|
||||
var r0 = matrix[0], r1 = matrix[1], r2 = matrix[2], r3 = matrix[3], r4 = matrix[4];
|
||||
var g0 = matrix[5], g1 = matrix[6], g2 = matrix[7], g3 = matrix[8], g4 = matrix[9];
|
||||
|
@ -273,157 +284,188 @@ function colorFilter(buffer, w, h, matrix) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Yet another abstraction over WebGL APIs.
|
||||
*/
|
||||
var WebGLCanvas = (function () {
|
||||
var WebGLFilters = (function () {
|
||||
var shaderRoot = SHUMWAY_ROOT + "/swf/filters/shaders/";
|
||||
|
||||
function colorVector(color) {
|
||||
return [color[0] / 255, color[1] / 255, color[2] / 255, color[3] / 255];
|
||||
}
|
||||
|
||||
function makeTranslation(tx, ty) {
|
||||
return transpose(3, 3, [
|
||||
1, 0, tx,
|
||||
0, 1, ty,
|
||||
0, 0, 1
|
||||
]);
|
||||
}
|
||||
|
||||
var counter = 0;
|
||||
|
||||
function constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
var w = this.width = canvas.width;
|
||||
var h = this.height = canvas.height;
|
||||
assert (w && h && isPowerOfTwo(w) && isPowerOfTwo(h));
|
||||
this.gl = this.canvas.getContext("experimental-webgl");
|
||||
assert (this.gl);
|
||||
assert (canvas);
|
||||
var gl = this.gl = new WebGLCanvas(canvas);
|
||||
var width = canvas.width;
|
||||
var height = canvas.height;
|
||||
function loadShader(name) {
|
||||
return gl.createShaderFromFile(shaderRoot + name);
|
||||
}
|
||||
// Create shader programs.
|
||||
var canvasVert = loadShader("canvas.vert");
|
||||
this.blurHProgram = gl.createProgram([canvasVert, loadShader("blurh.frag")]);
|
||||
this.blurVProgram = gl.createProgram([canvasVert, loadShader("blurv.frag")]);
|
||||
this.colorProgram = gl.createProgram([canvasVert, loadShader("color.frag")]);
|
||||
this.alphaProgram = gl.createProgram([canvasVert, loadShader("alpha.frag")]);
|
||||
this.multiplyProgram = gl.createProgram([canvasVert, loadShader("multiply.frag")]);
|
||||
this.identityProgram = gl.createProgram([canvasVert, loadShader("identity.frag")]);
|
||||
|
||||
this.programs = [
|
||||
this.blurHProgram,
|
||||
this.blurVProgram,
|
||||
this.colorProgram,
|
||||
this.alphaProgram,
|
||||
this.multiplyProgram,
|
||||
this.identityProgram
|
||||
];
|
||||
|
||||
this.texture = gl.createTexture();
|
||||
this.framebufferA = gl.createFramebuffer();
|
||||
this.framebufferB = gl.createFramebuffer();
|
||||
|
||||
var vertices = gl.createVertexBuffer(gl.rectangleVertices(width, height));
|
||||
var textureCoordinates = gl.createVertexBuffer(gl.rectangleTextureCoordinates());
|
||||
var matrix = makeTranslation(0, 0);
|
||||
|
||||
this.programs.forEach(setDefaultAttributesAndUniforms);
|
||||
|
||||
function setDefaultAttributesAndUniforms(program) {
|
||||
gl.useProgram(program);
|
||||
if (gl.hasUniform(program, "u_time")) {
|
||||
gl.setUniform1f(program, "u_time", 0.0);
|
||||
}
|
||||
gl.setUniformMatrix3fv(program, "u_transformMatrix", matrix);
|
||||
gl.setUniform2f(program, "u_resolution", width, height);
|
||||
gl.setUniform1f(program, "u_flipY", 1);
|
||||
|
||||
gl.setVertexAttribute(program, "a_textureCoordinate", textureCoordinates);
|
||||
gl.setVertexAttribute(program, "a_position", vertices);
|
||||
}
|
||||
|
||||
gl.useProgram(this.blurHProgram);
|
||||
gl.setUniform2f(this.blurHProgram, "u_textureSize", width, height);
|
||||
|
||||
gl.useProgram(this.blurVProgram);
|
||||
gl.setUniform2f(this.blurVProgram, "u_textureSize", width, height);
|
||||
|
||||
this.startTime = new Date();
|
||||
}
|
||||
|
||||
constructor.prototype = {
|
||||
rectangleVertices: function rectangleVertices(w, h) {
|
||||
return new Float32Array([0, 0, w, 0, 0, h, 0, h, w, 0, w, h]);
|
||||
getElapsedTime: function getElapsedTime() {
|
||||
return new Date() - this.startTime;
|
||||
},
|
||||
rectangleTextureCoordinates: function rectangleTextureCoordinates() {
|
||||
return new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]);
|
||||
},
|
||||
useProgram: function (program) {
|
||||
this.gl.useProgram(program);
|
||||
},
|
||||
setVertexAttribute: function setVertexAttribute(program, name, buffer) {
|
||||
blurFilter: function blurFilterGL(buffer, w, h, blurX, blurY) {
|
||||
var gl = this.gl;
|
||||
var location = gl.getAttribLocation(program, name);
|
||||
assert (location >= 0, "Attribute " + name + " not found.");
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.enableVertexAttribArray(location);
|
||||
gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
gl.bindFramebuffer(null);
|
||||
gl.clear([0, 0, 0, 0]);
|
||||
|
||||
gl.initializeTexture(this.texture, w, h, new Uint8Array(buffer.buffer));
|
||||
gl.bindTexture(this.texture);
|
||||
gl.useProgram(this.blurHProgram);
|
||||
gl.bindFramebuffer(this.framebufferA);
|
||||
gl.clear([0, 0, 0, 0]);
|
||||
gl.drawTriangles(0, 6);
|
||||
|
||||
gl.useProgram(this.blurVProgram);
|
||||
gl.setUniform1f(this.blurVProgram, "u_flipY", -1);
|
||||
gl.bindTexture(this.framebufferA.texture);
|
||||
gl.bindFramebuffer(null);
|
||||
gl.drawTriangles(0, 6);
|
||||
gl.setUniform1f(this.blurVProgram, "u_flipY", 1);
|
||||
},
|
||||
setUniform4fv: function setUniform2f(program, name, vector) {
|
||||
var gl = this.gl
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
gl.uniform4fv(location, vector);
|
||||
colorFilter: function colorFilter(buffer, w, h, matrix) {
|
||||
var colorMatrix5x4 = transpose(4, 5, matrix);
|
||||
var colorMatrix4x4 = colorMatrix5x4.subarray(0, 16);
|
||||
var colorMatrixVector = colorMatrix5x4.subarray(16, 20);
|
||||
gl.initializeTexture(this.texture, w, h, new Uint8Array(buffer.buffer));
|
||||
gl.useProgram(this.colorProgram);
|
||||
gl.setUniformMatrix4fv(this.colorProgram, "u_colorMatrix", colorMatrix4x4);
|
||||
gl.setUniform4fv(this.colorProgram, "u_vector", colorMatrixVector);
|
||||
gl.setUniform1f(this.colorProgram, "u_flipY", -1);
|
||||
gl.bindTexture(this.texture);
|
||||
gl.bindFramebuffer(null);
|
||||
gl.clear([0, 0, 0, 0]);
|
||||
gl.drawTriangles(0, 6);
|
||||
gl.setUniform1f(this.colorProgram, "u_flipY", 1);
|
||||
},
|
||||
setUniform2f: function setUniform2f(program, name, x, y) {
|
||||
var gl = this.gl
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
gl.uniform2f(location, x, y);
|
||||
alphaFilter: function alphaFilter(buffer, w, h, color) {
|
||||
gl.initializeTexture(this.texture, w, h, new Uint8Array(buffer.buffer));
|
||||
gl.useProgram(this.alphaProgram);
|
||||
gl.setUniform4fv(this.alphaProgram, "u_color", colorVector(color));
|
||||
gl.bindTexture(this.texture);
|
||||
gl.bindFramebuffer(null);
|
||||
gl.drawTriangles(0, 6);
|
||||
},
|
||||
setUniform1f: function setUniform2f(program, name, x) {
|
||||
var gl = this.gl
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
gl.uniform1f(location, x);
|
||||
glowFilter: function dropShadowFilter(buffer, w, h, color, blurX, blurY, strength) {
|
||||
this.dropShadowFilter(buffer, w, h, color, blurX, blurY, 0, 0, strength);
|
||||
},
|
||||
setUniformMatrix4fv: function setUniform(program, name, matrix) {
|
||||
var gl = this.gl
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
assert (matrix.length === 16, "Invalid matrix size.");
|
||||
gl.uniformMatrix4fv(location, false, matrix);
|
||||
},
|
||||
createVertexBuffer: function createBuffer(vertices) {
|
||||
var gl = this.gl;
|
||||
var buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
||||
return buffer;
|
||||
},
|
||||
createFramebuffer: function createFramebuffer() {
|
||||
var gl = this.gl;
|
||||
var texture = this.createTexture();
|
||||
this.initializeTexture(texture, this.width, this.height, null);
|
||||
var framebuffer = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
||||
framebuffer.texture = texture;
|
||||
return framebuffer;
|
||||
},
|
||||
createTexture: function createAndBindTexture() {
|
||||
var gl = this.gl;
|
||||
var texture = gl.createTexture();
|
||||
this.bindTexture(texture);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
return texture;
|
||||
},
|
||||
initializeTexture: function initializeTexture(texture, width, height, data) {
|
||||
var gl = this.gl;
|
||||
this.bindTexture(texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
},
|
||||
bindTexture: function bindTexture(texture) {
|
||||
var gl = this.gl;
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
},
|
||||
bindFramebuffer: function bindFramebuffer(framebuffer) {
|
||||
var gl = this.gl;
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
||||
},
|
||||
createShader: function createShader(gl, shaderType, shaderSource) {
|
||||
var gl = this.gl;
|
||||
var shader = gl.createShader(shaderType);
|
||||
gl.shaderSource(shader, shaderSource);
|
||||
gl.compileShader(shader);
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
var lastError = gl.getShaderInfoLog(shader);
|
||||
unexpected("Cannot compile shader: " + lastError);
|
||||
gl.deleteShader(shader);
|
||||
return null;
|
||||
}
|
||||
return shader;
|
||||
},
|
||||
createShaderFromElement: function createShaderFromElement(id) {
|
||||
var gl = this.gl;
|
||||
var shaderScript = document.getElementById(id);
|
||||
if (!shaderScript) {
|
||||
unexpected("Shader Script Element: " + id + " not found.");
|
||||
}
|
||||
var shaderType;
|
||||
switch (shaderScript.type) {
|
||||
case "x-shader/x-vertex":
|
||||
shaderType = gl.VERTEX_SHADER;
|
||||
break;
|
||||
case "x-shader/x-fragment":
|
||||
shaderType = gl.FRAGMENT_SHADER;
|
||||
break;
|
||||
default:
|
||||
throw "Shader Type: " + shaderScript.type + " not supported.";
|
||||
break;
|
||||
}
|
||||
return this.createShader(gl, shaderType, shaderScript.text);
|
||||
},
|
||||
createProgram: function createProgram(shaders) {
|
||||
var gl = this.gl;
|
||||
var program = gl.createProgram();
|
||||
shaders.forEach(function (shader) {
|
||||
gl.attachShader(program, shader);
|
||||
});
|
||||
gl.linkProgram(program);
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
var lastError = gl.getProgramInfoLog(program);
|
||||
unexpected("Cannot link program: " + lastError);
|
||||
gl.deleteProgram(program);
|
||||
}
|
||||
return program;
|
||||
},
|
||||
drawTriangles: function drawArrays(first, count) {
|
||||
var gl = this.gl;
|
||||
gl.drawArrays(gl.TRIANGLES, first, count);
|
||||
dropShadowFilter: function dropShadowFilter(buffer, w, h, color, blurX, blurY, angle, distance, strength) {
|
||||
|
||||
gl.bindFramebuffer(this.framebufferA);
|
||||
gl.clear([0, 0, 0, 0]);
|
||||
gl.bindFramebuffer(this.framebufferB);
|
||||
gl.clear([0, 0, 0, 0]);
|
||||
gl.bindFramebuffer(null);
|
||||
gl.clear([0, 0, 0, 0]);
|
||||
|
||||
// Alpha
|
||||
gl.initializeTexture(this.texture, w, h, new Uint8Array(buffer.buffer));
|
||||
gl.useProgram(this.alphaProgram);
|
||||
gl.setUniform4fv(this.alphaProgram, "u_color", colorVector(color));
|
||||
gl.bindTexture(this.texture);
|
||||
gl.bindFramebuffer(this.framebufferA);
|
||||
gl.drawTriangles(0, 6);
|
||||
|
||||
// Blur H
|
||||
gl.bindTexture(this.framebufferA.texture);
|
||||
gl.useProgram(this.blurHProgram);
|
||||
gl.bindFramebuffer(this.framebufferB);
|
||||
gl.drawTriangles(0, 6);
|
||||
|
||||
// Blur V
|
||||
gl.useProgram(this.blurVProgram);
|
||||
gl.bindTexture(this.framebufferB.texture);
|
||||
gl.bindFramebuffer(this.framebufferA);
|
||||
gl.drawTriangles(0, 6);
|
||||
|
||||
// Multiply Alpha
|
||||
gl.bindTexture(this.framebufferA.texture);
|
||||
gl.useProgram(this.multiplyProgram);
|
||||
var dy = (Math.sin(angle) * distance) | 0;
|
||||
var dx = (Math.cos(angle) * distance) | 0;
|
||||
gl.setUniformMatrix3fv(this.multiplyProgram, "u_transformMatrix", makeTranslation(dx, dy));
|
||||
gl.setUniform4fv(this.multiplyProgram, "u_color", [strength, strength, strength, strength]);
|
||||
gl.bindFramebuffer(this.framebufferB);
|
||||
gl.drawTriangles(0, 6);
|
||||
|
||||
gl.bindTexture(this.texture);
|
||||
gl.useProgram(this.identityProgram);
|
||||
gl.enableBlend();
|
||||
gl.gl.blendFunc(gl.gl.ONE, gl.gl.ONE_MINUS_SRC_ALPHA);
|
||||
gl.bindFramebuffer(this.framebufferB);
|
||||
gl.drawTriangles(0, 6);
|
||||
gl.disableBlend();
|
||||
|
||||
gl.bindTexture(this.framebufferB.texture);
|
||||
gl.useProgram(this.identityProgram);
|
||||
gl.setUniform1f(this.identityProgram, "u_flipY", -1);
|
||||
gl.bindFramebuffer(null);
|
||||
gl.clear([0, 0, 0, 0]);
|
||||
gl.drawTriangles(0, 6);
|
||||
gl.setUniform1f(this.identityProgram, "u_flipY", 1);
|
||||
|
||||
return;
|
||||
}
|
||||
};
|
||||
return constructor;
|
||||
})();
|
||||
|
||||
function trace(s) {
|
||||
console.info(s);
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/**
|
||||
* Yet another abstraction over WebGL APIs.
|
||||
*/
|
||||
var WebGLCanvas = (function () {
|
||||
function constructor(canvas) {
|
||||
this.canvas = canvas;
|
||||
var w = this.width = canvas.width;
|
||||
var h = this.height = canvas.height;
|
||||
assert (w && h && isPowerOfTwo(w) && isPowerOfTwo(h));
|
||||
this.gl = this.canvas.getContext("experimental-webgl");
|
||||
assert (this.gl);
|
||||
}
|
||||
|
||||
constructor.prototype = {
|
||||
rectangleVertices: function rectangleVertices(w, h) {
|
||||
return new Float32Array([0, 0, w, 0, 0, h, 0, h, w, 0, w, h]);
|
||||
},
|
||||
rectangleTextureCoordinates: function rectangleTextureCoordinates() {
|
||||
return new Float32Array([0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1]);
|
||||
},
|
||||
useProgram: function (program) {
|
||||
this.gl.useProgram(program);
|
||||
},
|
||||
hasUniform: function hasUniform(program, name) {
|
||||
return !!this.gl.getUniformLocation(program, name);
|
||||
},
|
||||
setVertexAttribute: function setVertexAttribute(program, name, buffer) {
|
||||
var gl = this.gl;
|
||||
var location = gl.getAttribLocation(program, name);
|
||||
assert (location >= 0, "Attribute " + name + " not found.");
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.enableVertexAttribArray(location);
|
||||
gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0);
|
||||
},
|
||||
setUniform4fv: function setUniform2f(program, name, vector) {
|
||||
var gl = this.gl;
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
gl.uniform4fv(location, vector);
|
||||
},
|
||||
setUniform2f: function setUniform2f(program, name, x, y) {
|
||||
var gl = this.gl;
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
gl.uniform2f(location, x, y);
|
||||
},
|
||||
setUniform1f: function setUniform2f(program, name, value) {
|
||||
var gl = this.gl;
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
gl.uniform1f(location, value);
|
||||
},
|
||||
setUniformMatrix4fv: function setUniform(program, name, matrix) {
|
||||
var gl = this.gl;
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
assert (matrix.length === 16, "Invalid matrix size.");
|
||||
gl.uniformMatrix4fv(location, false, matrix);
|
||||
},
|
||||
setUniformMatrix3fv: function setUniformMatrix3fv(program, name, matrix) {
|
||||
var gl = this.gl;
|
||||
var location = gl.getUniformLocation(program, name);
|
||||
assert (location, "Uniform " + name + " not found.");
|
||||
assert (matrix.length === 9, "Invalid matrix size.");
|
||||
gl.uniformMatrix3fv(location, false, matrix);
|
||||
},
|
||||
createVertexBuffer: function createBuffer(vertices) {
|
||||
var gl = this.gl;
|
||||
var buffer = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
||||
return buffer;
|
||||
},
|
||||
createFramebuffer: function createFramebuffer() {
|
||||
var gl = this.gl;
|
||||
var texture = this.createTexture();
|
||||
this.initializeTexture(texture, this.width, this.height, null);
|
||||
var framebuffer = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
||||
framebuffer.texture = texture;
|
||||
return framebuffer;
|
||||
},
|
||||
createTexture: function createAndBindTexture() {
|
||||
var gl = this.gl;
|
||||
var texture = gl.createTexture();
|
||||
this.bindTexture(texture);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
return texture;
|
||||
},
|
||||
initializeTexture: function initializeTexture(texture, width, height, data) {
|
||||
var gl = this.gl;
|
||||
this.bindTexture(texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
||||
},
|
||||
bindTexture: function bindTexture(texture) {
|
||||
var gl = this.gl;
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
},
|
||||
bindFramebuffer: function bindFramebuffer(framebuffer) {
|
||||
var gl = this.gl;
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
||||
},
|
||||
createShader: function createShader(gl, shaderType, shaderSource) {
|
||||
var gl = this.gl;
|
||||
var shader = gl.createShader(shaderType);
|
||||
gl.shaderSource(shader, shaderSource);
|
||||
gl.compileShader(shader);
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
var lastError = gl.getShaderInfoLog(shader);
|
||||
unexpected("Cannot compile shader: " + lastError);
|
||||
gl.deleteShader(shader);
|
||||
return null;
|
||||
}
|
||||
return shader;
|
||||
},
|
||||
createShaderFromFile: function createShaderFromFile(file) {
|
||||
var gl = this.gl;
|
||||
var request = new XMLHttpRequest();
|
||||
request.open("GET", file, false);
|
||||
request.send();
|
||||
assert (request.status === 200, "File : " + file + " not found.");
|
||||
var shaderType;
|
||||
if (file.endsWith(".vert")) {
|
||||
shaderType = gl.VERTEX_SHADER;
|
||||
} else if (file.endsWith(".frag")) {
|
||||
shaderType = gl.FRAGMENT_SHADER;
|
||||
} else {
|
||||
throw "Shader Type: not supported.";
|
||||
}
|
||||
return this.createShader(gl, shaderType, request.responseText);
|
||||
},
|
||||
createShaderFromElement: function createShaderFromElement(id) {
|
||||
var gl = this.gl;
|
||||
var shaderScript = document.getElementById(id);
|
||||
if (!shaderScript) {
|
||||
unexpected("Shader Script Element: " + id + " not found.");
|
||||
}
|
||||
var shaderType;
|
||||
switch (shaderScript.type) {
|
||||
case "x-shader/x-vertex":
|
||||
shaderType = gl.VERTEX_SHADER;
|
||||
break;
|
||||
case "x-shader/x-fragment":
|
||||
shaderType = gl.FRAGMENT_SHADER;
|
||||
break;
|
||||
default:
|
||||
throw "Shader Type: " + shaderScript.type + " not supported.";
|
||||
break;
|
||||
}
|
||||
return this.createShader(gl, shaderType, shaderScript.text);
|
||||
},
|
||||
createProgram: function createProgram(shaders) {
|
||||
var gl = this.gl;
|
||||
var program = gl.createProgram();
|
||||
shaders.forEach(function (shader) {
|
||||
gl.attachShader(program, shader);
|
||||
});
|
||||
gl.linkProgram(program);
|
||||
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
||||
var lastError = gl.getProgramInfoLog(program);
|
||||
unexpected("Cannot link program: " + lastError);
|
||||
gl.deleteProgram(program);
|
||||
}
|
||||
return program;
|
||||
},
|
||||
drawTriangles: function drawArrays(first, count) {
|
||||
var gl = this.gl;
|
||||
gl.drawArrays(gl.TRIANGLES, first, count);
|
||||
},
|
||||
clear: function clear(color) {
|
||||
var gl = this.gl;
|
||||
gl.clearColor(color[0], color[1], color[2], color[3]);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
},
|
||||
enableBlend: function enableBlend() {
|
||||
var gl = this.gl;
|
||||
gl.enable(gl.BLEND);
|
||||
},
|
||||
disableBlend: function disableBlend() {
|
||||
var gl = this.gl;
|
||||
gl.disable(gl.BLEND);
|
||||
}
|
||||
};
|
||||
return constructor;
|
||||
})();
|
|
@ -0,0 +1,8 @@
|
|||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform vec4 u_color;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
// gl_FragColor = u_matrix * texture2D(u_image, v_texCoord) + u_vector;
|
||||
gl_FragColor = u_color * texture2D(u_image, v_texCoord).a;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform vec2 u_textureSize;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
const int sampleRadius = 10;
|
||||
const int samples = sampleRadius * 2 + 1;
|
||||
vec2 one = vec2(1.0, 1.0) / u_textureSize;
|
||||
vec4 color = vec4(0, 0, 0, 0);
|
||||
for (int i = -sampleRadius; i <= sampleRadius; i++) {
|
||||
color += texture2D(u_image, v_texCoord + vec2(float(i) * one.x, 0));
|
||||
}
|
||||
color /= float(samples);
|
||||
gl_FragColor = color;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform vec2 u_textureSize;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
const int sampleRadius = 10;
|
||||
const int samples = sampleRadius * 2 + 1;
|
||||
vec2 one = vec2(1.0, 1.0) / u_textureSize;
|
||||
vec4 color = vec4(0, 0, 0, 0);
|
||||
for (int i = -sampleRadius; i <= sampleRadius; i++) {
|
||||
color += texture2D(u_image, v_texCoord + vec2(0, float(i) * one.y));
|
||||
}
|
||||
color /= float(samples);
|
||||
gl_FragColor = color;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
attribute vec2 a_position;
|
||||
uniform vec2 u_resolution;
|
||||
uniform float u_flipY;
|
||||
uniform float u_time;
|
||||
attribute vec2 a_textureCoordinate;
|
||||
uniform mat3 u_transformMatrix;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
void main() {
|
||||
vec2 position = ((u_transformMatrix * vec3(a_position, 1.0)).xy / u_resolution) * 2.0 - 1.0;
|
||||
position *= vec2(1.0, u_flipY);
|
||||
gl_Position = vec4(vec3(position, 1.0), 1.0);
|
||||
v_texCoord = a_textureCoordinate;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform mat4 u_colorMatrix;
|
||||
uniform vec4 u_vector;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
gl_FragColor = u_colorMatrix * texture2D(u_image, v_texCoord) + u_vector;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
gl_FragColor = texture2D(u_image, v_texCoord);
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
precision mediump float;
|
||||
uniform sampler2D u_image;
|
||||
uniform vec4 u_color;
|
||||
varying vec2 v_texCoord;
|
||||
void main() {
|
||||
gl_FragColor = texture2D(u_image, v_texCoord) * vec4(1.9, 1.0, 1.0, 1.0);
|
||||
gl_FragColor = texture2D(u_image, v_texCoord) * u_color;
|
||||
}
|
Загрузка…
Ссылка в новой задаче