package j15r.webgl.client; import static com.google.gwt.webgl.client.WebGLRenderingContext.*; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.dom.client.CanvasElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.ImageElement; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.typedarrays.client.Float32Array; import com.google.gwt.typedarrays.client.Int32Array; import com.google.gwt.user.client.Timer; import com.google.gwt.webgl.client.WebGLBuffer; import com.google.gwt.webgl.client.WebGLFramebuffer; import com.google.gwt.webgl.client.WebGLProgram; import com.google.gwt.webgl.client.WebGLRenderbuffer; import com.google.gwt.webgl.client.WebGLRenderingContext; import com.google.gwt.webgl.client.WebGLTexture; import com.google.gwt.webgl.client.WebGLUniformLocation; import com.google.gwt.webgl.client.WebGLUtil; public class WebGLDemo implements EntryPoint { private interface EventHandler { void onEvent(NativeEvent e); } private static final int CANVAS_WIDTH = 640; private static final int CANVAS_HEIGHT = 480; private static native ImageElement createImage() /*-{ return new Image(); }-*/; private static native void hookOnLoad(ImageElement img, EventHandler h) /*-{ img.addEventListener('load', function(e) { h.@j15r.webgl.client.WebGLDemo.EventHandler::onEvent(Lcom/google/gwt/dom/client/NativeEvent;)(e); }, false); }-*/; private WebGLBuffer buffer; private WebGLBuffer indexBuffer; private WebGLProgram shaderProgram; private float[] projectionMatrix; private float[] modelViewMatrix; protected CanvasElement canvas; protected WebGLRenderingContext gl; private WebGLTexture birdTexture; private WebGLFramebuffer fbuf; @Override public void onModuleLoad() { canvas = Document.get().createElement("canvas").cast(); Document.get().getBody().appendChild(canvas); canvas.setWidth(CANVAS_WIDTH); canvas.setHeight(CANVAS_HEIGHT); gl = WebGLRenderingContext.getContext(canvas); gl.viewport(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT); init(); new Timer() { @Override public void run() { draw(); } }.scheduleRepeating(100); } private void drawToFramebuffer() { gl.bindFramebuffer(FRAMEBUFFER, fbuf); gl.clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT); gl.bindTexture(TEXTURE_2D, birdTexture); drawQuad(); gl.bindTexture(TEXTURE_2D, null); gl.bindFramebuffer(FRAMEBUFFER, null); } private void draw() { gl.bindFramebuffer(FRAMEBUFFER, null); gl.clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT); gl.bindTexture(TEXTURE_2D, birdTexture); drawQuad(); gl.bindTexture(TEXTURE_2D, null); } private void drawQuad() { // Use the sole shader program. gl.useProgram(shaderProgram); // Projection matrix. WebGLUniformLocation pUniform = gl.getUniformLocation(shaderProgram, "projectionMatrix"); gl.uniformMatrix4fv(pUniform, false, projectionMatrix); // Model View matrix. WebGLUniformLocation mvUniform = gl.getUniformLocation(shaderProgram, "modelViewMatrix"); gl.uniformMatrix4fv(mvUniform, false, modelViewMatrix); // Bird texture. gl.activeTexture(TEXTURE0); gl.uniform1i(gl.getUniformLocation(shaderProgram, "texture"), 0); // Vertices (position, texCoord) gl.bindBuffer(ARRAY_BUFFER, buffer); int vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "vertexPosition"); gl.vertexAttribPointer(vertexPositionAttribute, 3, FLOAT, false, 0, 0); gl.enableVertexAttribArray(vertexPositionAttribute); int texCoordAttribute = gl.getAttribLocation(shaderProgram, "texCoord"); gl.vertexAttribPointer(texCoordAttribute, 2, FLOAT, false, 0, 12 * Float32Array.BYTES_PER_ELEMENT); gl.enableVertexAttribArray(texCoordAttribute); // Elements. gl.bindBuffer(ELEMENT_ARRAY_BUFFER, indexBuffer); gl.drawArrays(TRIANGLE_STRIP, 0, 4); } private void init() { // Basic stuff. gl.clearColor(0.0f, 0.0f, 0.0f, 1.0f); gl.enable(TEXTURE_2D); gl.enable(BLEND); gl.blendFunc(SRC_ALPHA, ONE_MINUS_SRC_ALPHA); // Projection matrix. //projectionMatrix = WebGLUtil.createPerspectiveMatrix(45, 1.0f, 0.1f, 100); projectionMatrix= new float[] { 2f/CANVAS_WIDTH,0,0,0, 0,2f/CANVAS_HEIGHT,0,0, 0,0,1,0, 0,0,0,1, }; // Model View matrix. modelViewMatrix = new float[] { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1, }; // Bird texture. birdTexture = createTexture("/bird.png"); // Compile the shader. shaderProgram = WebGLUtil.createShaderProgram(gl, Shaders.INSTANCE.vertexShader().getText(), Shaders.INSTANCE.fragmentShader().getText() ); // Create quad buffers. initVertexBuffer(); } private WebGLTexture createTexture() { WebGLTexture tex = gl.createTexture(); gl.bindTexture(TEXTURE_2D, tex); gl.texParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, LINEAR); gl.texParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, LINEAR); gl.texParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE); gl.texParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE); return tex; } private WebGLFramebuffer createFramebuffer(int width, int height) { WebGLTexture tex = createTexture(); fbuf = gl.createFramebuffer(); gl.texImage2D(TEXTURE_2D, 0, RGBA, width, height, 0, RGBA, UNSIGNED_BYTE, null); WebGLRenderbuffer rbuf = gl.createRenderbuffer(); gl.bindRenderbuffer(RENDERBUFFER, rbuf); gl.renderbufferStorage(RENDERBUFFER, RGBA4, width, height); gl.framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D, tex, 0); gl.framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER, rbuf); gl.bindTexture(TEXTURE_2D, null); gl.bindRenderbuffer(RENDERBUFFER, null); gl.bindFramebuffer(FRAMEBUFFER, null); return fbuf; } private WebGLTexture createTexture(String url) { // Create the texture object. final WebGLTexture tex = gl.createTexture(); // Load the image. final ImageElement img = createImage(); img.setSrc(url); hookOnLoad(img, new EventHandler() { @Override public void onEvent(NativeEvent e) { // Load image data into the texture object once it's loaded. gl.bindTexture(TEXTURE_2D, tex); gl.texImage2D(TEXTURE_2D, 0, RGBA, RGBA, UNSIGNED_BYTE, img); gl.texParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, LINEAR); gl.texParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, LINEAR); gl.texParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE); gl.texParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE); gl.bindTexture(TEXTURE_2D, null); } }); return tex; } private void initVertexBuffer() { // Create the vertex buffer. buffer = gl.createBuffer(); gl.bindBuffer(ARRAY_BUFFER, buffer); // (12 + 8) == positions (vec3 * 4) + texCoords (vec2 * 4) gl.bufferData(ARRAY_BUFFER, (12 + 8) * Float32Array.BYTES_PER_ELEMENT, STATIC_DRAW); float z = 0f; // doesn't matter really; [-1, 1] all in front of the camera // attribute vec3 vertexPosition; float[] positions = new float[] { -42/2f,-42/2f, z, 42/2f,-42/2f,z, -42/2f,42/2f,z, 42/2f,42/2f,z, }; gl.bufferSubData(ARRAY_BUFFER, 0, Float32Array.create(positions)); // attribute vec2 texCoord; float[] texCoords = new float[] { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, }; gl.bufferSubData(ARRAY_BUFFER, 12 * Float32Array.BYTES_PER_ELEMENT, Float32Array.create(texCoords)); // create the index buffer. int[] indices = new int[] { 0, 1, 2, 3 }; indexBuffer = gl.createBuffer(); gl.bindBuffer(ELEMENT_ARRAY_BUFFER, indexBuffer); gl.bufferData(ELEMENT_ARRAY_BUFFER, Int32Array.create(indices), STREAM_DRAW); } }