nuclear@0: /* nuclear@0: glass - (web)gl-assistant. nuclear@0: Copyright (C) 2011 John Tsiombikas nuclear@0: nuclear@0: This program is free software: you can redistribute it and/or modify nuclear@0: it under the terms of the GNU General Public License as published by nuclear@0: the Free Software Foundation, either version 3 of the License, or nuclear@0: (at your option) any later version. nuclear@0: nuclear@0: This program is distributed in the hope that it will be useful, nuclear@0: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@0: GNU General Public License for more details. nuclear@0: nuclear@0: You should have received a copy of the GNU General Public License nuclear@0: along with this program. If not, see . nuclear@0: */ nuclear@0: nuclear@0: var gl; nuclear@0: var canvas, console; nuclear@0: var glass_data_loaded, glass_data_count; nuclear@0: var glass_progr_prog; nuclear@0: var glass_start_time = 0; nuclear@0: nuclear@0: var glass_cb_disp = null; nuclear@2: var glass_cb_mouse = null; nuclear@2: var glass_cb_motion = null; nuclear@0: nuclear@0: function glass_init(canv_id, cons_id) nuclear@0: { nuclear@0: if(cons_id && (console = document.getElementById(cons_id))) { nuclear@0: console.value = ""; nuclear@0: } nuclear@0: nuclear@0: if(!(canvas = document.getElementById(canv_id))) { nuclear@0: logmsg("canvas \"" + canv_id + "\" does not exist\n"); nuclear@0: return false; nuclear@0: } nuclear@0: try { nuclear@0: gl = canvas.getContext("experimental-webgl"); nuclear@0: } nuclear@0: catch(e) { nuclear@0: logmsg("can't get an OpenGL context\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: var vs = create_shader(glass_progr_vs_src, gl.VERTEX_SHADER); nuclear@0: var ps = create_shader(glass_progr_ps_src, gl.FRAGMENT_SHADER); nuclear@0: if(!vs || !ps || !(glass_progr_prog = create_program(vs, ps))) { nuclear@0: logmsg("internal glass error\n"); nuclear@0: return false; nuclear@0: } nuclear@0: nuclear@0: glass_data_loaded = glass_data_count = 0; nuclear@0: return true; nuclear@0: } nuclear@0: nuclear@0: function glass_start() nuclear@0: { nuclear@2: if(glass_cb_motion) { nuclear@2: canvas.onmousemove = function(ev) { nuclear@2: glass_cb_motion(ev.clientX, ev.clientY); nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: if(glass_cb_mouse) { nuclear@2: canvas.onmousedown = function(ev) { nuclear@2: glass_cb_mouse(ev.button, true, ev.clientX, ev.clientY); nuclear@2: } nuclear@2: canvas.onmouseup = function(ev) { nuclear@2: glass_cb_mouse(ev.button, false, ev.clientX, ev.clientY); nuclear@2: } nuclear@2: } nuclear@2: nuclear@0: glass_start_time = get_msec(); nuclear@0: glass_redraw(); nuclear@0: } nuclear@0: nuclear@0: function glass_display_func(func) nuclear@0: { nuclear@0: glass_cb_disp = func; nuclear@0: } nuclear@0: nuclear@2: function glass_mouse_func(func) nuclear@2: { nuclear@2: glass_cb_mouse = func; nuclear@2: } nuclear@2: nuclear@2: function glass_motion_func(func) nuclear@2: { nuclear@2: glass_cb_motion = func; nuclear@2: } nuclear@2: nuclear@2: nuclear@0: function glass_redraw() nuclear@0: { nuclear@0: var msec = get_msec(); nuclear@0: nuclear@0: if(glass_data_loaded < glass_data_count || !glass_cb_disp) { nuclear@0: glass_draw_progress(msec); nuclear@0: } else { nuclear@0: glass_cb_disp(msec); nuclear@0: } nuclear@0: request_redisplay(glass_redraw); nuclear@0: } nuclear@0: nuclear@0: function get_msec() nuclear@0: { nuclear@0: return new Date().getTime() - glass_start_time; nuclear@0: } nuclear@0: nuclear@0: /* ---- textures ---- */ nuclear@0: function load_texture(name) nuclear@0: { nuclear@0: glass_data_count++; nuclear@0: nuclear@0: var tex = gl.createTexture(); nuclear@0: tex.image = new Image(); nuclear@0: tex.image.onload = function() { glass_tex_load_done(tex); } nuclear@0: tex.image.onerror = glass_tex_load_failed; nuclear@0: tex.image.src = name; nuclear@0: return tex; nuclear@0: } nuclear@0: nuclear@0: function glass_tex_load_done(tex) nuclear@0: { nuclear@0: gl.bindTexture(gl.TEXTURE_2D, tex); nuclear@0: gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tex.image); nuclear@0: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); nuclear@0: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); nuclear@0: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); nuclear@0: gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); nuclear@0: gl.bindTexture(gl.TEXTURE_2D, null); nuclear@0: glass_data_loaded++; nuclear@0: logmsg("loaded image: " + tex.image.src + nuclear@0: " (" + glass_data_loaded + "/" + glass_data_count + ")\n"); nuclear@0: } nuclear@0: nuclear@0: function glass_tex_load_failed() nuclear@0: { nuclear@0: logmsg("failed to load texture: " + this.src + "\n"); nuclear@0: } nuclear@0: nuclear@0: nuclear@0: /* ---- shaders ---- */ nuclear@0: function load_shader(name, type) nuclear@0: { nuclear@0: var xhr = new XMLHttpRequest(); nuclear@0: xhr.open("GET", name, false); nuclear@0: xhr.overrideMimeType("text/plain"); nuclear@0: xhr.send(null); nuclear@0: nuclear@0: var src = xhr.responseText; nuclear@2: return create_shader(src, type, name); nuclear@0: } nuclear@0: nuclear@2: function create_shader(src, type, name) nuclear@0: { nuclear@0: var sdr = gl.createShader(type); nuclear@0: gl.shaderSource(sdr, src); nuclear@0: gl.compileShader(sdr); nuclear@0: nuclear@0: if(!gl.getShaderParameter(sdr, gl.COMPILE_STATUS)) { nuclear@2: if(!name) { nuclear@2: name = ""; nuclear@2: } nuclear@2: logmsg("failed to compile shader: " + name + ": " + gl.getShaderInfoLog(sdr)); nuclear@0: return null; nuclear@0: } nuclear@0: return sdr; nuclear@0: } nuclear@0: nuclear@0: function load_program(vsname, psname) nuclear@0: { nuclear@0: var vs, ps; nuclear@0: nuclear@0: if(!(vs = load_shader(vsname, gl.VERTEX_SHADER))) { nuclear@0: return null; nuclear@0: } nuclear@0: if(!(ps = load_shader(psname, gl.FRAGMENT_SHADER))) { nuclear@0: return null; nuclear@0: } nuclear@0: return create_program(vs, ps); nuclear@0: } nuclear@0: nuclear@0: function create_program(vs, ps) nuclear@0: { nuclear@0: var prog = gl.createProgram(); nuclear@0: gl.attachShader(prog, vs); nuclear@0: gl.attachShader(prog, ps); nuclear@0: gl.linkProgram(prog); nuclear@0: nuclear@0: if(!gl.getProgramParameter(prog, gl.LINK_STATUS)) { nuclear@0: logmsg("Failed to link GLSL program (" + vsname + " - " + psname + ")\n"); nuclear@0: return null; nuclear@0: } nuclear@0: return prog; nuclear@0: } nuclear@0: nuclear@3: function set_uniform1i(p, name, v) nuclear@3: { nuclear@3: var loc = gl.getUniformLocation(p, name); nuclear@3: if(loc != -1) { nuclear@3: gl.useProgram(p); nuclear@3: gl.uniform1i(loc, v); nuclear@3: } nuclear@3: } nuclear@3: nuclear@2: function set_uniform1f(p, name, v) nuclear@2: { nuclear@2: var loc = gl.getUniformLocation(p, name); nuclear@2: if(loc != -1) { nuclear@2: gl.useProgram(p); nuclear@2: gl.uniform1f(loc, v); nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: function set_uniform2f(p, name, x, y) nuclear@2: { nuclear@2: var loc = gl.getUniformLocation(p, name); nuclear@2: if(loc != -1) { nuclear@2: gl.useProgram(p); nuclear@2: gl.uniform2f(loc, x, y); nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: function set_uniform3f(p, name, x, y, z) nuclear@2: { nuclear@2: var loc = gl.getUniformLocation(p, name); nuclear@2: if(loc != -1) { nuclear@2: gl.useProgram(p); nuclear@2: gl.uniform3f(loc, x, y, z); nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: function set_uniform4f(p, name, x, y, z, w) nuclear@2: { nuclear@2: var loc = gl.getUniformLocation(p, name); nuclear@2: if(loc != -1) { nuclear@2: gl.useProgram(p); nuclear@2: gl.uniform4f(loc, x, y, z, w); nuclear@2: } nuclear@2: } nuclear@2: nuclear@2: function set_uniform_matrix4fv(p, name, mat) nuclear@2: { nuclear@2: var loc = gl.getUniformLocation(p, name); nuclear@2: if(loc != -1) { nuclear@2: gl.useProgram(p); nuclear@2: gl.uniformMatrix4fv(loc, false, mat); nuclear@2: } nuclear@2: } nuclear@2: nuclear@0: function logmsg(str) nuclear@0: { nuclear@0: if(console) { nuclear@0: console.value += str; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: window.request_redisplay = (function() { nuclear@0: return window.requestAnimationFrame || nuclear@0: window.webkitRequestAnimationFrame || nuclear@0: window.mozRequestAnimationFrame || nuclear@0: window.oRequestAnimationFrame || nuclear@0: window.msRequestAnimationFrame || nuclear@0: function(callback, element) { window.setTimeout(callback, 1000/60); }; nuclear@0: })(); nuclear@0: nuclear@0: nuclear@0: var glass_progr_vs_src = nuclear@0: "attribute vec4 attr_vertex, attr_color;\n" + nuclear@0: "uniform mat4 mvmat, projmat;\n" + nuclear@0: "varying vec4 color;\n" + nuclear@0: "void main()\n{\n" + nuclear@0: "\tmat4 mvp = projmat * mvmat;\n" + nuclear@0: "\tgl_Position = mvp * attr_vertex;\n" + nuclear@0: "\tcolor = attr_color;\n}\n"; nuclear@0: nuclear@0: var glass_progr_ps_src = nuclear@0: "precision highp float;\n" + nuclear@0: "varying vec4 color;\n" + nuclear@0: "void main()\n{\n" + nuclear@0: "\tgl_FragColor = color;\n}\n"; nuclear@0: nuclear@0: function glass_draw_progress(msec) nuclear@0: { nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glPushMatrix(); nuclear@0: glLoadIdentity(); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPushMatrix(); nuclear@0: glLoadIdentity(); nuclear@0: nuclear@0: gl.clearColor(0, 0, 0, 1); nuclear@0: gl.clear(gl.COLOR_BUFFER_BIT); nuclear@0: nuclear@0: var progr = glass_data_loaded / glass_data_count; nuclear@0: nuclear@0: gl.useProgram(glass_progr_prog); nuclear@0: nuclear@0: glBegin(GL_QUADS); nuclear@0: glColor3f(0.3, 0.5, 0.8); nuclear@0: glVertex2f(-0.55, -0.1); nuclear@0: glVertex2f(0.55, -0.1); nuclear@0: glVertex2f(0.55, 0.1); nuclear@0: glVertex2f(-0.55, 0.1); nuclear@0: nuclear@0: glColor3f(0, 0, 0); nuclear@0: glVertex2f(-0.525, -0.075); nuclear@0: glVertex2f(0.525, -0.075); nuclear@0: glVertex2f(0.525, 0.075); nuclear@0: glVertex2f(-0.525, 0.075); nuclear@0: nuclear@0: glColor3f(1.0, 0.3, 0.2); nuclear@0: glVertex2f(-0.5, -0.05); nuclear@0: glVertex2f(progr - 0.5, -0.05); nuclear@0: glVertex2f(progr - 0.5, 0.05); nuclear@0: glVertex2f(-0.5, 0.05); nuclear@0: glEnd(); nuclear@0: nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glPopMatrix(); nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: