diff options
Diffstat (limited to 'examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js')
-rw-r--r-- | examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js | 483 |
1 files changed, 483 insertions, 0 deletions
diff --git a/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js b/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js new file mode 100644 index 0000000..e7102fe --- /dev/null +++ b/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js @@ -0,0 +1,483 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCanvas3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +Qt.include("gl-matrix.js") + +// +// Draws a cube that has the Qt logo as decal texture on each face in to a texture. +// That texture is used as the texture for drawing another cube on the screen. +// + +var gl; + +//! [0] +var rttFramebuffer; +var rttTexture; +var rttWidth = 512; +var rttHeight = 512; +//! [0] + +var cubeTexture = 0; + +var vertexPositionAttribute; +var textureCoordAttribute; +var vertexNormalAttribute; +var vertexColorAttribute; +var mvMatrix = mat4.create(); +var pMatrix = mat4.create(); +var nMatrix = mat4.create(); +var pMatrixUniform; +var mvMatrixUniform; +var nUniform; + +var canvas3d; +var isLogEnabled = false; + +function log(message) { + if (isLogEnabled) + console.log(message) +} + +function initializeGL(canvas, textureLoader) { + canvas3d = canvas + try { + // Get the OpenGL context object that represents the API we call + gl = canvas.getContext("canvas3d", {depth:true, antialias:true, alpha:false}); + + // Setup the OpenGL state + gl.enable(gl.DEPTH_TEST); + gl.enable(gl.CULL_FACE); + gl.cullFace(gl.BACK); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); + + // Initialize the shader program + initShaders(); + + // Initialize vertex and color buffers + initBuffers(); + + // Load the Qt logo as texture + var qtLogoImage = TextureImageFactory.newTexImage(); + qtLogoImage.imageLoaded.connect(function() { + cubeTexture = gl.createTexture(); + cubeTexture.name = "CubeTexture"; + gl.bindTexture(gl.TEXTURE_2D, cubeTexture); + gl.texImage2D(gl.TEXTURE_2D, // target + 0, // level + gl.RGBA, // internalformat + gl.RGBA, // format + gl.UNSIGNED_BYTE, // type + qtLogoImage); // pixels + + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); + gl.generateMipmap(gl.TEXTURE_2D); + }); + qtLogoImage.imageLoadingFailed.connect(function() { + console.log("Texture load FAILED, "+qtLogoImage.errorString); + }); + qtLogoImage.src = "qrc:/qtlogo.png"; + + //! [1] + // Create the framebuffer object + rttFramebuffer = gl.createFramebuffer(); + rttFramebuffer.name = "OffscreenRenderTarget"; + gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer); + //! [1] + + //! [2] + // Create the texture + rttTexture = gl.createTexture(); + rttTexture.name = "OffscreenRenderTargetTexture"; + gl.bindTexture(gl.TEXTURE_2D, rttTexture); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); + gl.texImage2D(gl.TEXTURE_2D, 0, + gl.RGBA, rttWidth, rttHeight, + 0, gl.RGBA, gl.UNSIGNED_BYTE, + null); + gl.generateMipmap(gl.TEXTURE_2D); + //! [2] + + //! [3] + // Bind the texture as color attachment, create and bind a depth buffer + gl.framebufferTexture2D(gl.FRAMEBUFFER, + gl.COLOR_ATTACHMENT0, + gl.TEXTURE_2D, rttTexture, 0); + var renderbuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, + gl.DEPTH_COMPONENT16, + rttWidth, rttHeight); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, + gl.DEPTH_ATTACHMENT, + gl.RENDERBUFFER, renderbuffer); + //! [3] + gl.bindTexture(gl.TEXTURE_2D, 0); + gl.bindRenderbuffer(gl.RENDERBUFFER, 0); + gl.bindFramebuffer(gl.FRAMEBUFFER, 0); + } catch(e) { + console.log("initializeGL FAILURE!"); + console.log(""+e); + console.log(""+e.message); + } +} + +function degToRad(degrees) { + return degrees * Math.PI / 180; +} + +function paintGL(canvas) { + //! [4] + // bind the FBO and setup viewport + gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer); + gl.viewport(0, 0, rttWidth, rttHeight); + //! [4] + + gl.clearColor(0.95, 0.95, 0.95, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + //! [5] + // Bind the loaded texture + gl.bindTexture(gl.TEXTURE_2D, cubeTexture); + //! [5] + + // Calculate and set matrix uniforms + mat4.perspective(pMatrix, degToRad(45), rttWidth / rttHeight, 0.1, 100.0); + gl.uniformMatrix4fv(pMatrixUniform, false, pMatrix); + + mat4.identity(mvMatrix); + mat4.translate(mvMatrix, mvMatrix, [0, 0, -5.0]); + mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotSlider), [0, 1, 0]); + mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotSlider), [1, 0, 0]); + mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotSlider), [0, 0, 1]); + gl.uniformMatrix4fv(mvMatrixUniform, false, mvMatrix); + + mat4.invert(nMatrix, mvMatrix); + mat4.transpose(nMatrix, nMatrix); + gl.uniformMatrix4fv(nUniform, false, nMatrix); + + //! [6] + // Draw the cube to the FBO + gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); + //! [6] + + //! [7] + // Bind the render-to-texture and generate mipmaps + gl.bindTexture(gl.TEXTURE_2D, rttTexture); + gl.generateMipmap(gl.TEXTURE_2D); + //! [7] + + //! [8] + // Bind default framebuffer and setup viewport accordingly + gl.bindFramebuffer(gl.FRAMEBUFFER, 0); + gl.viewport(0, 0, + canvas.width * canvas.devicePixelRatio, + canvas.height * canvas.devicePixelRatio); + //! [8] + gl.clearColor(0.98, 0.98, 0.98, 1.0); + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); + + // Calculate and set matrix uniforms + mat4.perspective(pMatrix, degToRad(45), canvas.width / canvas.height, 0.1, 100.0); + gl.uniformMatrix4fv(pMatrixUniform, false, pMatrix); + + mat4.identity(mvMatrix); + mat4.translate(mvMatrix, mvMatrix, [(canvas.yRotAnim - 120.0) / 120.0, + (canvas.xRotAnim - 60.0) / 50.0, + -10.0]); + mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotAnim), [0, 1, 0]); + gl.uniformMatrix4fv(mvMatrixUniform, false, mvMatrix); + + mat4.invert(nMatrix, mvMatrix); + mat4.transpose(nMatrix, nMatrix); + gl.uniformMatrix4fv(nUniform, false, nMatrix); + + //! [9] + // Draw the on-screen cube + gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0); + //! [9] +} + +function resizeGL(canvas) +{ + var pixelRatio = canvas.devicePixelRatio; + canvas.pixelSize = Qt.size(canvas.width * pixelRatio, + canvas.height * pixelRatio); +} + +function initBuffers() +{ + log(" cubeVertexPositionBuffer"); + var cubeVertexPositionBuffer = gl.createBuffer(); + cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer"; + gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer); + gl.bufferData( + gl.ARRAY_BUFFER, + new Float32Array([// Front face + -1.0, -1.0, 1.0, + 1.0, -1.0, 1.0, + 1.0, 1.0, 1.0, + -1.0, 1.0, 1.0, + + // Back face + -1.0, -1.0, -1.0, + -1.0, 1.0, -1.0, + 1.0, 1.0, -1.0, + 1.0, -1.0, -1.0, + + // Top face + -1.0, 1.0, -1.0, + -1.0, 1.0, 1.0, + 1.0, 1.0, 1.0, + 1.0, 1.0, -1.0, + + // Bottom face + -1.0, -1.0, -1.0, + 1.0, -1.0, -1.0, + 1.0, -1.0, 1.0, + -1.0, -1.0, 1.0, + + // Right face + 1.0, -1.0, -1.0, + 1.0, 1.0, -1.0, + 1.0, 1.0, 1.0, + 1.0, -1.0, 1.0, + + // Left face + -1.0, -1.0, -1.0, + -1.0, -1.0, 1.0, + -1.0, 1.0, 1.0, + -1.0, 1.0, -1.0 + ]), + gl.STATIC_DRAW); + + gl.enableVertexAttribArray(vertexPositionAttribute); + gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0); + + log(" cubeVertexIndexBuffer"); + var cubeVertexIndexBuffer = gl.createBuffer(); + cubeVertexIndexBuffer.name = "cubeVertexIndexBuffer"; + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); + gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, + new Uint16Array([ + 0, 1, 2, 0, 2, 3, // front + 4, 5, 6, 4, 6, 7, // back + 8, 9, 10, 8, 10, 11, // top + 12, 13, 14, 12, 14, 15, // bottom + 16, 17, 18, 16, 18, 19, // right + 20, 21, 22, 20, 22, 23 // left + ]), + gl.STATIC_DRAW); + gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer); + + log(" cubeVerticesTextureCoordBuffer"); + var cubeVerticesTextureCoordBuffer = gl.createBuffer(); + cubeVerticesTextureCoordBuffer.name = "cubeVerticesTextureCoordBuffer"; + gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer); + var textureCoordinates = [ + // Front + 1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + // Back + 1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + // Top + 1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + // Bottom + 1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + // Right + 1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0, + // Left + 1.0, 0.0, + 0.0, 0.0, + 0.0, 1.0, + 1.0, 1.0 + ]; + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), + gl.STATIC_DRAW); + gl.enableVertexAttribArray(textureCoordAttribute); + gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0); + + var cubeVerticesNormalBuffer = gl.createBuffer(); + cubeVerticesNormalBuffer.name = "cubeVerticesNormalBuffer"; + gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer); + gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ + // Front + 0.0, 0.0, 1.0, + 0.0, 0.0, 1.0, + 0.0, 0.0, 1.0, + 0.0, 0.0, 1.0, + + // Back + 0.0, 0.0, -1.0, + 0.0, 0.0, -1.0, + 0.0, 0.0, -1.0, + 0.0, 0.0, -1.0, + + // Top + 0.0, 1.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 1.0, 0.0, + 0.0, 1.0, 0.0, + + // Bottom + 0.0, -1.0, 0.0, + 0.0, -1.0, 0.0, + 0.0, -1.0, 0.0, + 0.0, -1.0, 0.0, + + // Right + 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, + 1.0, 0.0, 0.0, + + // Left + -1.0, 0.0, 0.0, + -1.0, 0.0, 0.0, + -1.0, 0.0, 0.0, + -1.0, 0.0, 0.0 + ]), gl.STATIC_DRAW); + gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer); + gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0); +} + +function initShaders() +{ + var vertexShader = getShader(gl, + "attribute highp vec3 aVertexNormal; \ + attribute highp vec3 aVertexPosition; \ + attribute highp vec2 aTextureCoord; \ + + uniform highp mat4 uNormalMatrix; \ + uniform mat4 uMVMatrix; \ + uniform mat4 uPMatrix; \ + + varying mediump vec4 vColor; \ + varying highp vec2 vTextureCoord; \ + varying highp vec3 vLighting; \ + + void main(void) { \ + gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); \ + vTextureCoord = aTextureCoord; \ + highp vec3 ambientLight = vec3(0.5, 0.5, 0.5); \ + highp vec3 directionalLightColor = vec3(0.75, 0.75, 0.75); \ + highp vec3 directionalVector = vec3(0.85, 0.8, 0.75); \ + highp vec4 transformedNormal = uNormalMatrix * vec4(aVertexNormal, 1.0); \ + highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0); \ + vLighting = ambientLight + (directionalLightColor * directional); \ + }", gl.VERTEX_SHADER); + var fragmentShader = getShader(gl, + "varying highp vec2 vTextureCoord; \ + varying highp vec3 vLighting; \ + + uniform sampler2D uSampler; \ + + void main(void) { \ + mediump vec3 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t)).rgb; \ + gl_FragColor = vec4(texelColor * vLighting, 1.0); \ + }", gl.FRAGMENT_SHADER); + + var shaderProgram = gl.createProgram(); + gl.attachShader(shaderProgram, vertexShader); + gl.attachShader(shaderProgram, fragmentShader); + gl.linkProgram(shaderProgram); + + if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { + console.log("Could not initialise shaders"); + console.log(gl.getProgramInfoLog(shaderProgram)); + } + + gl.useProgram(shaderProgram); + + // look up where the vertex data needs to go. + vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); + gl.enableVertexAttribArray(vertexPositionAttribute); + textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); + gl.enableVertexAttribArray(textureCoordAttribute); + vertexNormalAttribute =gl.getAttribLocation(shaderProgram, "aVertexNormal"); + gl.enableVertexAttribArray(vertexNormalAttribute); + + pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); + mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); + nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix"); + + var textureSamplerUniform = gl.getUniformLocation(shaderProgram, "uSampler") + gl.activeTexture(gl.TEXTURE0); + gl.uniform1i(textureSamplerUniform, 0); +} + +function getShader(gl, str, type) { + var shader = gl.createShader(type); + gl.shaderSource(shader, str); + gl.compileShader(shader); + + if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { + console.log("JS:Shader compile failed"); + console.log(gl.getShaderInfoLog(shader)); + return null; + } + + return shader; +} |