Here's an example of using webgl. It's a start of what might turn into a paint program.
If it's working right you should see a green square on the page when it loads. Drag the mouse over it and random colored squares will appear with a magenta triangle on the right (over top of the drawing - the green square underneath). My next step, I think, will involve introducing a second "program" - my understanding is that a webgl "program" always consists of the two shaders and that different operations are performed by using different programs. In J terms, a shader is probably best thought of as a specialized gerund (one for position with vertices being an item, one for color where a "pixel" or a "fragment" being an item), a program as a conjunction or the verb which results after giving the conjunction a pair of these shaders. The subtle distinction between a pixel and a fragment is also kind of interesting, but I want to try more things so I have a better understanding of the capabilities of this kind of system. I am also thinking of writing a J-like library so I can work with comfortable-ish operations in javascript (maybe closer to VSAPL than true J, because I just want basic functionality - if I want to do heavy duty computation I think I'd prefer to use JHS, and the limitations of browser access to things like files only reinforce that impression). Anyways, since other people are working with webgl, perhaps this is of interest. (I should also note that I've not made any significant effort to make this portable, so I have no idea if it will work for you. If nothing else, not all browsers even support webgl.) Thanks, -- Raul <html> <title>WebGL Example</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script> <script> function useShader(gl, program, scriptId) { var shaderScript= document.getElementById(scriptId); console.log('shaderScript: ',shaderScript); var shaderType= gl[shaderScript.type.replace(/.*\//,'')]; console.log('shaderType: ',shaderType); var shader= gl.createShader(shaderType); console.log('shader: ',shader); gl.shaderSource(shader, shaderScript.text); gl.compileShader(shader); var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS); console.log('compiled: ',compiled); if (!compiled) { throw('error creating shader "' + scriptId + '": ' + gl.getShaderInfoLog(shader)); } gl.attachShader(program, shader); return shader; }; function beginProgram(gl, pixelShader, vertexShader) { var program = gl.createProgram(); console.log('program: ',program); useShader(gl, program, pixelShader); console.log('pixel shader: ',pixelShader); useShader(gl, program, vertexShader); console.log('vertex shader',vertexShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {throw('error from linkProgram: '+gl.getProgramInfoLog(program))} gl.useProgram(program); return program; }; window.onload = function() { window.canvas = document.getElementById("canvas"); console.log('canvas: ',canvas); window.gl = canvas.getContext('webgl', {preserveDrawingBuffer: true}); console.log('graphics library: ',gl); window.bcr= canvas.getBoundingClientRect(); console.log('bounding client rectangle (left, top): ',bcr, bcr.left, bcr.top); program = beginProgram(gl, '2d-fragment-shader', '2d-vertex-shader'); gl.bindBuffer(gl.ARRAY_BUFFER, gl.createBuffer()); // tell vertex shader the size of our drawing region gl.uniform2f(gl.getUniformLocation(program, "resolution"), canvas.width, canvas.height); // and where each vertex is - our array buffer will be shaped as a list of coordinate pairs var positionLocation = gl.getAttribLocation(program, "position"); console.log('positionLocation: ',positionLocation); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); // meanwhile, our fragment shader will need to know what color we are drawing window.colorLocation= gl.getUniformLocation(program, 'color'); console.log('colorLocation: ',colorLocation); // example of rendering: draw a pair of green triangles to form a square gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([20,30, 50,30, 20,60, 20,60, 50,30, 50,60]), gl.STATIC_DRAW); gl.uniform4f(colorLocation, 0, 1, 0, 1); // (red,green,blue,alpha) gl.drawArrays(gl.TRIANGLES, 0, 6); self.mousedown= 0; $('#canvas').on('mousedown', function(e) {render(1,e)}); $('#canvas').on('mousemove', function(e) {render(0,e)}); $('body').on('mouseup', function(e) {render(-1,e)}); window.gl = canvas.getContext('webgl'); console.log('gl: ',gl); } function render(mode, e) { if (0===mode && 1===mousedown) { var x= e.clientX-bcr.left; var y= e.clientY-bcr.top; var width= 9; var height=9; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ x, y, x+width, y, x, y+height, x, y+height, x+width, y, x+width, y+height]), gl.STATIC_DRAW); gl.uniform4f(colorLocation, Math.random(), Math.random(), Math.random(), 1); gl.drawArrays(gl.TRIANGLES, 0, 6); // each time we add something to the screen put a purple triangle on top of it gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 310, 10, 390, 80, 310, 149]), gl.STATIC_DRAW); gl.uniform4f(colorLocation, 1, 0, 1, 1); gl.drawArrays(gl.TRIANGLES, 0, 3); } else { self.mousedown= mode; } } function randomInt(range){return Math.floor(Math.random()*range);} </script> <script id="2d-vertex-shader" type="x-shader/VERTEX_SHADER"> attribute vec2 position; uniform vec2 resolution; void main() { vec2 zeroToOne = position / resolution; // convert the rectangle from pixels to 0.0 to 1.0 vec2 zeroToTwo = zeroToOne * 2.0; // convert from 0->1 to 0->2 vec2 clipSpace = zeroToTwo - 1.0; // convert from 0->2 to -1->+1 (clipspace) gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); } </script> <script id="2d-fragment-shader" type="x-shader/FRAGMENT_SHADER"> precision mediump float; uniform vec4 color; void main() { gl_FragColor = color; } </script> </head> <body style="margin: 8px"> <canvas id="canvas" width="400" height="300"></canvas> </body> </html> ---------------------------------------------------------------------- For information about J forums see http://www.jsoftware.com/forums.htm
