Skip to content

Instantly share code, notes, and snippets.

@Themaister
Created September 17, 2011 22:50
Show Gist options
  • Save Themaister/1224459 to your computer and use it in GitHub Desktop.
Save Themaister/1224459 to your computer and use it in GitHub Desktop.
<html>
<head>
<title>XML Shader (1.0) Viewer</title>
</head>
<body onload="webGLStart();">
<input type="button" onclick="do_resize(0.25)" value="Scale 0.25x"/>
<input type="button" onclick="do_resize(0.5)" value="Scale 0.5x"/>
<input type="button" onclick="do_resize(1)" value="Scale 1x"/>
<input type="button" onclick="do_resize(2)" value="Scale 2x"/>
<input type="button" onclick="do_resize(3)" value="Scale 3x"/>
<input type="button" onclick="do_resize(4)" value="Scale 4x"/>
<input type="button" onclick="do_resize(5)" value="Scale 5x"/><br/>
<p>Image: <input type="file" id="image_file" name="files[]"/></p>
<p>Shader: <input type="file" id="shader_file" name="files[]"/></p>
<canvas id="test_canvas" style="border: none" width="256" height="224"></canvas><br/>
<output id="text_output"></output><br/>
</body>
<script type="text/javascript">
function do_resize(scale) {
var canvas = document.getElementById("test_canvas");
canvas.width = texture_.image.width * scale;
canvas.height = texture_.image.height * scale;
}
</script>
<script id="vertex_shader" type="x-shader/x-vertex">
attribute vec2 rubyVertex;
attribute vec2 rubyTexCoord;
varying vec4 rubyTexCoord_[8];
void main()
{
gl_Position = vec4(rubyVertex, 0.0, 1.0);
rubyTexCoord_[0] = vec4(rubyTexCoord, 0.0, 1.0);
}
</script>
<script id="fragment_shader" type="x-shader/x-fragment">
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D rubyTexture;
varying vec4 rubyTexCoord_[5];
void main()
{
gl_FragColor = texture2D(rubyTexture, rubyTexCoord_[0].xy);
}
</script>
<script type="text/javascript">
var gl;
function initGL(canvas) {
try {
gl = canvas.getContext("experimental-webgl");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
} catch (e) {}
if (!gl) {
alert("Could not init WebGL ... :(");
}
}
function getShader(id) {
var script = document.getElementById(id);
if (!script) { return null; }
var str = "";
var k = script.firstChild;
while (k) {
if (k.nodeType == 3) { // Magic number 3, what :v
str += k.textContent;
}
k = k.nextSibling;
}
var shader;
if (script.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (script.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
return null;
}
gl.shaderSource(shader, str);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(shader));
return null;
}
return shader;
}
var texture_ = null;
function set_image(img) {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
// Would prefer clamp to border,
// but GLES only supports CLAMP_TO_EDGE with NPOT textures.
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);
}
function load_image(evt) {
if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
alert("FileReader API not supported by this browser ...");
return;
}
var file = evt.target.files[0];
if (!file.type.match("image.*")) {
alert("This is not an image file! :(");
return;
}
var reader = new FileReader();
reader.onload =
function(e) {
texture_.old_img = texture_.image;
texture_.image = new Image();
texture_.image.onload = function() {
if (texture_.image.width > 0 && texture_.image.height > 0) {
try {
set_image(texture_.image);
do_resize(1);
} catch (e) {
texture_.image = texture_.old_img;
alert(e);
}
} else {
texture_.image = texture_.old_img;
}
}
texture_.image.src = e.target.result;
}
reader.readAsDataURL(file);
}
function parse_xml(text) {
try {
var vert = null;
var frag = null;
var parser = new DOMParser();
var xmldoc = parser.parseFromString(text, "text/xml");
var elems;
elems = xmldoc.getElementsByTagName("vertex");
if (elems.length > 0) {
vert = elems[0].childNodes[0].nodeValue;
}
elems = xmldoc.getElementsByTagName("fragment");
if (elems.length > 0) {
frag = elems[0].childNodes[0].nodeValue;
}
} catch (e) {
alert(e);
}
return {
vert: vert,
frag: frag
};
}
function transform_vert(vert_) {
var vert = "const mat4 trans_matrix_ = mat4(1.0, 0.0, 0.0, 0.0,\n";
vert += "0.0, 1.0, 0.0, 0.0,\n";
vert += "0.0, 0.0, 1.0, 0.0,\n";
vert += "0.0, 0.0, 0.0, 1.0);\n";
vert += "#define gl_ModelViewProjectionMatrix trans_matrix_\n";
vert += "#define gl_Vertex vec4(rubyVertex, 0.0, 1.0)\n";
vert += "#define gl_MultiTexCoord0 vec4(rubyTexCoord, 0.0, 0.0)\n";
vert += "attribute vec2 rubyVertex;\n";
vert += "attribute vec2 rubyTexCoord;\n";
vert += "varying vec4 rubyTexCoord_[8];\n";
vert += "#define gl_TexCoord rubyTexCoord_\n";
vert += vert_;
return vert;
}
function transform_frag(frag_) {
var frag = "precision highp float;\n";
frag += "varying vec4 rubyTexCoord_[8];\n";
frag += "#define gl_TexCoord rubyTexCoord_\n";
frag += frag_;
return frag;
}
function compile_xml_shader(vert, frag) {
var vert_s = null;
var frag_s = null;
if (vert) {
vert_s = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vert_s, transform_vert(vert));
gl.compileShader(vert_s);
if (!gl.getShaderParameter(vert_s, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(vert_s));
return;
}
} else {
vert_s = getShader("vertex_shader");
}
if (frag) {
frag_s = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(frag_s, transform_frag(frag));
gl.compileShader(frag_s);
if (!gl.getShaderParameter(frag_s, gl.COMPILE_STATUS)) {
alert(gl.getShaderInfoLog(frag_s));
return;
}
} else {
frag_s = getShader("fragment_shader");
}
gl.deleteProgram(prog);
prog = gl.createProgram();
gl.attachShader(prog, vert_s);
gl.attachShader(prog, frag_s);
gl.linkProgram(prog);
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
alert(gl.getProgramInfoLog(prog));
return;
}
prog.vert = vert_s;
prog.frag = frag_s;
gl.useProgram(prog);
prog.vert_attr = gl.getAttribLocation(prog, "rubyVertex");
prog.tex_attr = gl.getAttribLocation(prog, "rubyTexCoord");
gl.enableVertexAttribArray(prog.vert_attr);
gl.enableVertexAttribArray(prog.tex_attr);
gl.uniform1i(gl.getUniformLocation(prog, "rubyTexture"), 0);
gl.vertexAttribPointer(prog.tex_attr, 2, gl.FLOAT, false, 4 * 4, 0 * 4);
gl.vertexAttribPointer(prog.vert_attr, 2, gl.FLOAT, false, 4 * 4, 2 * 4);
}
function load_text(evt) {
if (!(window.File && window.FileReader && window.FileList && window.Blob)) {
alert("FileReader API not supported by this browser ...");
return;
}
if (!window.DOMParser) {
alert("No XML parser found :(");
return;
}
var file = evt.target.files[0];
if (!file.name.match("\\.shader$")) {
alert("Not an XML shader!");
return;
}
var reader = new FileReader();
reader.onload =
function(e) {
var xml = parse_xml(e.target.result);
var output = document.getElementById("text_output");
output.innerHTML = "";
if (xml.vert != null) {
output.innerHTML += '<textarea cols="50" rows="10" style="font-family:monospace">'
+ xml.vert + '</textarea>';
}
if (xml.frag != null) {
output.innerHTML += '<textarea cols="50" rows="10" style="font-family:monospace">'
+ xml.frag + '</textarea>';
}
try {
compile_xml_shader(xml.vert, xml.frag);
} catch (e) {
alert(e);
}
}
reader.readAsText(file);
}
document.getElementById("image_file").addEventListener('change', load_image, false);
document.getElementById("shader_file").addEventListener('change', load_text, false);
var prog;
function initShaders() {
prog = gl.createProgram();
prog.frag = getShader("fragment_shader");
prog.vertex = getShader("vertex_shader");
gl.attachShader(prog, prog.frag);
gl.attachShader(prog, prog.vertex);
gl.linkProgram(prog);
if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
alert("Failed to init shader!");
}
gl.useProgram(prog);
prog.vert_attr = gl.getAttribLocation(prog, "rubyVertex");
prog.tex_attr = gl.getAttribLocation(prog, "rubyTexCoord");
gl.enableVertexAttribArray(prog.vert_attr);
gl.enableVertexAttribArray(prog.tex_attr);
gl.uniform1i(gl.getUniformLocation(prog, "rubyTexture"), 0);
gl.enable(gl.TEXTURE_2D);
texture_ = gl.createTexture();
texture_.image = new Image();
texture_.image.width = 0;
texture_.image.height = 0;
gl.bindTexture(gl.TEXTURE_2D, texture_);
}
var vert_buf;
function initBuffers() {
vert_buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vert_buf);
var coords = [
// TEX // VERT
0.0, 0.0, -1.0, 1.0,
1.0, 0.0, 1.0, 1.0,
0.0, 1.0, -1.0, -1.0,
1.0, 1.0, 1.0, -1.0,
];
coords.size = 4;
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(coords), gl.STATIC_DRAW);
gl.vertexAttribPointer(prog.tex_attr, 2, gl.FLOAT, false, 4 * coords.size, 0 * coords.size);
gl.vertexAttribPointer(prog.vert_attr, 2, gl.FLOAT, false, 4 * coords.size, 2 * coords.size);
}
function do_render() {
if (texture_.image.width == 0 && texture_.image.height == 0)
return;
var canvas = document.getElementById("test_canvas");
gl.viewportWidth = canvas.width;
gl.viewportHeight = canvas.height;
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.uniform2f(gl.getUniformLocation(prog, "rubyTextureSize"),
texture_.image.width, texture_.image.height);
gl.uniform2f(gl.getUniformLocation(prog, "rubyInputSize"),
texture_.image.width, texture_.image.height);
gl.uniform2f(gl.getUniformLocation(prog, "rubyOutputSize"),
gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.flush();
}
function webGLStart() {
try {
var canvas = document.getElementById("test_canvas");
initGL(canvas);
initShaders();
initBuffers();
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
var f = function() {
window.setTimeout(f, 100);
do_render();
};
f();
} catch (e) {
alert(e);
}
}
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment