summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPasi Keränen <Pasi.Keranen@digia.com>2014-08-20 11:46:26 +0300
committerFrederik Gladhorn <frederik.gladhorn@digia.com>2014-08-20 17:13:44 +0200
commit66e9d956d3055483597416b864204a51fde1c745 (patch)
treee70b75d8ed14ff836758db10756b0bf5c2759a23
Initial commit
-rw-r--r--.qmake.conf6
-rw-r--r--examples/canvas3d/canvas3d.pro11
-rw-r--r--examples/canvas3d/canvasswitch/canvasswitch.pro11
-rw-r--r--examples/canvas3d/canvasswitch/canvasswitch.qrc8
-rw-r--r--examples/canvas3d/canvasswitch/doc/images/canvasswitch-example.pngbin0 -> 21926 bytes
-rw-r--r--examples/canvas3d/canvasswitch/doc/src/canvasswitch.qdoc82
-rw-r--r--examples/canvas3d/canvasswitch/main.cpp66
-rw-r--r--examples/canvas3d/canvasswitch/qml/canvasswitch/cube.js216
-rw-r--r--examples/canvas3d/canvasswitch/qml/canvasswitch/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/canvasswitch/qml/canvasswitch/main.qml193
-rw-r--r--examples/canvas3d/canvasswitch/qml/canvasswitch/triangle.js111
-rw-r--r--examples/canvas3d/examples.pri10
-rw-r--r--examples/canvas3d/framebuffer/doc/images/framebuffer-example.pngbin0 -> 34175 bytes
-rw-r--r--examples/canvas3d/framebuffer/doc/src/framebuffer.qdoc103
-rw-r--r--examples/canvas3d/framebuffer/framebuffer.pro11
-rw-r--r--examples/canvas3d/framebuffer/framebuffer.qrc8
-rw-r--r--examples/canvas3d/framebuffer/main.cpp65
-rw-r--r--examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js456
-rw-r--r--examples/canvas3d/framebuffer/qml/framebuffer/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/framebuffer/qml/framebuffer/main.qml240
-rw-r--r--examples/canvas3d/framebuffer/qml/framebuffer/qtlogo.pngbin0 -> 13923 bytes
-rw-r--r--examples/canvas3d/interaction/3dmodels.txt19
-rw-r--r--examples/canvas3d/interaction/doc/images/interaction-example.pngbin0 -> 37799 bytes
-rw-r--r--examples/canvas3d/interaction/doc/src/interaction.qdoc90
-rw-r--r--examples/canvas3d/interaction/interaction.pro11
-rw-r--r--examples/canvas3d/interaction/interaction.qrc10
-rw-r--r--examples/canvas3d/interaction/main.cpp65
-rw-r--r--examples/canvas3d/interaction/qml/interaction/ThreeJSLoader.js427
-rw-r--r--examples/canvas3d/interaction/qml/interaction/barrel.jpgbin0 -> 165573 bytes
-rw-r--r--examples/canvas3d/interaction/qml/interaction/barrel.json42
-rw-r--r--examples/canvas3d/interaction/qml/interaction/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/interaction/qml/interaction/interaction.js359
-rw-r--r--examples/canvas3d/interaction/qml/interaction/main.qml161
-rw-r--r--examples/canvas3d/interaction/readme.txt3
-rw-r--r--examples/canvas3d/jsonmodels/3dmodels.txt19
-rw-r--r--examples/canvas3d/jsonmodels/ThreeJSLoader.js427
-rw-r--r--examples/canvas3d/jsonmodels/bush.json47
-rw-r--r--examples/canvas3d/jsonmodels/bush.pngbin0 -> 515919 bytes
-rw-r--r--examples/canvas3d/jsonmodels/deployment.pri27
-rw-r--r--examples/canvas3d/jsonmodels/doc/images/jsonmodels-example.pngbin0 -> 149203 bytes
-rw-r--r--examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc131
-rw-r--r--examples/canvas3d/jsonmodels/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/jsonmodels/gold.jpgbin0 -> 24728 bytes
-rw-r--r--examples/canvas3d/jsonmodels/gold.json47
-rw-r--r--examples/canvas3d/jsonmodels/jsonmodels.js839
-rw-r--r--examples/canvas3d/jsonmodels/jsonmodels.pro16
-rw-r--r--examples/canvas3d/jsonmodels/jsonmodels.qml335
-rw-r--r--examples/canvas3d/jsonmodels/jsonmodelsbasic.qml279
-rw-r--r--examples/canvas3d/jsonmodels/main.cpp18
-rw-r--r--examples/canvas3d/jsonmodels/pallet.jpgbin0 -> 830335 bytes
-rw-r--r--examples/canvas3d/jsonmodels/pallet.json47
-rw-r--r--examples/canvas3d/jsonmodels/qml.qrc19
-rw-r--r--examples/canvas3d/jsonmodels/readme.txt3
-rw-r--r--examples/canvas3d/jsonmodels/rock.jpgbin0 -> 1037186 bytes
-rw-r--r--examples/canvas3d/jsonmodels/rock.json42
-rw-r--r--examples/canvas3d/jsonmodels/woodbox.jpgbin0 -> 32056 bytes
-rw-r--r--examples/canvas3d/jsonmodels/woodbox.json47
-rw-r--r--examples/canvas3d/plasmaeffects/doc/images/plasmaeffects-example.pngbin0 -> 195491 bytes
-rw-r--r--examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc76
-rw-r--r--examples/canvas3d/plasmaeffects/main.cpp65
-rw-r--r--examples/canvas3d/plasmaeffects/plasmaeffects.pro11
-rw-r--r--examples/canvas3d/plasmaeffects/plasmaeffects.qrc8
-rw-r--r--examples/canvas3d/plasmaeffects/qml/plasmaeffects/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml166
-rw-r--r--examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js549
-rw-r--r--examples/canvas3d/plasmaeffects/qml/plasmaeffects/qtlogo_gray.pngbin0 -> 32261 bytes
-rw-r--r--examples/canvas3d/pureqml/cube.js203
-rw-r--r--examples/canvas3d/pureqml/doc/images/pureqml-example.pngbin0 -> 41316 bytes
-rw-r--r--examples/canvas3d/pureqml/doc/src/pureqml.qdoc73
-rw-r--r--examples/canvas3d/pureqml/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/pureqml/pureqml.qml73
-rw-r--r--examples/canvas3d/pureqml/pureqml.qmlproject20
-rw-r--r--examples/canvas3d/textureandlight/doc/images/textureandlight-example.pngbin0 -> 34122 bytes
-rw-r--r--examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc129
-rw-r--r--examples/canvas3d/textureandlight/main.cpp65
-rw-r--r--examples/canvas3d/textureandlight/qml/textureandlight/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/textureandlight/qml/textureandlight/main.qml172
-rw-r--r--examples/canvas3d/textureandlight/qml/textureandlight/qtlogo.pngbin0 -> 14027 bytes
-rw-r--r--examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js390
-rw-r--r--examples/canvas3d/textureandlight/textureandlight.pro11
-rw-r--r--examples/canvas3d/textureandlight/textureandlight.qrc8
-rw-r--r--examples/canvas3d/texturedcube/doc/images/texturedcube-example.pngbin0 -> 24650 bytes
-rw-r--r--examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc92
-rw-r--r--examples/canvas3d/texturedcube/main.cpp65
-rw-r--r--examples/canvas3d/texturedcube/qml/texturedcube/glMatrix-0.9.5.min.js4128
-rw-r--r--examples/canvas3d/texturedcube/qml/texturedcube/main.qml165
-rw-r--r--examples/canvas3d/texturedcube/qml/texturedcube/qtlogo_gray.pngbin0 -> 24733 bytes
-rw-r--r--examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js326
-rw-r--r--examples/canvas3d/texturedcube/texturedcube.pro11
-rw-r--r--examples/canvas3d/texturedcube/texturedcube.qrc8
-rw-r--r--examples/examples.pro2
-rw-r--r--qtcanvas3d.pro6
-rw-r--r--src/abstractobject3d.cpp62
-rw-r--r--src/abstractobject3d_p.h72
-rw-r--r--src/arraybuffer.cpp177
-rw-r--r--src/arraybuffer_p.h96
-rw-r--r--src/arraybufferview.cpp121
-rw-r--r--src/arraybufferview_p.h83
-rw-r--r--src/arrayutils.cpp37
-rw-r--r--src/arrayutils_p.h232
-rw-r--r--src/buffer3d.cpp127
-rw-r--r--src/buffer3d_p.h82
-rw-r--r--src/canvas3d.cpp696
-rw-r--r--src/canvas3d_p.h152
-rw-r--r--src/canvas3dcommon_p.h54
-rw-r--r--src/canvasrendernode.cpp102
-rw-r--r--src/canvasrendernode_p.h81
-rw-r--r--src/context3d.cpp3523
-rw-r--r--src/context3d_p.h1190
-rw-r--r--src/contextattributes.cpp282
-rw-r--r--src/contextattributes_p.h112
-rw-r--r--src/contextextensions.cpp42
-rw-r--r--src/contextextensions_p.h64
-rw-r--r--src/doc/qtcanvas3d.qdocconf55
-rw-r--r--src/doc/snippets/doc_src_qtcanvas3d.cpp4
-rw-r--r--src/doc/snippets/doc_src_qtcanvas3d.pro3
-rw-r--r--src/doc/src/qtcanvas3d-index.qdoc69
-rw-r--r--src/doc/src/qtcanvas3d.qdoc179
-rw-r--r--src/enumtostringmap.cpp426
-rw-r--r--src/enumtostringmap_p.h68
-rw-r--r--src/float32array.cpp259
-rw-r--r--src/float32array_p.h81
-rw-r--r--src/float64array.cpp201
-rw-r--r--src/float64array_p.h79
-rw-r--r--src/framebuffer3d.cpp105
-rw-r--r--src/framebuffer3d_p.h73
-rw-r--r--src/int16array.cpp198
-rw-r--r--src/int16array_p.h79
-rw-r--r--src/int32array.cpp198
-rw-r--r--src/int32array_p.h79
-rw-r--r--src/int8array.cpp197
-rw-r--r--src/int8array_p.h78
-rw-r--r--src/program3d.cpp139
-rw-r--r--src/program3d_p.h82
-rw-r--r--src/qcanvas3d_plugin.cpp148
-rw-r--r--src/qcanvas3d_plugin.h107
-rw-r--r--src/qmldir6
-rw-r--r--src/qtcanvas3d.qmltypes2105
-rw-r--r--src/renderbuffer3d.cpp93
-rw-r--r--src/renderbuffer3d_p.h67
-rw-r--r--src/shader3d.cpp106
-rw-r--r--src/shader3d_p.h73
-rw-r--r--src/shaderprecisionformat.cpp87
-rw-r--r--src/shaderprecisionformat_p.h81
-rw-r--r--src/src.pro117
-rw-r--r--src/teximage3d.cpp369
-rw-r--r--src/teximage3d_p.h128
-rw-r--r--src/teximage3dloader.cpp209
-rw-r--r--src/teximage3dloader_p.h87
-rw-r--r--src/texture3d.cpp120
-rw-r--r--src/texture3d_p.h76
-rw-r--r--src/typedarray.cpp122
-rw-r--r--src/typedarray_p.h82
-rw-r--r--src/typedarrayfactory.cpp589
-rw-r--r--src/typedarrayfactory_p.h137
-rw-r--r--src/uint16array.cpp201
-rw-r--r--src/uint16array_p.h79
-rw-r--r--src/uint32array.cpp194
-rw-r--r--src/uint32array_p.h81
-rw-r--r--src/uint8array.cpp198
-rw-r--r--src/uint8array_p.h79
-rw-r--r--src/uint8clampedarray.cpp197
-rw-r--r--src/uint8clampedarray_p.h79
-rw-r--r--src/uniformlocation.cpp84
-rw-r--r--src/uniformlocation_p.h70
-rw-r--r--sync.profile15
166 files changed, 57070 insertions, 0 deletions
diff --git a/.qmake.conf b/.qmake.conf
new file mode 100644
index 0000000..c3a4524
--- /dev/null
+++ b/.qmake.conf
@@ -0,0 +1,6 @@
+load(qt_build_config)
+CONFIG += qt_example_installs
+
+MODULE_VERSION=0.8.0
+
+CMAKE_MODULE_TESTS=-
diff --git a/examples/canvas3d/canvas3d.pro b/examples/canvas3d/canvas3d.pro
new file mode 100644
index 0000000..887eddf
--- /dev/null
+++ b/examples/canvas3d/canvas3d.pro
@@ -0,0 +1,11 @@
+TEMPLATE = subdirs
+SUBDIRS += canvasswitch \
+ texturedcube \
+ textureandlight \
+ framebuffer \
+ plasmaeffects \
+ interaction \
+ jsonmodels
+OTHER_FILES += pureqml/* \
+ pureqml/doc/src/* \
+ pureqml/doc/images/*
diff --git a/examples/canvas3d/canvasswitch/canvasswitch.pro b/examples/canvas3d/canvasswitch/canvasswitch.pro
new file mode 100644
index 0000000..5f0997c
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/canvasswitch.pro
@@ -0,0 +1,11 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCES += main.cpp
+
+OTHER_FILES += qml/canvasswitch/* \
+ doc/src/* \
+ doc/images/*
+
+RESOURCES += canvasswitch.qrc
diff --git a/examples/canvas3d/canvasswitch/canvasswitch.qrc b/examples/canvas3d/canvasswitch/canvasswitch.qrc
new file mode 100644
index 0000000..468604b
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/canvasswitch.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/canvasswitch/glMatrix-0.9.5.min.js</file>
+ <file>qml/canvasswitch/main.qml</file>
+ <file>qml/canvasswitch/triangle.js</file>
+ <file>qml/canvasswitch/cube.js</file>
+ </qresource>
+</RCC>
diff --git a/examples/canvas3d/canvasswitch/doc/images/canvasswitch-example.png b/examples/canvas3d/canvasswitch/doc/images/canvasswitch-example.png
new file mode 100644
index 0000000..8a5331d
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/doc/images/canvasswitch-example.png
Binary files differ
diff --git a/examples/canvas3d/canvasswitch/doc/src/canvasswitch.qdoc b/examples/canvas3d/canvasswitch/doc/src/canvasswitch.qdoc
new file mode 100644
index 0000000..d26b031
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/doc/src/canvasswitch.qdoc
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example canvasswitch
+ \since QtCanvas3D 1.0
+ \title Canvas Switch Example
+ \ingroup qtcanvas3d-examples
+ \brief Switch between canvases on run-time
+
+ The Canvas Switch example shows how to create a Canvas3D dynamically and how to switch between
+ two canvases on run-time.
+
+ \image canvasswitch-example.png
+
+ \section1 Dynamic Canvas Creation
+
+ First we'll add a function call to the \c{Component.onCompleted} of the main component:
+
+ \snippet canvasswitch/qml/canvasswitch/main.qml 0
+
+ The function handles the initial canvas creation:
+
+ \snippet canvasswitch/qml/canvasswitch/main.qml 1
+
+ In the function we create the Canvas3D dynamically:
+
+ \snippet canvasswitch/qml/canvasswitch/main.qml 2
+
+ We also need to anchor it to the layout we have added inside the function, as we'll call the
+ function again when switching canvases.
+
+ \snippet canvasswitch/qml/canvasswitch/main.qml 3
+
+ \section1 Switching Canvas
+
+ First we import the content for both canvases:
+
+ \snippet canvasswitch/qml/canvasswitch/main.qml 4
+
+ Then, we have a button for switching the content we want to show:
+
+ \snippet canvasswitch/qml/canvasswitch/main.qml 5
+
+ The content switching itself is done by destroying the old canvas and
+ creating a new one in the \c{Button}'s \c{onClicked}:
+
+ \snippet canvasswitch/qml/canvasswitch/main.qml 6
+ */
diff --git a/examples/canvas3d/canvasswitch/main.cpp b/examples/canvas3d/canvasswitch/main.cpp
new file mode 100644
index 0000000..5d5fe0f
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/main.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtCore/QDir>
+#include <QtQuick/QQuickView>
+#include <QtQml/QQmlEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView viewer;
+
+ // The following are needed to make examples run without having to install the module
+ // in desktop environments.
+#ifdef Q_OS_WIN
+ QString extraImportPath(QStringLiteral("%1/../../../../%2"));
+#else
+ QString extraImportPath(QStringLiteral("%1/../../../%2"));
+#endif
+ viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
+ QString::fromLatin1("qml")));
+
+ QObject::connect(viewer.engine(), &QQmlEngine::quit, &viewer, &QWindow::close);
+ viewer.setSource(QUrl("qrc:/qml/canvasswitch/main.qml"));
+
+ viewer.setTitle(QStringLiteral("Canvas Switch"));
+ viewer.setResizeMode(QQuickView::SizeRootObjectToView);
+ viewer.show();
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/canvasswitch/qml/canvasswitch/cube.js b/examples/canvas3d/canvasswitch/qml/canvasswitch/cube.js
new file mode 100644
index 0000000..a738df1
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/qml/canvasswitch/cube.js
@@ -0,0 +1,216 @@
+Qt.include("glMatrix-0.9.5.min.js")
+
+//
+// Draws a cube that has different colors assigned to the vertices.
+// Each face of the cube has the linear interpolation of the corner colors.
+//
+
+var gl;
+var vertexPositionAttrLoc;
+var shaderProgram;
+var cubeVertexPositionBuffer;
+var cubeVertexIndexBuffer;
+var cubeVertexColorBuffer;
+var vertexShader;
+var fragmentShader;
+var vertexColorAttrLoc;
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+var pMatrixUniformLoc;
+var mvMatrixUniformLoc;
+
+var canvas3d;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+function initGL(canvas) {
+ canvas3d = canvas
+ try {
+ // Get the context object that represents the 3D API
+ gl = canvas.getContext("canvas3d", {depth:true});
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.enable(gl.DEPTH_WRITE);
+ gl.depthMask(true);
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+ // Set viewport
+ log("canvas width:"+canvas.width+" height:"+canvas.height+" devicePixelRatio:"+canvas.devicePixelRatio);
+ gl.viewport(0, 0, canvas.width * canvas.devicePixelRatio, canvas.height * canvas.devicePixelRatio);
+
+ // Initialize vertex and color buffers
+ initBuffers();
+
+ // Initialize the shader program
+ initShaders();
+ } catch(e) {
+ console.log("initGL FAILURE!");
+ console.log(""+e);
+ console.log(""+e.message);
+ }
+}
+
+function textureLoadError(textureImage) {
+}
+
+function textureLoaded(textureImage) {
+ log("textureLoaded IGNORED");
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function renderGL(canvas) {
+ log("Render Enter *******")
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ mat4.perspective(pMatrix, degToRad(45), canvas.width / canvas.height, 0.1, 100.0);
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -20.0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotAnim), [0, 1, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotAnim), [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotAnim), [0, 0, 1]);
+
+ gl.useProgram(shaderProgram);
+
+ gl.uniformMatrix4fva(pMatrixUniformLoc, false, pMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniformLoc, false, mvMatrix);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.enableVertexAttribArray(vertexPositionAttrLoc);
+ gl.vertexAttribPointer(vertexPositionAttrLoc, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ gl.enableVertexAttribArray(vertexColorAttrLoc);
+ gl.vertexAttribPointer(vertexColorAttrLoc, 4, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+ log("Render Exit *******")
+}
+
+function initBuffers() {
+ // Create a cubeVertexPositionBuffer and put a single clipspace rectangle in
+ // it (2 triangles)
+ cubeVertexPositionBuffer = gl.createBuffer();
+ cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([ // front
+ -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
+ -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);
+
+ cubeVertexIndexBuffer = gl.createBuffer();
+ cubeVertexIndexBuffer.name = "cubeVertexIndexBuffer";
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ Arrays.newUint16Array([// front
+ 0, 1, 2,
+ 2, 3, 0,
+ // top
+ 3, 2, 6,
+ 6, 7, 3,
+ // back
+ 7, 6, 5,
+ 5, 4, 7,
+ // bottom
+ 4, 5, 1,
+ 1, 0, 4,
+ // left
+ 4, 0, 3,
+ 3, 7, 4,
+ // right
+ 1, 5, 6,
+ 6, 2, 1
+ ]),
+ gl.STATIC_DRAW);
+
+ cubeVertexColorBuffer = gl.createBuffer();
+ cubeVertexColorBuffer.name = "cubeVertexColorBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, Arrays.newFloat32Array([// front
+ 0.000, 1.000, 0.000,
+ 1.000, 0.000, 1.000,
+ 1.000, 1.000, 0.000,
+ 1.000, 0.000, 0.000,
+ // back
+ 0.435, 0.602, 0.223,
+ 0.310, 0.747, 0.185,
+ 1.000, 1.000, 1.000,
+ 0.000, 0.000, 1.000
+ ]), gl.STATIC_DRAW);
+}
+
+function initShaders() {
+ log(" Initializing shaders...");
+
+ vertexShader = getShader(gl, "attribute highp vec3 aVertexPosition; \
+ attribute highp vec4 aVertexColor; \
+ uniform highp mat4 uMVMatrix; \
+ uniform highp mat4 uPMatrix; \
+ varying highp vec4 vColor; \
+ void main(void) { \
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); \
+ vColor = aVertexColor; \
+ }", gl.VERTEX_SHADER);
+ fragmentShader = getShader(gl, "varying highp vec4 vColor; \
+ void main(void) { \
+ gl_FragColor = vColor; \
+ }", gl.FRAGMENT_SHADER);
+
+ shaderProgram = gl.createProgram();
+ shaderProgram.name = "shaderProgram";
+ 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.
+ vertexPositionAttrLoc = gl.getAttribLocation(shaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttrLoc);
+ vertexColorAttrLoc = gl.getAttribLocation(shaderProgram, "aVertexColor");
+ gl.enableVertexAttribArray(vertexColorAttrLoc);
+
+ pMatrixUniformLoc = gl.getUniformLocation(shaderProgram, "uPMatrix");
+ pMatrixUniformLoc.name = "pMatrixUniformLoc";
+ mvMatrixUniformLoc = gl.getUniformLocation(shaderProgram, "uMVMatrix");
+ mvMatrixUniformLoc.name = "mvMatrixUniformLoc";
+ log(" ...done")
+}
+
+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;
+}
diff --git a/examples/canvas3d/canvasswitch/qml/canvasswitch/glMatrix-0.9.5.min.js b/examples/canvas3d/canvasswitch/qml/canvasswitch/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/qml/canvasswitch/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/canvasswitch/qml/canvasswitch/main.qml b/examples/canvas3d/canvasswitch/qml/canvasswitch/main.qml
new file mode 100644
index 0000000..b89a48f
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/qml/canvasswitch/main.qml
@@ -0,0 +1,193 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtCanvas3D 1.0
+import QtQuick.Controls 1.1
+import QtQuick.Layouts 1.1
+
+//! [4]
+import "triangle.js" as GLCodeTriangle
+import "cube.js" as GLCodeCube
+//! [4]
+
+Item {
+ id: mainview
+ width: 1280
+ height: 768
+ visible: true
+
+ property var activeObject: GLCodeTriangle
+ property var canvas3d
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ property double zRotAnim: 0
+
+ //! [0]
+ Component.onCompleted: {
+ createCanvas()
+ }
+ //! [0]
+
+ SequentialAnimation {
+ id: objAnimationX
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: mainview
+ property: "xRotAnim"
+ from: 0.0
+ to: 120.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ target: mainview
+ property: "xRotAnim"
+ from: 120.0
+ to: 0.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationY
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: mainview
+ property: "yRotAnim"
+ from: 0.0
+ to: 240.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ NumberAnimation {
+ target: mainview
+ property: "yRotAnim"
+ from: 240.0
+ to: 0.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationZ
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: mainview
+ property: "zRotAnim"
+ from: -100.0
+ to: 100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: mainview
+ property: "zRotAnim"
+ from: 100.0
+ to: -100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ ColumnLayout {
+ id: layout
+ anchors.fill: parent
+ RowLayout {
+ id: buttonrow
+ anchors.margins: 10
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ //! [5]
+ Button {
+ id: toggleButton
+ text: "Toggle Canvas"
+ property bool firstObject: true
+ //! [5]
+ //! [6]
+ onClicked: {
+ canvas3d.destroy()
+ firstObject = !firstObject
+ if (firstObject)
+ activeObject = GLCodeTriangle
+ else
+ activeObject = GLCodeCube
+ createCanvas()
+ }
+ //! [6]
+ }
+ Button {
+ id: quitButton
+ text: "Quit"
+ onClicked: {
+ canvas3d.destroy()
+ Qt.quit()
+ }
+ }
+ }
+ }
+
+ //! [1]
+ function createCanvas() {
+ //! [2]
+ // Create canvas dynamically to allow changing js objects on the fly
+ canvas3d = Qt.createQmlObject("
+ import QtQuick 2.2
+ import QtCanvas3D 1.0
+ Canvas3D {
+ property double xRotAnim: mainview.xRotAnim
+ property double yRotAnim: mainview.yRotAnim
+ property double zRotAnim: mainview.zRotAnim
+ function initGL() { activeObject.initGL(canvas3d) }
+ function renderGL() { activeObject.renderGL(canvas3d) }
+ }", layout)
+ //! [2]
+ //! [3]
+ canvas3d.anchors.margins = 10
+ canvas3d.anchors.top = layout.top
+ canvas3d.anchors.left = layout.left
+ canvas3d.anchors.right = layout.right
+ canvas3d.anchors.bottom = buttonrow.top
+ //! [3]
+ }
+ //! [1]
+}
diff --git a/examples/canvas3d/canvasswitch/qml/canvasswitch/triangle.js b/examples/canvas3d/canvasswitch/qml/canvasswitch/triangle.js
new file mode 100644
index 0000000..08052ab
--- /dev/null
+++ b/examples/canvas3d/canvasswitch/qml/canvasswitch/triangle.js
@@ -0,0 +1,111 @@
+Qt.include("glMatrix-0.9.5.min.js")
+
+//
+// Draws a single blue triangle on black background in clipspace.
+//
+
+var gl;
+var positionLocation;
+var shaderProgram;
+var buffer;
+var vertexShader;
+var fragmentShader;
+
+var canvas3d;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+function initGL(canvas) {
+ canvas3d = canvas
+ log("initGL("+canvas+") BEGIN");
+ try {
+ gl = canvas.getContext("3d");
+
+ // Create a buffer and put a single clipspace rectangle in
+ // it (2 triangles)
+ buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER, Arrays.newFloat32Array(
+ [-1.0, -1.0,
+ 1.0, -1.0,
+ -1.0, 1.0
+ ]),
+ gl.STATIC_DRAW);
+
+
+ if (!initShaders()) {
+ console.log("initGL(): FAILURE!");
+ return;
+ }
+
+ gl.useProgram(shaderProgram);
+
+ // look up where the vertex data needs to go.
+ positionLocation = gl.getAttribLocation(shaderProgram, "a_position");
+ gl.enableVertexAttribArray(positionLocation);
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
+
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+
+ gl.viewport(0, 0, canvas.width * canvas.devicePixelRatio, canvas.height * canvas.devicePixelRatio);
+ } catch(e) {
+ console.log("initGL(): FAILURE!");
+ console.log(""+e);
+ console.log(""+e.message);
+ }
+ log("initGL("+canvas+") END");
+}
+
+function renderGL(canvas) {
+ log("renderGL("+canvas+") BEGIN");
+ // Clear background
+ gl.clear(gl.COLOR_BUFFER_BIT);
+
+ // Draw single green triangle
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
+ log("renderGL("+canvas+") END");
+}
+
+function initShaders()
+{
+ // setup a GLSL program
+ vertexShader = compileShader("attribute vec2 a_position; \
+ void main() { \
+ gl_Position = vec4(a_position, 0.0, 1.0); \
+ }", gl.VERTEX_SHADER);
+ fragmentShader = compileShader("void main() { \
+ gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); \
+ }", gl.FRAGMENT_SHADER);
+
+ shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.linkProgram(shaderProgram);
+
+ // Check linking status
+ if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialise shaders");
+ console.log(gl.getProgramInfoLog(shaderProgram));
+ return false;
+ }
+
+ return true;
+}
+
+function compileShader(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;
+}
diff --git a/examples/canvas3d/examples.pri b/examples/canvas3d/examples.pri
new file mode 100644
index 0000000..0d61739
--- /dev/null
+++ b/examples/canvas3d/examples.pri
@@ -0,0 +1,10 @@
+INCLUDEPATH += ../../../include
+
+LIBS += -L$$OUT_PWD/../../../lib
+
+TEMPLATE = app
+
+QT += qml quick
+
+target.path = $$[QT_INSTALL_EXAMPLES]/canvas3d/$$TARGET
+INSTALLS += target
diff --git a/examples/canvas3d/framebuffer/doc/images/framebuffer-example.png b/examples/canvas3d/framebuffer/doc/images/framebuffer-example.png
new file mode 100644
index 0000000..4a4ca67
--- /dev/null
+++ b/examples/canvas3d/framebuffer/doc/images/framebuffer-example.png
Binary files differ
diff --git a/examples/canvas3d/framebuffer/doc/src/framebuffer.qdoc b/examples/canvas3d/framebuffer/doc/src/framebuffer.qdoc
new file mode 100644
index 0000000..51f7603
--- /dev/null
+++ b/examples/canvas3d/framebuffer/doc/src/framebuffer.qdoc
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example framebuffer
+ \since QtCanvas3D 1.0
+ \title Framebuffer Example
+ \ingroup qtcanvas3d-examples
+ \brief Render into a framebuffer and use it as a texture
+
+ The Framebuffer Example shows how to render into a framebuffer, create a texture of it, and
+ apply the texture to an object in normal on-screen rendering.
+
+ The example has a moving and rotating cube, which has another textured cube drawn into it via
+ the framebuffer object. The cube in the frambuffer can be rotated using the Qt Quick sliders.
+
+ \image framebuffer-example.png
+
+ \section1 Preparing the Framebuffer
+
+ We'll first define the variables we need for the render-to-texture framebuffer:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 0
+
+ Then, in the \c initGL function, we create the framebuffer object:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 1
+
+ \section1 Creating the Texture
+
+ After the creation of the framebuffer, we create the texture:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 2
+
+ Then we'll need to bind the texture as a color attachment, create and bind a render buffer, and
+ bind the depth attachment:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 3
+
+ \section1 Rendering into the Framebuffer
+
+ In \c renderGL function, we'll first need to draw the scene into the framebuffer. We'll start
+ by binding the framebuffer object and setting a viewport:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 4
+
+ Then, we'll need to bind the loaded texture we want to use in rendering into the framebuffer
+ object:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 5
+
+ And then we can draw the textured cube into the framebuffer:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 6
+
+ \section1 Using the Framebuffer as a Texture
+
+ First we'll bind the render-to-texture right after drawing, and generate mipmaps:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 7
+
+ Then we need to bind the default framebuffer (= screen), and set up viewport:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 8
+
+ And finally draw the on-screen view:
+
+ \snippet framebuffer/qml/framebuffer/framebuffer.js 9
+
+ */
diff --git a/examples/canvas3d/framebuffer/framebuffer.pro b/examples/canvas3d/framebuffer/framebuffer.pro
new file mode 100644
index 0000000..71adfce
--- /dev/null
+++ b/examples/canvas3d/framebuffer/framebuffer.pro
@@ -0,0 +1,11 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCES += main.cpp
+
+OTHER_FILES += qml/framebuffer/* \
+ doc/src/* \
+ doc/images/*
+
+RESOURCES += framebuffer.qrc
diff --git a/examples/canvas3d/framebuffer/framebuffer.qrc b/examples/canvas3d/framebuffer/framebuffer.qrc
new file mode 100644
index 0000000..5142cba
--- /dev/null
+++ b/examples/canvas3d/framebuffer/framebuffer.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/framebuffer/glMatrix-0.9.5.min.js</file>
+ <file>qml/framebuffer/main.qml</file>
+ <file>qml/framebuffer/qtlogo.png</file>
+ <file>qml/framebuffer/framebuffer.js</file>
+ </qresource>
+</RCC>
diff --git a/examples/canvas3d/framebuffer/main.cpp b/examples/canvas3d/framebuffer/main.cpp
new file mode 100644
index 0000000..20e988e
--- /dev/null
+++ b/examples/canvas3d/framebuffer/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtCore/QDir>
+#include <QtQuick/QQuickView>
+#include <QtQml/QQmlEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView viewer;
+
+ // The following are needed to make examples run without having to install the module
+ // in desktop environments.
+#ifdef Q_OS_WIN
+ QString extraImportPath(QStringLiteral("%1/../../../../%2"));
+#else
+ QString extraImportPath(QStringLiteral("%1/../../../%2"));
+#endif
+ viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
+ QString::fromLatin1("qml")));
+
+ viewer.setSource(QUrl("qrc:/qml/framebuffer/main.qml"));
+
+ viewer.setTitle(QStringLiteral("Render into FrameBuffer"));
+ viewer.setResizeMode(QQuickView::SizeRootObjectToView);
+ viewer.show();
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js b/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js
new file mode 100644
index 0000000..b58b34f
--- /dev/null
+++ b/examples/canvas3d/framebuffer/qml/framebuffer/framebuffer.js
@@ -0,0 +1,456 @@
+Qt.include("glMatrix-0.9.5.min.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;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+function initGL(canvas, textureLoader) {
+ canvas3d = canvas
+ try {
+ // Get the OpenGL context object that represents the API we call
+ gl = canvas.getContext("canvas3d", {depth:true, antialias:true});
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+ gl.enable(gl.DEPTH_WRITE);
+ gl.depthMask(true);
+
+ // Initialize the shader program
+ initShaders();
+
+ // Initialize vertex and color buffers
+ initBuffers();
+
+ // Load the texture
+ textureLoader.loadTexture("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.generateMipmap(gl.TEXTURE_2D);
+ gl.texImage2D(gl.TEXTURE_2D, 0,
+ gl.RGBA, rttWidth, rttHeight,
+ 0, gl.RGBA, gl.UNSIGNED_BYTE,
+ null);
+ //! [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("initGL FAILURE!");
+ console.log(""+e);
+ console.log(""+e.message);
+ }
+}
+
+function textureLoaded(textureImage) {
+ if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture == 0) {
+ log(" processing "+textureImage.source);
+ 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
+ textureImage); // 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);
+ }
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function renderGL(canvas) {
+ //! [4]
+ // bind the FBO and setup viewport
+ gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
+ gl.viewport(0, 0, rttWidth, rttHeight);
+ //! [4]
+
+ gl.clearColor(0.0, 0.0, 1.0, 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.uniformMatrix4fva(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.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ mat4.invert(nMatrix, mvMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(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.0, 0.0, 0.0, 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.uniformMatrix4fva(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.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ mat4.invert(nMatrix, mvMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nUniform, false, nMatrix);
+
+ //! [9]
+ // Draw the on-screen cube
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+ //! [9]
+}
+
+function initBuffers()
+{
+ log(" cubeVertexPositionBuffer");
+ var cubeVertexPositionBuffer = gl.createBuffer();
+ cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([// 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,
+ Arrays.newUint16Array([
+ 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);
+
+ var colors = [
+ [0.0, 1.0, 1.0, 1.0], // Front face: white
+ [1.0, 0.0, 0.0, 1.0], // Back face: red
+ [0.0, 1.0, 0.0, 1.0], // Top face: green
+ [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
+ [1.0, 1.0, 0.0, 1.0], // Right face: yellow
+ [1.0, 0.0, 1.0, 1.0] // Left face: purple
+ ];
+
+ var generatedColors = [];
+ for (var j = 0; j < 6; j++) {
+ var c = colors[j];
+
+ for (var i = 0; i < 4; i++) {
+ generatedColors = generatedColors.concat(c);
+ }
+ }
+ log(" cubeVertexColorBuffer");
+ var cubeVertexColorBuffer = gl.createBuffer();
+ cubeVertexColorBuffer.name = "cubeVertexColorBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, Arrays.newFloat32Array(generatedColors), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(vertexColorAttribute);
+ gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ 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, Arrays.newFloat32Array(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, Arrays.newFloat32Array([
+ // 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 mediump vec4 aVertexColor;
+ 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);
+ vColor = aVertexColor;
+ 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 mediump vec4 vColor;
+ varying highp vec2 vTextureCoord;
+ varying highp vec3 vLighting;
+
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ mediump vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ mediump vec3 blendColor = mix(vColor.rgb, texelColor.rgb, texelColor.a);
+ gl_FragColor = vec4(blendColor * 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);
+ vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
+ gl.enableVertexAttribArray(vertexColorAttribute);
+ 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;
+}
diff --git a/examples/canvas3d/framebuffer/qml/framebuffer/glMatrix-0.9.5.min.js b/examples/canvas3d/framebuffer/qml/framebuffer/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/framebuffer/qml/framebuffer/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/framebuffer/qml/framebuffer/main.qml b/examples/canvas3d/framebuffer/qml/framebuffer/main.qml
new file mode 100644
index 0000000..d0b4a39
--- /dev/null
+++ b/examples/canvas3d/framebuffer/qml/framebuffer/main.qml
@@ -0,0 +1,240 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtCanvas3D 1.0
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+
+import "framebuffer.js" as GLCode
+
+Item {
+ id: mainview
+ width: 1280
+ height: 768
+ visible: true
+
+ Canvas3D {
+ id: canvas3d
+ anchors.fill: parent
+ imageLoader: textureImageLoader
+ property double xRotSlider: 0
+ property double yRotSlider: 0
+ property double zRotSlider: 0
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ property double zRotAnim: 0
+ property bool isRunning: true
+
+ // Called by Canvas 3D once on Scene Graph render thread
+ // to allow one time initializations to happen
+ function initGL() {
+ GLCode.initGL(canvas3d, textureImageLoader);
+ }
+
+ // Called by Canvas 3D for every frame
+ // rendered on Scene Graph render thread
+ function renderGL() {
+ GLCode.renderGL(canvas3d);
+ }
+
+ Keys.onSpacePressed: {
+ canvas3d.isRunning = !canvas3d.isRunning
+ if (canvas3d.isRunning) {
+ objAnimationX.pause();
+ objAnimationY.pause();
+ objAnimationZ.pause();
+ } else {
+ objAnimationX.resume();
+ objAnimationY.resume();
+ objAnimationZ.resume();
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationX
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 0.0
+ to: 120.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 120.0
+ to: 0.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationY
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 0.0
+ to: 240.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 240.0
+ to: 0.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationZ
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: -100.0
+ to: 100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: 100.0
+ to: -100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ }
+ }
+
+ RowLayout {
+ id: controlLayout
+ spacing: 5
+ x: 0
+ y: parent.height-100
+ width: parent.width
+ height: 100
+ visible: true
+
+ Label {
+ id: xRotLabel
+ Layout.alignment: Qt.AlignRight
+ Layout.fillWidth: false
+ text: "X-axis:"
+ color: "#FFFFFF"
+ }
+
+ Slider {
+ id: xSlider
+ Layout.alignment: Qt.AlignLeft
+ Layout.preferredWidth : 300
+ Layout.fillWidth: true
+ minimumValue: 0;
+ maximumValue: 360;
+ onValueChanged: canvas3d.xRotSlider = value;
+ }
+
+ Label {
+ id: yRotLabel
+ Layout.alignment: Qt.AlignRight
+ Layout.fillWidth: false
+ text: "Y-axis:"
+ color: "#FFFFFF"
+ }
+
+ Slider {
+ id: ySlider
+ Layout.alignment: Qt.AlignLeft
+ Layout.preferredWidth : 300
+ Layout.fillWidth: true
+ minimumValue: 0;
+ maximumValue: 360;
+ onValueChanged: canvas3d.yRotSlider = value;
+ }
+
+ Label {
+ id: zRotLabel
+ Layout.alignment: Qt.AlignRight
+ Layout.fillWidth: false
+ text: "Z-axis:"
+ color: "#FFFFFF"
+ }
+
+ Slider {
+ id: zSlider
+ Layout.alignment: Qt.AlignLeft
+ Layout.preferredWidth : 300
+ Layout.fillWidth: true
+ minimumValue: 0;
+ maximumValue: 360;
+ onValueChanged: canvas3d.zRotSlider = value;
+ }
+ }
+
+ TextureImageLoader {
+ id: textureImageLoader
+
+ function loadTexture(file) {
+ if (canvas3d.logAllCalls)
+ console.log("TextureImageLoader.loadTexture(qrc:/qml/framebuffer/"+file+")")
+ return textureImageLoader.loadImage("qrc:/qml/framebuffer/"+file);
+ }
+
+ function imageLoaded(textureImage) {
+ if (canvas3d.logAllCalls)
+ console.log("Texture loaded, size "+textureImage.width+"x"+textureImage.height);
+ GLCode.textureLoaded(textureImage);
+ }
+
+ function imageLoadingError(textureImage) {
+ if (GLCode.textureLoadError !== undefined) {
+ GLCode.textureLoadError(textureImage);
+ }
+ console.log("Texture load FAILED, "+textureImage.errorString);
+ }
+ }
+}
diff --git a/examples/canvas3d/framebuffer/qml/framebuffer/qtlogo.png b/examples/canvas3d/framebuffer/qml/framebuffer/qtlogo.png
new file mode 100644
index 0000000..7d3e97e
--- /dev/null
+++ b/examples/canvas3d/framebuffer/qml/framebuffer/qtlogo.png
Binary files differ
diff --git a/examples/canvas3d/interaction/3dmodels.txt b/examples/canvas3d/interaction/3dmodels.txt
new file mode 100644
index 0000000..3aea437
--- /dev/null
+++ b/examples/canvas3d/interaction/3dmodels.txt
@@ -0,0 +1,19 @@
+Provided by Nobiax.
+
+ CC0 1.0 Universal (CC0 1.0)
+ Public Domain Dedication
+ No Copyright
+ This license is acceptable for Free Cultural Works
+
+ The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
+
+ You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission.
+
+So absolutely free to use or to modify in any kind of work (personal, commercial or else) =)
+
+Please (no obligation), send me a link of the result at nobiax.deviantart.com or my other account on OpenGameArt.com (yughues) or ShareCG.com (yughues)
+( watch my journal on deviantart to find them ) ;)
+
+Or on Youtube.
+
+For any commissions details are on my DeviantArt account. \ No newline at end of file
diff --git a/examples/canvas3d/interaction/doc/images/interaction-example.png b/examples/canvas3d/interaction/doc/images/interaction-example.png
new file mode 100644
index 0000000..a72efc8
--- /dev/null
+++ b/examples/canvas3d/interaction/doc/images/interaction-example.png
Binary files differ
diff --git a/examples/canvas3d/interaction/doc/src/interaction.qdoc b/examples/canvas3d/interaction/doc/src/interaction.qdoc
new file mode 100644
index 0000000..ea0dc5b
--- /dev/null
+++ b/examples/canvas3d/interaction/doc/src/interaction.qdoc
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example interaction
+ \since QtCanvas3D 1.0
+ \title Interaction Example
+ \ingroup qtcanvas3d-examples
+ \brief Interact with an object in canvas using Qt Quick Controls
+
+ The Interaction Example concentrates on the interaction between Qt Quick Controls and the objects
+ displayed in Canvas3D. The other thing this example demonstrates is drawing the same object
+ in three different ways.
+
+ \image interaction-example.png
+
+ \section1 The Controls
+
+ First, we'll need to import Qt Quick Controls and Layouts:
+
+ \snippet interaction/qml/interaction/main.qml 0
+
+ Then, we'll add a \c RowLayout to the main component to easily add the controls side-by-side:
+
+ \snippet interaction/qml/interaction/main.qml 1
+
+ And then we'll add three sliders to the layout. Here's the one for controlling x axis rotation:
+
+ \snippet interaction/qml/interaction/main.qml 2
+
+ \section1 Interaction
+
+ First we need to define some properties in the Canvas3D for the rotations:
+
+ \snippet interaction/qml/interaction/main.qml 3
+
+ The \c onValueChanged functions in the \c{Slider}s are connected to the properties in Canvas3D.
+ Here's the connection in x rotation slider as an example:
+
+ \snippet interaction/qml/interaction/main.qml 4
+
+ Then, on the JavaScript side, we just use the Canvas3D properties directly as the values when
+ setting the modelview matrix rotations:
+
+ \snippet interaction/qml/interaction/interaction.js 0
+
+ \section1 Drawing in 3 ways
+
+ The actual drawing is done in the same way as everywhere else we are drawing the same object
+ multiple times, only in this case we use different drawing mode for each:
+
+ \snippet interaction/qml/interaction/interaction.js 1
+ \dots 0
+ \snippet interaction/qml/interaction/interaction.js 2
+ \dots 0
+ \snippet interaction/qml/interaction/interaction.js 3
+ */
diff --git a/examples/canvas3d/interaction/interaction.pro b/examples/canvas3d/interaction/interaction.pro
new file mode 100644
index 0000000..fb399b9
--- /dev/null
+++ b/examples/canvas3d/interaction/interaction.pro
@@ -0,0 +1,11 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCES += main.cpp
+
+OTHER_FILES += qml/interaction/* \
+ doc/src/* \
+ doc/images/*
+
+RESOURCES += interaction.qrc
diff --git a/examples/canvas3d/interaction/interaction.qrc b/examples/canvas3d/interaction/interaction.qrc
new file mode 100644
index 0000000..696aa06
--- /dev/null
+++ b/examples/canvas3d/interaction/interaction.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/interaction/barrel.jpg</file>
+ <file>qml/interaction/barrel.json</file>
+ <file>qml/interaction/glMatrix-0.9.5.min.js</file>
+ <file>qml/interaction/interaction.js</file>
+ <file>qml/interaction/main.qml</file>
+ <file>qml/interaction/ThreeJSLoader.js</file>
+ </qresource>
+</RCC>
diff --git a/examples/canvas3d/interaction/main.cpp b/examples/canvas3d/interaction/main.cpp
new file mode 100644
index 0000000..1a267bc
--- /dev/null
+++ b/examples/canvas3d/interaction/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtCore/QDir>
+#include <QtQuick/QQuickView>
+#include <QtQml/QQmlEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView viewer;
+
+ // The following are needed to make examples run without having to install the module
+ // in desktop environments.
+#ifdef Q_OS_WIN
+ QString extraImportPath(QStringLiteral("%1/../../../../%2"));
+#else
+ QString extraImportPath(QStringLiteral("%1/../../../%2"));
+#endif
+ viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
+ QString::fromLatin1("qml")));
+
+ viewer.setSource(QUrl("qrc:/qml/interaction/main.qml"));
+
+ viewer.setTitle(QStringLiteral("Interaction"));
+ viewer.setResizeMode(QQuickView::SizeRootObjectToView);
+ viewer.show();
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/interaction/qml/interaction/ThreeJSLoader.js b/examples/canvas3d/interaction/qml/interaction/ThreeJSLoader.js
new file mode 100644
index 0000000..d4f0d73
--- /dev/null
+++ b/examples/canvas3d/interaction/qml/interaction/ThreeJSLoader.js
@@ -0,0 +1,427 @@
+function GLModel() {
+ this.vertices = [];
+ this.normals = [];
+ this.texCoords = [];
+ this.indices = [];
+}
+
+function Geometry() {
+ this.vertices = [];
+ this.faceVertexUvs = [];
+ this.faces = [];
+}
+
+function Face3( a, b, c, normal, color, materialIndex ) {
+
+ this.a = a;
+ this.b = b;
+ this.c = c;
+
+ this.normal = normal instanceof Vector3 ? normal : new Vector3();
+ this.vertexNormals = normal instanceof Array ? normal : [ ];
+
+ this.color = color instanceof Array ? color : [ ];
+ this.vertexColors = color instanceof Array ? color : [];
+
+ this.vertexTangents = [];
+
+ this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
+
+ this.centroid = new Vector3()
+};
+
+function Vector2( x, y) {
+ this.x = x || 0;
+ this.y = y || 0;
+};
+
+function Vector3( x, y, z ) {
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+};
+
+Vector3.prototype = {
+
+ constructor: Vector3,
+
+ set: function ( x, y, z ) {
+
+ this.x = x;
+ this.y = y;
+ this.z = z;
+
+ return this;
+ },
+
+ copy: function ( v ) {
+
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+
+ return this;
+
+ }
+};
+
+Face3.prototype = {
+
+ constructor: Face3,
+
+ clone: function () {
+
+ var face = new Face3( this.a, this.b, this.c );
+
+ face.normal.copy( this.normal );
+ face.color.copy( this.color );
+ face.centroid.copy( this.centroid );
+
+ face.materialIndex = this.materialIndex;
+
+ var i, il;
+ for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
+ for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
+ for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
+
+ return face;
+ }
+};
+
+function parseJSON3DModel( json, texturePath )
+{
+ var formatVersion = json.metadata.formatVersion;
+
+ if (formatVersion < 4.0 ) {
+ var i, j;
+ var geometry = new Geometry();
+ var scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
+ parseModel( json, geometry, scale );
+
+ // Translate to model we can use from GL
+ var glModel = new GLModel();
+
+ for (i = 0; i < geometry.vertices.length; i++) {
+ glModel.vertices.push(geometry.vertices[i].x);
+ glModel.vertices.push(geometry.vertices[i].y);
+ glModel.vertices.push(geometry.vertices[i].z);
+ }
+
+ glModel.texCoords[0] = [];
+ for (var faceIdx = 0; faceIdx < geometry.faces.length; faceIdx++) {
+ var face = geometry.faces[faceIdx];
+ // Array indices
+ glModel.indices.push(face.a);
+ glModel.indices.push(face.b);
+ glModel.indices.push(face.c);
+
+ // Materials
+ // face.materialIndex
+
+ // Only parse first layer of UVs for this face
+ for(var uvLayer = 0; uvLayer < geometry.faceVertexUvs.length; uvLayer++) {
+ var faceUVs = geometry.faceVertexUvs[uvLayer][faceIdx];
+ var idxUVA = face.a * 2;
+ var idxUVB = face.b * 2;
+ var idxUVC = face.c * 2;
+
+ glModel.texCoords[uvLayer][idxUVA++] = faceUVs[0].x;
+ glModel.texCoords[uvLayer][idxUVA ] = faceUVs[0].y;
+ glModel.texCoords[uvLayer][idxUVB++] = faceUVs[1].x;
+ glModel.texCoords[uvLayer][idxUVB ] = faceUVs[1].y;
+ glModel.texCoords[uvLayer][idxUVC++] = faceUVs[2].x;
+ glModel.texCoords[uvLayer][idxUVC ] = faceUVs[2].y;
+ }
+
+ // Normal
+ if (face.vertexNormals !== undefined) {
+ // Per vertex normals
+ var idxA = face.a * 3;
+ var idxB = face.b * 3;
+ var idxC = face.c * 3;
+ var vrtNormals = face.vertexNormals;
+
+ glModel.normals[idxA++] = vrtNormals[0].x;
+ glModel.normals[idxA++] = vrtNormals[0].y;
+ glModel.normals[idxA ] = vrtNormals[0].z;
+
+ glModel.normals[idxB++] = vrtNormals[1].x;
+ glModel.normals[idxB++] = vrtNormals[1].y;
+ glModel.normals[idxB ] = vrtNormals[1].z;
+
+ glModel.normals[idxC++] = vrtNormals[2].x;
+ glModel.normals[idxC++] = vrtNormals[2].y;
+ glModel.normals[idxC ] = vrtNormals[2].z;
+ } else if (face.normal !== undefined) {
+ // Per face normal
+ glModel.normals[idxA++] = face.normal.x;
+ glModel.normals[idxA++] = face.normal.y;
+ glModel.normals[idxA ] = face.normal.z;
+
+ glModel.normals[idxB++] = face.normal.x;
+ glModel.normals[idxB++] = face.normal.y;
+ glModel.normals[idxB ] = face.normal.z;
+
+ glModel.normals[idxC++] = face.normal.x;
+ glModel.normals[idxC++] = face.normal.y;
+ glModel.normals[idxC ] = face.normal.z;
+ }
+ }
+ }
+
+ return glModel;
+};
+
+function parseModel( json, geometry, scale ) {
+
+ function isBitSet( value, position )
+ {
+ return value & ( 1 << position );
+ }
+
+ var i, j, fi,
+
+ offset, zLength,
+
+ colorIndex, normalIndex, uvIndex, materialIndex,
+
+ type,
+ isQuad,
+ hasMaterial,
+ hasFaceVertexUv,
+ hasFaceNormal, hasFaceVertexNormal,
+ hasFaceColor, hasFaceVertexColor,
+
+ vertex, face, faceA, faceB, color, hex, normal,
+
+ uvLayer, uv, u, v,
+
+ faces = json.faces,
+ vertices = json.vertices,
+ normals = json.normals,
+ colors = json.colors,
+
+ nUvLayers = 0;
+
+ if ( json.uvs !== undefined ) {
+ // disregard empty arrays
+ for ( i = 0; i < json.uvs.length; i++ ) {
+ if ( json.uvs[ i ].length > 0 ) nUvLayers ++;
+ }
+
+ for ( i = 0; i < nUvLayers; i++ ) {
+ geometry.faceVertexUvs[ i ] = [];
+ }
+ }
+
+ offset = 0;
+ zLength = vertices.length;
+
+ while ( offset < zLength ) {
+ vertex = new Vector3();
+
+ vertex.x = vertices[ offset ++ ] * scale;
+ vertex.y = vertices[ offset ++ ] * scale;
+ vertex.z = vertices[ offset ++ ] * scale;
+
+ geometry.vertices.push( vertex );
+ }
+
+ offset = 0;
+ zLength = faces.length;
+
+ while ( offset < zLength ) {
+ type = faces[ offset ++ ];
+
+ isQuad = isBitSet( type, 0 );
+ hasMaterial = isBitSet( type, 1 );
+ hasFaceVertexUv = isBitSet( type, 3 );
+ hasFaceNormal = isBitSet( type, 4 );
+ hasFaceVertexNormal = isBitSet( type, 5 );
+ hasFaceColor = isBitSet( type, 6 );
+ hasFaceVertexColor = isBitSet( type, 7 );
+
+ // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
+
+ if ( isQuad ) {
+ faceA = new Face3();
+ faceA.a = faces[ offset ];
+ faceA.b = faces[ offset + 1 ];
+ faceA.c = faces[ offset + 3 ];
+
+ faceB = new Face3();
+ faceB.a = faces[ offset + 1 ];
+ faceB.b = faces[ offset + 2 ];
+ faceB.c = faces[ offset + 3 ];
+
+ offset += 4;
+
+ if ( hasMaterial ) {
+ materialIndex = faces[ offset ++ ];
+ faceA.materialIndex = materialIndex;
+ faceB.materialIndex = materialIndex;
+ }
+
+ // to get face <=> uv index correspondence
+ fi = geometry.faces.length;
+
+ if ( hasFaceVertexUv ) {
+ for ( i = 0; i < nUvLayers; i++ ) {
+ uvLayer = json.uvs[ i ];
+ geometry.faceVertexUvs[ i ][ fi ] = [];
+ geometry.faceVertexUvs[ i ][ fi + 1 ] = []
+
+ for ( j = 0; j < 4; j ++ ) {
+ uvIndex = faces[ offset ++ ];
+
+ u = uvLayer[ uvIndex * 2 ];
+ v = uvLayer[ uvIndex * 2 + 1 ];
+
+ uv = new Vector2( u, v );
+
+ if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
+ if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
+ }
+ }
+ }
+
+ if ( hasFaceNormal ) {
+ normalIndex = faces[ offset ++ ] * 3;
+ faceA.normal.set(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+ faceB.normal.copy( faceA.normal );
+ }
+
+ if ( hasFaceVertexNormal ) {
+ for ( i = 0; i < 4; i++ ) {
+ normalIndex = faces[ offset ++ ] * 3;
+ normal = new Vector3(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+
+ if ( i !== 2 ) faceA.vertexNormals.push( normal );
+ if ( i !== 0 ) faceB.vertexNormals.push( normal );
+ }
+ }
+
+ if ( hasFaceColor ) {
+ colorIndex = faces[ offset ++ ];
+ hex = colors[ colorIndex ];
+ // faceA.color.setHex( hex );
+ // faceB.color.setHex( hex );
+ }
+
+ if ( hasFaceVertexColor ) {
+ for ( i = 0; i < 4; i++ ) {
+ colorIndex = faces[ offset ++ ];
+ hex = colors[ colorIndex ];
+
+ // if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) );
+ // if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) );
+ }
+ }
+
+ geometry.faces.push( faceA );
+ geometry.faces.push( faceB );
+
+ } else {
+ face = new Face3();
+ face.a = faces[ offset ++ ];
+ face.b = faces[ offset ++ ];
+ face.c = faces[ offset ++ ];
+
+ if ( hasMaterial ) {
+ materialIndex = faces[ offset ++ ];
+ face.materialIndex = materialIndex;
+ }
+
+ // to get face <=> uv index correspondence
+
+ fi = geometry.faces.length;
+
+ if ( hasFaceVertexUv ) {
+
+ for ( i = 0; i < nUvLayers; i++ ) {
+
+ uvLayer = json.uvs[ i ];
+
+ geometry.faceVertexUvs[ i ][ fi ] = [];
+
+ for ( j = 0; j < 3; j ++ ) {
+
+ uvIndex = faces[ offset ++ ];
+
+ u = uvLayer[ uvIndex * 2 ];
+ v = uvLayer[ uvIndex * 2 + 1 ];
+
+ uv = new Vector2( u, v );
+
+ geometry.faceVertexUvs[ i ][ fi ].push( uv );
+
+ }
+
+ }
+
+ }
+
+ if ( hasFaceNormal ) {
+
+ normalIndex = faces[ offset ++ ] * 3;
+
+ face.normal.set(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+
+ }
+
+ if ( hasFaceVertexNormal ) {
+
+ for ( i = 0; i < 3; i++ ) {
+
+ normalIndex = faces[ offset ++ ] * 3;
+
+ normal = new Vector3(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+
+ face.vertexNormals.push( normal );
+
+ }
+
+ }
+
+
+ if ( hasFaceColor ) {
+ // colorIndex = faces[ offset ];
+ offset++;
+ // face.color.setHex( colors[ colorIndex ] );
+ }
+
+
+ if ( hasFaceVertexColor ) {
+
+ for ( i = 0; i < 3; i++ ) {
+
+ // colorIndex = faces[offset];
+ offset++;
+ // face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );
+
+ }
+
+ }
+
+ geometry.faces.push( face );
+
+ }
+
+ }
+};
diff --git a/examples/canvas3d/interaction/qml/interaction/barrel.jpg b/examples/canvas3d/interaction/qml/interaction/barrel.jpg
new file mode 100644
index 0000000..cfc3bcb
--- /dev/null
+++ b/examples/canvas3d/interaction/qml/interaction/barrel.jpg
Binary files differ
diff --git a/examples/canvas3d/interaction/qml/interaction/barrel.json b/examples/canvas3d/interaction/qml/interaction/barrel.json
new file mode 100644
index 0000000..953b733
--- /dev/null
+++ b/examples/canvas3d/interaction/qml/interaction/barrel.json
@@ -0,0 +1,42 @@
+{
+
+"metadata" :
+{
+"formatVersion" : 3.1,
+"generatedBy" : "Blender 2.7 Exporter",
+"vertices" : 1097,
+"faces" : 1061,
+"normals" : 904,
+"colors" : 0,
+"uvs" : [1283],
+"materials" : 0,
+"morphTargets" : 0,
+"bones" : 0
+},
+
+"scale" : 0.100000,
+
+"materials" : [],
+
+"vertices" : [3.18589,0.2,0.85366,0,0.20018,0.85429,0,0.20018,2.38633e-08,3.29827,0.2,2.38419e-08,0,10.1998,1.21591e-06,-3.29827,10.2,1.21593e-06,-3.18589,10.2,0.853661,0,10.1998,0.854291,-3.18589,10.2,-0.853659,0,10.1998,-0.854289,-2.85639,10.2,1.64914,0,10.1998,1.65036,-2.33223,10.2,2.33223,0,10.1998,2.33396,-1.64914,10.2,2.85639,0,10.1998,2.85851,-0.85366,10.2,3.18589,0,10.2,3.29827,-2.85639,10.2,-1.64914,0,10.1998,-1.65036,-2.33223,10.2,-2.33223,0,10.1998,-2.33396,-1.64914,10.2,-2.85639,0,10.1998,-2.85851,-0.85366,10.2,-3.18589,0,10.2,-3.29827,0.85366,10.2,3.18589,1.64913,10.2,2.85639,2.33223,10.2,2.33223,2.85639,10.2,1.64914,3.18589,10.2,0.853661,3.29827,10.2,1.21593e-06,3.18589,10.2,-0.853659,2.85639,10.2,-1.64914,2.33223,10.2,-2.33223,1.64914,10.2,-2.85639,0.85366,10.2,-3.18589,3.18589,0.2,-0.85366,0,0.20018,-0.85429,2.85639,0.2,1.64914,0,0.20018,1.65036,2.33223,0.2,2.33223,0,0.20018,2.33396,1.64913,0.2,2.85639,0,0.20018,2.85851,0.85366,0.2,3.18589,0,0.2,3.29827,2.85639,0.2,-1.64914,0,0.20018,-1.65036,2.33223,0.2,-2.33223,0,0.20018,-2.33396,1.64914,0.2,-2.85639,0,0.20018,-2.85851,0.85366,0.2,-3.18589,0,0.2,-3.29827,-0.85366,0.2,3.18589,-1.64914,0.2,2.85639,-2.33223,0.2,2.33223,-2.85639,0.2,1.64914,-3.18589,0.2,0.85366,-3.29827,0.2,2.38419e-08,-3.18589,0.2,-0.85366,-2.85639,0.2,-1.64914,-2.33223,0.2,-2.33223,-1.64914,0.2,-2.85639,-0.85366,0.2,-3.18589,3.38072,0.49269,-0.90586,3.24961,1.2607,-0.79774,3.49998,0.49269,5.87332e-08,3.03107,0.49269,-1.74999,2.62813,1.2607,-1.51735,2.47486,0.49269,-2.47486,2.28587,1.2607,-2.40424,1.74999,0.49269,-3.03107,1.92706,2.01349,-2.67957,1.74999,0.39996,-3.03107,0.91195,3.05908,-3.38389,1.75608,3.05908,-3.03424,0.90586,0.39996,-3.38072,0,0.39996,-3.49998,0.00609,3.05908,-3.50315,0,10,-3.49998,-0.89977,3.05908,-3.38389,-0.90586,10,-3.38072,-1.7439,3.05908,-3.03424,-1.74999,10,-3.03107,-2.46876,3.05908,-2.47803,-2.47486,10,-2.47486,-2.47486,0.39996,-2.47486,-3.03107,0.39996,-1.74999,-3.02498,3.05908,-1.75316,-3.38072,0.39996,-0.90586,-3.37463,3.05908,-0.90903,-3.49998,0.39996,4.76789e-08,-3.49389,3.05908,-0.00316964,-3.38072,0.39996,0.90586,-3.37463,3.05908,0.90269,-3.03107,0.39996,1.74999,-3.02498,3.05908,1.74682,-2.47486,0.39996,2.47486,-2.46877,3.05908,2.47169,-1.74999,0.39996,3.03107,-1.7439,3.05908,3.0279,-0.90586,0.39996,3.38072,-0.89977,3.05908,3.37755,0,0.39996,3.49998,0.00609,3.05908,3.49681,0.90569,4.13133,3.10396,-0.09523,4.49132,3.21186,0,3.78134,3.49998,0.90586,3.78134,3.38072,1.74999,3.78134,3.03107,1.75727,4.6979,2.78561,1.75608,3.05908,3.0279,1.74999,0.39996,3.03107,2.47486,0.39996,2.47486,2.48095,3.05908,2.47169,3.03107,0.39996,1.74999,3.03716,3.05908,1.74682,3.38072,0.39996,0.90586,3.38681,3.05908,0.90269,3.50607,3.05908,-0.00316964,3.49998,0.39996,4.76789e-08,3.67416,0.3009,3.58701e-08,3.70173,0.2,2.38419e-08,3.57559,0.2,-0.95808,3.54897,0.3009,-0.95094,3.60177,0.37267,4.44257e-08,3.47904,0.37267,-0.93221,3.38072,0.39996,-0.90586,3.32584,0.0991,1.18136e-08,3.21251,0.0991001,-0.86079,3.39823,0.02733,3.25799e-09,3.28244,0.0273301,-0.87953,3.5,0,0,3.38074,1.07988e-07,-0.90587,3.60177,0.02733,3.25799e-09,3.47904,0.0273301,-0.93221,3.67416,0.0991,1.18136e-08,3.54897,0.0991001,-0.95094,3.54897,0.3009,0.95094,3.57559,0.2,0.95808,3.47904,0.37267,0.93221,3.21251,0.0990999,0.86079,3.28244,0.0273299,0.87953,3.38074,-1.07988e-07,0.90587,3.47904,0.0273299,0.93221,3.54897,0.0990999,0.95094,3.18192,0.3009,1.83708,3.20579,0.2,1.85087,3.11922,0.37267,1.80089,2.88026,0.0990998,1.66292,2.94295,0.0273298,1.69912,3.03109,-2.08616e-07,1.75,3.11922,0.0273298,1.80089,3.18192,0.0990998,1.83708,2.59802,0.3009,2.59803,2.61751,0.2,2.61752,2.54683,0.37267,2.54684,2.35172,0.0990997,2.35172,2.40291,0.0273297,2.40291,2.47487,-2.95029e-07,2.47488,2.54683,0.0273297,2.54684,2.59802,0.0990997,2.59803,1.83708,0.3009,3.18192,1.85086,0.2,3.20579,1.80088,0.37267,3.11923,1.66292,0.0990997,2.88026,1.69911,0.0273296,2.94295,1.75,-3.61334e-07,3.03109,1.80088,0.0273296,3.11923,1.83708,0.0990996,3.18192,0.95094,0.3009,3.54897,0.95807,0.2,3.57559,0.9322,0.37267,3.47904,0.90586,0.39996,3.38072,0.86079,0.0990996,3.21251,0.87953,0.0273296,3.28244,0.90586,-4.03016e-07,3.38074,0.9322,0.0273296,3.47904,0.95094,0.0990996,3.54897,0,0.3009,3.67416,0,0.2,3.70173,0,0.37267,3.60177,0,0.0990996,3.32584,0,0.0273296,3.39823,0,-4.17233e-07,3.5,0,0.0273296,3.60177,0,0.0990996,3.67416,-0.95094,0.3009,3.54897,-0.95808,0.2,3.57559,-0.93221,0.37267,3.47904,-0.86079,0.0990996,3.21251,-0.87953,0.0273296,3.28244,-0.90587,-4.03016e-07,3.38074,-0.93221,0.0273296,3.47904,-0.95094,0.0990996,3.54897,-1.83708,0.3009,3.18192,-1.85087,0.2,3.20579,-1.80089,0.37267,3.11922,-1.66292,0.0990997,2.88026,-1.69912,0.0273296,2.94295,-1.75,-3.61334e-07,3.03109,-1.80089,0.0273296,3.11922,-1.83708,0.0990996,3.18192,-2.59803,0.3009,2.59802,-2.61752,0.2,2.61751,-2.54684,0.37267,2.54683,-2.35172,0.0990997,2.35172,-2.40291,0.0273297,2.40291,-2.47488,-2.95027e-07,2.47487,-2.54684,0.0273297,2.54683,-2.59803,0.0990997,2.59802,-3.18192,0.3009,1.83708,-3.20579,0.2,1.85086,-3.11922,0.37267,1.80088,-2.88026,0.0990998,1.66292,-2.94295,0.0273298,1.69911,-3.03109,-2.08616e-07,1.75,-3.11923,0.0273298,1.80088,-3.18192,0.0990998,1.83708,-3.54897,0.3009,0.95094,-3.57559,0.2,0.95807,-3.47904,0.37267,0.9322,-3.21251,0.0990999,0.86079,-3.28244,0.0273299,0.87953,-3.38074,-1.07988e-07,0.90587,-3.47904,0.0273299,0.9322,-3.54897,0.0990999,0.95094,-3.67416,0.3009,3.58701e-08,-3.70173,0.2,2.38419e-08,-3.60177,0.37267,4.44257e-08,-3.32584,0.0991,1.18136e-08,-3.39823,0.02733,3.25799e-09,-3.5,0,0,-3.60177,0.02733,3.25799e-09,-3.67416,0.0991,1.18136e-08,-3.54897,0.3009,-0.95094,-3.57559,0.2,-0.95808,-3.47904,0.37267,-0.93221,-3.21251,0.0991001,-0.86079,-3.28244,0.0273301,-0.87953,-3.38074,1.07988e-07,-0.90587,-3.47904,0.0273301,-0.93221,-3.54897,0.0991001,-0.95094,-3.18192,0.3009,-1.83708,-3.20579,0.2,-1.85086,-3.11922,0.37267,-1.80089,-2.88026,0.0991002,-1.66292,-2.94295,0.0273302,-1.69912,-3.03109,2.08616e-07,-1.75,-3.11922,0.0273302,-1.80089,-3.18192,0.0991002,-1.83708,-2.59802,0.3009,-2.59803,-2.61751,0.2,-2.61752,-2.54684,0.37267,-2.54684,-2.35172,0.0991003,-2.35172,-2.40291,0.0273303,-2.40291,-2.47487,2.95027e-07,-2.47487,-2.54684,0.0273303,-2.54684,-2.59802,0.0991003,-2.59803,-1.83708,0.3009,-3.18192,-1.85086,0.2,-3.20579,-1.80089,0.37267,-3.11922,-1.74999,0.39996,-3.03107,-1.66292,0.0991003,-2.88026,-1.69911,0.0273304,-2.94295,-1.75,3.61334e-07,-3.03109,-1.80089,0.0273304,-3.11922,-1.83708,0.0991004,-3.18192,-0.95094,0.3009,-3.54897,-0.95808,0.2,-3.57559,-0.93221,0.37267,-3.47904,-0.90586,0.39996,-3.38072,-0.86079,0.0991004,-3.21251,-0.87953,0.0273304,-3.28244,-0.90587,4.03016e-07,-3.38074,-0.93221,0.0273304,-3.47904,-0.95094,0.0991004,-3.54897,0,0.3009,-3.67416,0,0.2,-3.70173,0,0.37267,-3.60177,0,0.0991004,-3.32584,0,0.0273304,-3.39823,0,4.17233e-07,-3.5,0,0.0273304,-3.60177,0,0.0991004,-3.67416,0.95094,0.3009,-3.54897,0.95808,0.2,-3.57559,0.93221,0.37267,-3.47904,0.86079,0.0991004,-3.21251,0.87953,0.0273304,-3.28244,0.90587,4.03016e-07,-3.38074,0.93221,0.0273304,-3.47904,0.95094,0.0991004,-3.54897,1.83708,0.3009,-3.18192,1.85086,0.2,-3.20579,1.80089,0.37267,-3.11922,1.66292,0.0991003,-2.88026,1.69911,0.0273304,-2.94295,1.75,3.61334e-07,-3.03109,1.80089,0.0273304,-3.11922,1.83708,0.0991004,-3.18192,2.59802,0.3009,-2.59802,2.61752,0.2,-2.61752,2.54684,0.37267,-2.54684,2.47486,0.39996,-2.47486,2.35172,0.0991003,-2.35172,2.40291,0.0273303,-2.40291,2.47487,2.95027e-07,-2.47487,2.54684,0.0273303,-2.54684,2.59802,0.0991003,-2.59802,3.18192,0.3009,-1.83708,3.20579,0.2,-1.85086,3.11922,0.37267,-1.80089,3.03107,0.39996,-1.74999,2.88026,0.0991002,-1.66292,2.94295,0.0273302,-1.69911,3.03109,2.08616e-07,-1.75,3.11922,0.0273302,-1.80089,3.18192,0.0991002,-1.83708,3.67416,10.0991,1.20391e-06,3.54897,10.0991,-0.950939,3.57559,10.2,-0.958079,3.70173,10.2,1.21593e-06,3.60177,10.0273,1.19535e-06,3.47904,10.0273,-0.932209,3.49998,10,1.19209e-06,3.38072,10,-0.905859,3.32584,10.3009,1.22796e-06,3.21251,10.3009,-0.860789,3.39823,10.3727,1.23652e-06,3.28244,10.3727,-0.879529,3.5,10.4,1.23978e-06,3.38074,10.4,-0.905869,3.60177,10.3727,1.23652e-06,3.47904,10.3727,-0.932209,3.67416,10.3009,1.22796e-06,3.54897,10.3009,-0.950939,3.54897,10.0991,0.950941,3.57559,10.2,0.958081,3.47904,10.0273,0.932211,3.38072,10,0.905861,3.21251,10.3009,0.860791,3.28244,10.3727,0.879531,3.38074,10.4,0.905871,3.47904,10.3727,0.932211,3.54897,10.3009,0.950941,3.18192,10.0991,1.83708,3.20579,10.2,1.85087,3.11922,10.0273,1.80089,3.03107,10,1.74999,2.88026,10.3009,1.66292,2.94295,10.3727,1.69912,3.03109,10.4,1.75,3.11922,10.3727,1.80089,3.18192,10.3009,1.83708,2.59802,10.0991,2.59803,2.61751,10.2,2.61752,2.54683,10.0273,2.54684,2.47486,10,2.47486,2.35172,10.3009,2.35172,2.40291,10.3727,2.40291,2.47487,10.4,2.47488,2.54683,10.3727,2.54684,2.59802,10.3009,2.59803,1.83708,10.0991,3.18192,1.85086,10.2,3.20579,1.80088,10.0273,3.11923,1.74999,10,3.03107,1.66292,10.3009,2.88026,1.69911,10.3727,2.94295,1.75,10.4,3.03109,1.80088,10.3727,3.11923,1.83708,10.3009,3.18192,0.95094,10.0991,3.54897,0.95807,10.2,3.57559,0.9322,10.0273,3.47904,0.90586,10,3.38072,0.86079,10.3009,3.21251,0.87953,10.3727,3.28244,0.90586,10.4,3.38074,0.9322,10.3727,3.47904,0.95094,10.3009,3.54897,0,10.0991,3.67416,0,10.2,3.70173,0,10.0273,3.60177,0,10,3.49998,0,10.3009,3.32584,0,10.3727,3.39823,0,10.4,3.5,0,10.3727,3.60177,0,10.3009,3.67416,-0.95094,10.0991,3.54897,-0.95808,10.2,3.57559,-0.93221,10.0273,3.47904,-0.90586,10,3.38072,-0.86079,10.3009,3.21251,-0.87953,10.3727,3.28244,-0.90587,10.4,3.38074,-0.93221,10.3727,3.47904,-0.95094,10.3009,3.54897,-1.83708,10.0991,3.18192,-1.85087,10.2,3.20579,-1.80089,10.0273,3.11922,-1.74999,10,3.03107,-1.66292,10.3009,2.88026,-1.69912,10.3727,2.94295,-1.75,10.4,3.03109,-1.80089,10.3727,3.11922,-1.83708,10.3009,3.18192,-2.59803,10.0991,2.59802,-2.61752,10.2,2.61751,-2.54684,10.0273,2.54683,-2.47486,10,2.47486,-2.35172,10.3009,2.35172,-2.40291,10.3727,2.40291,-2.47488,10.4,2.47487,-2.54684,10.3727,2.54683,-2.59803,10.3009,2.59802,-3.18192,10.0991,1.83708,-3.20579,10.2,1.85086,-3.11922,10.0273,1.80088,-3.03107,10,1.74999,-2.88026,10.3009,1.66292,-2.94295,10.3727,1.69911,-3.03109,10.4,1.75,-3.11923,10.3727,1.80088,-3.18192,10.3009,1.83708,-3.54897,10.0991,0.950941,-3.57559,10.2,0.958071,-3.47904,10.0273,0.932201,-3.38072,10,0.905861,-3.21251,10.3009,0.860791,-3.28244,10.3727,0.879531,-3.38074,10.4,0.905871,-3.47904,10.3727,0.932201,-3.54897,10.3009,0.950941,-3.67416,10.0991,1.20391e-06,-3.70173,10.2,1.21593e-06,-3.60177,10.0273,1.19535e-06,-3.49998,10,1.19209e-06,-3.32584,10.3009,1.22796e-06,-3.39823,10.3727,1.23652e-06,-3.5,10.4,1.23978e-06,-3.60177,10.3727,1.23652e-06,-3.67416,10.3009,1.22796e-06,-3.54897,10.0991,-0.950939,-3.57559,10.2,-0.958079,-3.47904,10.0273,-0.932209,-3.38072,10,-0.905859,-3.21251,10.3009,-0.860789,-3.28244,10.3727,-0.879529,-3.38074,10.4,-0.905869,-3.47904,10.3727,-0.932209,-3.54897,10.3009,-0.950939,-3.18192,10.0991,-1.83708,-3.20579,10.2,-1.85086,-3.11922,10.0273,-1.80089,-3.03107,10,-1.74999,-2.88026,10.3009,-1.66292,-2.94295,10.3727,-1.69912,-3.03109,10.4,-1.75,-3.11922,10.3727,-1.80089,-3.18192,10.3009,-1.83708,-2.59802,10.0991,-2.59803,-2.61751,10.2,-2.61752,-2.54684,10.0273,-2.54684,-2.35172,10.3009,-2.35172,-2.40291,10.3727,-2.40291,-2.47487,10.4,-2.47487,-2.54684,10.3727,-2.54684,-2.59802,10.3009,-2.59803,-1.83708,10.0991,-3.18192,-1.85086,10.2,-3.20579,-1.80089,10.0273,-3.11922,-1.66292,10.3009,-2.88026,-1.69911,10.3727,-2.94295,-1.75,10.4,-3.03109,-1.80089,10.3727,-3.11922,-1.83708,10.3009,-3.18192,-0.95094,10.0991,-3.54897,-0.95808,10.2,-3.57559,-0.93221,10.0273,-3.47904,-0.86079,10.3009,-3.21251,-0.87953,10.3727,-3.28244,-0.90587,10.4,-3.38074,-0.93221,10.3727,-3.47904,-0.95094,10.3009,-3.54897,0,10.0991,-3.67416,0,10.2,-3.70173,0,10.0273,-3.60177,0,10.3009,-3.32584,0,10.3727,-3.39823,0,10.4,-3.5,0,10.3727,-3.60177,0,10.3009,-3.67416,0.95094,10.0991,-3.54897,0.95808,10.2,-3.57559,0.93221,10.0273,-3.47904,0.90586,10,-3.38072,0.86079,10.3009,-3.21251,0.87953,10.3727,-3.28244,0.90587,10.4,-3.38074,0.93221,10.3727,-3.47904,0.95094,10.3009,-3.54897,1.83708,10.0991,-3.18192,1.85086,10.2,-3.20579,1.80089,10.0273,-3.11922,1.74999,10,-3.03107,1.66292,10.3009,-2.88026,1.69911,10.3727,-2.94295,1.75,10.4,-3.03109,1.80089,10.3727,-3.11922,1.83708,10.3009,-3.18192,2.59802,10.0991,-2.59802,2.61752,10.2,-2.61752,2.54684,10.0273,-2.54684,2.47486,10,-2.47486,2.35172,10.3009,-2.35172,2.40291,10.3727,-2.40291,2.47487,10.4,-2.47487,2.54684,10.3727,-2.54684,2.59802,10.3009,-2.59802,3.18192,10.0991,-1.83708,3.20579,10.2,-1.85086,3.11922,10.0273,-1.80089,3.03107,10,-1.74999,2.88026,10.3009,-1.66292,2.94295,10.3727,-1.69911,3.03109,10.4,-1.75,3.11922,10.3727,-1.80089,3.18192,10.3009,-1.83708,3.44334,7.19777,-0.922639,3.37982,7.22954,-0.905619,3.49904,7.22954,8.61828e-07,3.56481,7.19777,8.58041e-07,3.48919,7.11557,-0.934919,3.61227,7.11557,8.48242e-07,3.50664,7,-0.939599,3.63034,7,8.34465e-07,3.48919,6.88444,-0.934919,3.61227,6.88444,8.20689e-07,3.44334,6.80224,-0.922639,3.56481,6.80224,8.1089e-07,3.37982,6.77047,-0.905619,3.49904,6.77047,8.07103e-07,3.37982,7.22954,0.905621,3.44334,7.19777,0.922641,3.48919,7.11557,0.934931,3.50664,7,0.939601,3.48919,6.88444,0.934931,3.44334,6.80224,0.922641,3.37982,6.77047,0.905621,3.03026,7.22954,1.74952,3.08722,7.19777,1.78241,3.12832,7.11557,1.80614,3.14397,7,1.81517,3.12832,6.88444,1.80614,3.08722,6.80224,1.78241,3.03026,6.77047,1.74952,2.4742,7.22954,2.4742,2.5207,7.19777,2.5207,2.55426,7.11557,2.55426,2.56704,7,2.56704,2.55426,6.88444,2.55426,2.5207,6.80224,2.5207,2.4742,6.77047,2.4742,1.74952,7.22954,3.03026,1.7824,7.19777,3.08722,1.80614,7.11557,3.12832,1.81517,7,3.14397,1.80613,6.88444,3.12832,1.7824,6.80224,3.08722,1.74952,6.77047,3.03026,0.90562,7.22954,3.37982,0.92264,7.19777,3.44334,0.93492,7.11557,3.48919,0.9396,7,3.50664,0.93492,6.88444,3.48919,0.92264,6.80224,3.44334,0.90562,6.77047,3.37982,0,7.22954,3.49904,0,7.19777,3.56481,0,7.11557,3.61227,0,7,3.63034,0,6.88444,3.61227,0,6.80224,3.56481,0,6.77047,3.49904,-0.90562,7.22954,3.37982,-0.92264,7.19777,3.44334,-0.93493,7.11557,3.48919,-0.9396,7,3.50664,-0.93493,6.88444,3.48919,-0.92264,6.80224,3.44334,-0.90562,6.77047,3.37982,-1.74952,7.22954,3.03026,-1.78241,7.19777,3.08722,-1.80614,7.11557,3.12832,-1.81517,7,3.14397,-1.80614,6.88444,3.12832,-1.78241,6.80224,3.08722,-1.74952,6.77047,3.03026,-2.4742,7.22954,2.4742,-2.5207,7.19777,2.5207,-2.55426,7.11557,2.55426,-2.56704,7,2.56704,-2.55426,6.88444,2.55426,-2.5207,6.80224,2.5207,-2.4742,6.77047,2.4742,-3.03026,7.22954,1.74952,-3.08722,7.19777,1.7824,-3.12832,7.11557,1.80614,-3.14397,7,1.81517,-3.12832,6.88444,1.80614,-3.08722,6.80224,1.7824,-3.03026,6.77047,1.74952,-3.37982,7.22954,0.905621,-3.44334,7.19777,0.922641,-3.48919,7.11557,0.934921,-3.50664,7,0.939601,-3.48919,6.88444,0.934921,-3.44334,6.80224,0.922641,-3.37982,6.77047,0.905621,-3.49904,7.22954,8.61828e-07,-3.56481,7.19777,8.58041e-07,-3.61227,7.11557,8.48242e-07,-3.63034,7,8.34465e-07,-3.61227,6.88444,8.20689e-07,-3.56481,6.80224,8.1089e-07,-3.49904,6.77047,8.07103e-07,-3.37982,7.22954,-0.905619,-3.44334,7.19777,-0.922639,-3.48919,7.11557,-0.934929,-3.50664,7,-0.939599,-3.48919,6.88444,-0.934929,-3.44334,6.80224,-0.922639,-3.37982,6.77047,-0.905619,-3.03026,7.22954,-1.74952,-3.08722,7.19777,-1.78241,-3.12832,7.11557,-1.80614,-3.14397,7,-1.81517,-3.12832,6.88444,-1.80614,-3.08722,6.80224,-1.78241,-3.03026,6.77047,-1.74952,-2.4742,7.22954,-2.4742,-2.5207,7.19777,-2.5207,-2.55426,7.11557,-2.55426,-2.56704,7,-2.56704,-2.55426,6.88444,-2.55426,-2.5207,6.80224,-2.5207,-2.4742,6.77047,-2.4742,-1.74952,7.22954,-3.03026,-1.78241,7.19777,-3.08722,-1.80614,7.11557,-3.12832,-1.81517,7,-3.14397,-1.80614,6.88444,-3.12832,-1.7824,6.80224,-3.08722,-1.74952,6.77047,-3.03026,-0.90562,7.22954,-3.37982,-0.92264,7.19777,-3.44334,-0.93492,7.11557,-3.48919,-0.9396,7,-3.50664,-0.93492,6.88444,-3.48919,-0.92264,6.80224,-3.44334,-0.90562,6.77047,-3.37982,0,7.22954,-3.49904,0,7.19777,-3.56481,0,7.11557,-3.61227,0,7,-3.63034,0,6.88444,-3.61227,0,6.80224,-3.56481,0,6.77047,-3.49904,0.90562,7.22954,-3.37982,0.92264,7.19777,-3.44334,0.93492,7.11557,-3.48919,0.9396,7,-3.50664,0.93492,6.88444,-3.48919,0.92264,6.80224,-3.44334,0.90562,6.77047,-3.37982,1.74952,7.22954,-3.03026,1.78241,7.19777,-3.08722,1.80614,7.11557,-3.12832,1.81517,7,-3.14397,1.80614,6.88444,-3.12832,1.78241,6.80224,-3.08722,1.74952,6.77047,-3.03026,2.4742,7.22954,-2.4742,2.5207,7.19777,-2.5207,2.55426,7.11557,-2.55426,2.56704,7,-2.56704,2.55426,6.88444,-2.55426,2.5207,6.80224,-2.5207,2.4742,6.77047,-2.4742,3.03026,7.22954,-1.74952,3.08722,7.19777,-1.78241,3.12832,7.11557,-1.80614,3.14397,7,-1.81517,3.12832,6.88444,-1.80614,3.08722,6.80224,-1.78241,3.03026,6.77047,-1.74952,3.44334,3.59777,-0.92264,3.37982,3.62953,-0.90562,3.49904,3.62953,4.32674e-07,3.56481,3.59777,4.28888e-07,3.48919,3.51556,-0.93492,3.61227,3.51556,4.19087e-07,3.50664,3.4,-0.9396,3.63034,3.4,4.05312e-07,3.48919,3.28444,-0.93492,3.61227,3.28444,3.91536e-07,3.44334,3.20224,-0.92264,3.56481,3.20224,3.81737e-07,3.37982,3.17047,-0.90562,3.49904,3.17047,3.77949e-07,3.37982,3.62953,0.905621,3.44334,3.59777,0.92264,3.48919,3.51556,0.93493,3.50664,3.4,0.9396,3.48919,3.28444,0.93493,3.44334,3.20224,0.92264,3.37982,3.17047,0.90562,3.03026,3.62953,1.74952,3.08722,3.59777,1.78241,3.12832,3.51556,1.80614,3.14397,3.4,1.81517,3.12832,3.28444,1.80614,3.08722,3.20224,1.78241,3.03026,3.17047,1.74952,2.4742,3.62953,2.4742,2.5207,3.59777,2.5207,2.55426,3.51556,2.55426,2.56704,3.4,2.56704,2.55426,3.28444,2.55426,2.5207,3.20224,2.5207,2.4742,3.17047,2.4742,1.74952,3.62953,3.03026,1.7824,3.59777,3.08722,1.80614,3.51556,3.12832,1.81517,3.4,3.14397,1.80613,3.28444,3.12832,1.7824,3.20224,3.08722,1.74952,3.17047,3.03026,0.90562,3.62953,3.37982,0.92264,3.59777,3.44334,0.93492,3.51556,3.48919,0.9396,3.4,3.50664,0.93492,3.28444,3.48919,0.92264,3.20224,3.44334,0.90562,3.17047,3.37982,0,3.62953,3.49904,0,3.59777,3.56481,0,3.51556,3.61227,0,3.4,3.63034,0,3.28444,3.61227,0,3.20224,3.56481,0,3.17047,3.49904,-0.90562,3.62953,3.37982,-0.92264,3.59777,3.44334,-0.93493,3.51556,3.48919,-0.9396,3.4,3.50664,-0.93493,3.28444,3.48919,-0.92264,3.20224,3.44334,-0.90562,3.17047,3.37982,-1.74952,3.62953,3.03026,-1.78241,3.59777,3.08722,-1.80614,3.51556,3.12832,-1.81517,3.4,3.14397,-1.80614,3.28444,3.12832,-1.78241,3.20224,3.08722,-1.74952,3.17047,3.03026,-2.4742,3.62953,2.4742,-2.5207,3.59777,2.5207,-2.55426,3.51556,2.55426,-2.56704,3.4,2.56704,-2.55426,3.28444,2.55426,-2.5207,3.20224,2.5207,-2.4742,3.17047,2.4742,-3.03026,3.62953,1.74952,-3.08722,3.59777,1.7824,-3.12832,3.51556,1.80614,-3.14397,3.4,1.81517,-3.12832,3.28444,1.80613,-3.08722,3.20224,1.7824,-3.03026,3.17047,1.74952,-3.37982,3.62953,0.905621,-3.44334,3.59777,0.92264,-3.48919,3.51556,0.93492,-3.50664,3.4,0.9396,-3.48919,3.28444,0.93492,-3.44334,3.20224,0.92264,-3.37982,3.17047,0.90562,-3.49904,3.62953,4.32674e-07,-3.56481,3.59777,4.28888e-07,-3.61227,3.51556,4.19087e-07,-3.63034,3.4,4.05312e-07,-3.61227,3.28444,3.91536e-07,-3.56481,3.20224,3.81737e-07,-3.49904,3.17047,3.77949e-07,-3.37982,3.62953,-0.90562,-3.44334,3.59777,-0.92264,-3.48919,3.51556,-0.93493,-3.50664,3.4,-0.9396,-3.48919,3.28444,-0.93493,-3.44334,3.20224,-0.92264,-3.37982,3.17047,-0.90562,-3.03026,3.62953,-1.74952,-3.08722,3.59777,-1.78241,-3.12832,3.51556,-1.80614,-3.14397,3.4,-1.81517,-3.12832,3.28444,-1.80614,-3.08722,3.20224,-1.78241,-3.03026,3.17047,-1.74952,-2.4742,3.62953,-2.4742,-2.5207,3.59777,-2.5207,-2.55426,3.51557,-2.55426,-2.56704,3.4,-2.56704,-2.55426,3.28444,-2.55426,-2.5207,3.20224,-2.5207,-2.4742,3.17047,-2.4742,-1.74952,3.62953,-3.03026,-1.78241,3.59777,-3.08722,-1.80614,3.51557,-3.12832,-1.81517,3.4,-3.14397,-1.80614,3.28444,-3.12832,-1.7824,3.20224,-3.08722,-1.74952,3.17047,-3.03026,-0.90562,3.62953,-3.37982,-0.92264,3.59777,-3.44334,-0.93492,3.51557,-3.48919,-0.9396,3.4,-3.50664,-0.93492,3.28444,-3.48919,-0.92264,3.20224,-3.44334,-0.90562,3.17047,-3.37982,0,3.62953,-3.49904,0,3.59777,-3.56481,0,3.51557,-3.61227,0,3.4,-3.63034,0,3.28444,-3.61227,0,3.20224,-3.56481,0,3.17047,-3.49904,0.90562,3.62953,-3.37982,0.92264,3.59777,-3.44334,0.93492,3.51557,-3.48919,0.9396,3.4,-3.50664,0.93492,3.28444,-3.48919,0.92264,3.20224,-3.44334,0.90562,3.17047,-3.37982,1.74952,3.62953,-3.03026,1.78241,3.59777,-3.08722,1.80614,3.51557,-3.12832,1.81517,3.4,-3.14397,1.80614,3.28444,-3.12832,1.78241,3.20224,-3.08722,1.74952,3.17047,-3.03026,2.4742,3.62953,-2.4742,2.5207,3.59777,-2.5207,2.55426,3.51557,-2.55426,2.56704,3.4,-2.56704,2.55426,3.28444,-2.55426,2.5207,3.20224,-2.5207,2.4742,3.17047,-2.4742,3.03026,3.62953,-1.74952,3.08722,3.59777,-1.78241,3.12832,3.51556,-1.80614,3.14397,3.4,-1.81517,3.12832,3.28444,-1.80614,3.08722,3.20224,-1.78241,3.03026,3.17047,-1.74952,0.35603,10.1971,-2.85603,0.50351,10.1971,-2.5,0.63342,10.183,-2.5,0.44789,10.183,-2.94789,0,10.1971,-3.00351,0,10.183,-3.13342,-0.35603,10.1971,-2.85603,-0.44789,10.183,-2.94789,-0.50351,10.1971,-2.5,-0.63342,10.183,-2.5,-0.35603,10.1971,-2.14397,-0.44789,10.183,-2.05211,0,10.1971,-1.99649,0,10.183,-1.86658,0.35603,10.1971,-2.14397,0.44789,10.183,-2.05211,-0.14291,10.6086,-2.41189,0.14291,10.6086,-2.41189,0.16335,10.6086,-2.46125,-0.16335,10.6086,-2.46125,0.45,10.233,-2.5,0.3182,10.233,-2.8182,0,10.233,-2.95,-0.3182,10.233,-2.8182,-0.45,10.233,-2.5,-0.3182,10.233,-2.1818,0,10.233,-2.05,0.3182,10.233,-2.1818,0.3182,10.283,-2.8182,0.45,10.283,-2.5,0,10.283,-2.95,-0.3182,10.283,-2.8182,-0.45,10.283,-2.5,-0.3182,10.283,-2.1818,0,10.283,-2.05,0.3182,10.283,-2.1818,0.31246,10.283,-2.7014,0.36335,10.283,-2.57853,0.07853,10.283,-2.86335,0.2014,10.283,-2.81246,-0.2014,10.283,-2.81246,-0.07853,10.283,-2.86335,-0.36335,10.283,-2.57853,-0.31246,10.283,-2.7014,-0.31246,10.283,-2.2986,-0.36335,10.283,-2.42147,-0.07853,10.283,-2.13665,-0.2014,10.283,-2.18754,0.2014,10.283,-2.18754,0.07853,10.283,-2.13665,0.36335,10.283,-2.42147,0.31246,10.283,-2.2986,0.31246,10.333,-2.7014,0.36335,10.333,-2.57853,0.2014,10.333,-2.81246,0.07853,10.333,-2.86335,-0.07853,10.333,-2.86335,-0.2014,10.333,-2.81246,-0.31246,10.333,-2.7014,-0.36335,10.333,-2.57853,-0.36335,10.333,-2.42147,-0.31246,10.333,-2.2986,-0.2014,10.333,-2.18754,-0.07853,10.333,-2.13665,0.07853,10.333,-2.13665,0.2014,10.333,-2.18754,0.31246,10.333,-2.2986,0.36335,10.333,-2.42147,0.39723,10.333,-2.75805,0.46335,10.333,-2.59842,0.25805,10.333,-2.89723,0.09842,10.333,-2.96335,-0.09842,10.333,-2.96335,-0.25805,10.333,-2.89723,-0.39723,10.333,-2.75805,-0.46335,10.333,-2.59842,-0.46335,10.333,-2.40158,-0.39723,10.333,-2.24195,-0.25805,10.333,-2.10277,-0.09842,10.333,-2.03665,0.09842,10.333,-2.03665,0.25805,10.333,-2.10277,0.39723,10.333,-2.24195,0.46335,10.333,-2.40158,0.39723,10.5336,-2.75805,0.46335,10.5336,-2.59842,0.25805,10.5336,-2.89723,0.09842,10.5336,-2.96335,-0.09842,10.5336,-2.96335,-0.25805,10.5336,-2.89723,-0.39723,10.5336,-2.75805,-0.46335,10.5336,-2.59842,-0.46335,10.5336,-2.40158,-0.39723,10.5336,-2.24195,-0.25805,10.5336,-2.10277,-0.09842,10.5336,-2.03665,0.09842,10.5336,-2.03665,0.25805,10.5336,-2.10277,0.39723,10.5336,-2.24195,0.46335,10.5336,-2.40158,0.31246,10.5836,-2.7014,0.36335,10.5836,-2.57853,0.2014,10.5836,-2.81246,0.07853,10.5836,-2.86335,-0.07853,10.5836,-2.86335,-0.2014,10.5836,-2.81246,-0.31246,10.5836,-2.7014,-0.36335,10.5836,-2.57853,-0.36335,10.5836,-2.42147,-0.31246,10.5836,-2.2986,-0.2014,10.5836,-2.18754,-0.07853,10.5836,-2.13665,0.07853,10.5836,-2.13665,0.2014,10.5836,-2.18754,0.31246,10.5836,-2.2986,0.36335,10.5836,-2.42147,0.14291,10.6086,-2.58811,0.16335,10.6086,-2.53875,0.08811,10.6086,-2.64291,0.03875,10.6086,-2.66335,-0.03875,10.6086,-2.66335,-0.08811,10.6086,-2.64291,-0.14291,10.6086,-2.58811,-0.16335,10.6086,-2.53875,-0.08811,10.6086,-2.35709,-0.03875,10.6086,-2.33665,0.03875,10.6086,-2.33665,0.08811,10.6086,-2.35709,0.08404,10.2092,2.45443,0.16809,10.2092,2.6,0.23899,10.1861,2.6,0.11949,10.1861,2.39303,-0.08404,10.2092,2.45443,-0.11949,10.1861,2.39303,-0.16809,10.2092,2.6,-0.23899,10.1861,2.6,-0.08404,10.2092,2.74557,-0.11949,10.1861,2.80697,0.08404,10.2092,2.74557,0.11949,10.1861,2.80697,0.09794,10.3211,2.57061,0.07442,10.3211,2.52988,0.02352,10.3211,2.50049,0.07442,10.3211,2.67012,-0.02352,10.3211,2.50049,-0.07442,10.3211,2.52988,-0.09794,10.3211,2.62939,-0.09794,10.3211,2.57061,-0.07442,10.3211,2.67012,-0.02352,10.3211,2.69951,0.02352,10.3211,2.69951,0.09794,10.3211,2.62939,0.15,10.2861,2.6,0.075,10.2861,2.4701,-0.075,10.2861,2.4701,-0.15,10.2861,2.6,-0.075,10.2861,2.7299,0.075,10.2861,2.7299,0.0854,10.2861,2.5189,0.11294,10.2861,2.5666,-0.02754,10.2861,2.48549,0.02754,10.2861,2.48549,-0.11294,10.2861,2.5666,-0.0854,10.2861,2.5189,-0.0854,10.2861,2.6811,-0.11294,10.2861,2.63341,0.02754,10.2861,2.71451,-0.02754,10.2861,2.71451,0.11294,10.2861,2.63341,0.0854,10.2861,2.6811,0.0854,10.3361,2.5189,0.11294,10.3361,2.5666,0.02754,10.3361,2.48549,-0.02754,10.3361,2.48549,-0.0854,10.3361,2.5189,-0.11294,10.3361,2.5666,-0.11294,10.3361,2.63341,-0.0854,10.3361,2.6811,-0.02754,10.3361,2.71451,0.02754,10.3361,2.71451,0.0854,10.3361,2.6811,0.11294,10.3361,2.63341,0.90553,5.19998,2.83755,0.90569,6.44188,3.10456,0.02736,5.78822,3.21128,1.74999,6.6768,3.03107,0.90586,6.67533,3.38072,1.72873,5.76378,2.78678,-3.31239,7.82871,0.935331,-3.49998,7.91884,9.43999e-07,-3.49998,7.49929,8.93985e-07,-3.38072,7.3172,0.905861,-2.843,7.82871,1.37134,-3.03107,7.3172,1.74999,-2.47486,7.91884,2.47486,-2.47486,7.49929,2.47486,-0.90586,6.6768,3.38072,0,6.6768,3.49998,2.47486,6.6768,2.47486,0.91195,3.05908,3.37755,-0.90586,3.78134,3.38072,2.47486,3.78134,2.47486,3.38681,3.05908,-0.90903,3.1211,2.01349,-0.69176,3.25528,2.54151,-0.80148,3.31243,2.01349,-0.34242,3.03716,3.05908,-1.75316,2.63918,2.54151,-1.52356,2.23316,2.01349,-1.28932,2.48095,3.05908,-2.47803,2.10062,2.01349,-2.33502,2.29269,2.54151,-2.40724,-3.38072,8.33009,-0.905859,-1.74999,8.33009,3.03107,-3.49998,8.33009,9.93024e-07,-3.49998,8.84436,1.05433e-06,-3.43975,8.33009,-0.457459,-3.49998,9.34845,1.11442e-06,-3.38072,9.80038,0.905861,-3.24542,8.33009,0.964221,-3.31374,9.07259,0.934751,-3.03107,9.80038,1.74999,-2.84672,9.07259,1.37884,-2.65865,8.33009,1.00019,-2.47486,9.34845,2.47486,-2.47486,8.33009,2.47486,-2.47486,8.84436,2.47486,-2.11605,8.33009,2.75018],
+
+"morphTargets" : [],
+
+"normals" : [-0.615192,-0.770928,-0.16483,0,-1,0,-0.636891,-0.770928,0,0,1,0,0.636891,0.770928,0,0.615192,0.770928,-0.16483,0.615192,0.770928,0.16483,0.551561,0.770928,-0.31843,0.450362,0.770928,-0.450331,0,1,-3.1e-05,0.318461,0.770898,-0.551561,0,1,-0.000183,0.164861,0.770837,-0.615284,0,0.770867,-0.636982,0.551561,0.770928,0.31843,0.450362,0.770928,0.450331,0,1,3.1e-05,0.318461,0.770898,0.551561,0,1,0.000183,0.164861,0.770837,0.615284,0,0.770867,0.636982,-0.164861,0.770837,-0.615284,-0.318461,0.770898,-0.551561,-0.450362,0.770928,-0.450331,-0.551561,0.770928,-0.31843,-0.615192,0.770928,-0.16483,-0.636891,0.770928,0,-0.615192,0.770928,0.16483,-0.551561,0.770928,0.31843,-0.450362,0.770928,0.450331,-0.318461,0.770898,0.551561,-0.164861,0.770837,0.615284,-0.615192,-0.770928,0.16483,-0.551561,-0.770928,-0.31843,-0.450362,-0.770928,-0.450331,0,-1,-3.1e-05,-0.318461,-0.770898,-0.551561,0,-1,-0.000183,-0.164861,-0.770837,-0.615284,0,-0.770867,-0.636982,-0.551561,-0.770928,0.31843,-0.450362,-0.770928,0.450331,0,-1,3.1e-05,-0.318461,-0.770898,0.551561,0,-1,0.000183,-0.164861,-0.770837,0.615284,0,-0.770867,0.636982,0.164861,-0.770837,-0.615284,0.318461,-0.770898,-0.551561,0.450362,-0.770928,-0.450331,0.551561,-0.770928,-0.31843,0.615192,-0.770928,-0.16483,0.636891,-0.770928,0,0.615192,-0.770928,0.16483,0.551561,-0.770928,0.31843,0.450362,-0.770928,0.450331,0.318461,-0.770898,0.551561,0.164861,-0.770837,0.615284,0.943785,0.147313,-0.295816,0.862392,0.258461,-0.435255,0.999268,0.027985,-0.025147,0.847377,0.195044,-0.49382,0.788507,0.391644,-0.474197,0.738273,0.140873,-0.659597,0.797784,0.284188,-0.531724,0.529191,0.029115,-0.847957,0.842433,-0.029023,-0.53795,0.38667,0.633961,-0.669729,0.25895,-0.000519,-0.96588,0.533921,-0.041841,-0.844478,0.20011,0.633656,-0.747246,-9.2e-05,0.633869,-0.7734,0.000122,-0.000366,-0.999969,-3.1e-05,-0.633992,-0.773309,-0.258675,-0.000153,-0.965941,-0.200171,-0.634083,-0.746879,-0.499863,3.1e-05,-0.866085,-0.386608,-0.634205,-0.669546,-0.706992,0.000214,-0.707205,-0.546678,-0.634297,-0.546587,-0.546525,0.634632,-0.546342,-0.669149,0.634877,-0.386181,-0.865932,0.000366,-0.500107,-0.746147,0.63506,-0.199835,-0.96585,0.000427,-0.259041,-0.772301,0.635212,3.1e-05,-0.999969,0.000458,-0.000244,-0.745933,0.635304,0.199896,-0.965941,0.000458,0.258736,-0.668752,0.635304,0.38609,-0.865993,0.000488,0.500015,-0.546098,0.635273,0.546037,-0.706931,0.000488,0.707266,-0.386212,0.635182,0.668844,-0.500168,-9.2e-05,0.865902,-0.200018,0.634999,0.746147,-0.258431,-0.002319,0.966002,-9.2e-05,0.634785,0.772668,0.000427,-0.001587,0.999969,0.207129,0.354595,0.911771,0.173528,0.176519,0.968871,0.023988,0.21308,0.976714,0.240394,0.213813,0.946806,0.459334,0.149846,0.875515,0.316507,0.127293,0.93997,0.500412,0.000153,0.865749,0.386425,0.634297,0.669546,0.546709,0.634022,0.546861,0.706992,0.000214,0.707205,0.66979,0.633808,0.386822,0.86578,-0.000336,0.500381,0.747246,0.633625,0.200262,0.965941,-0.00058,0.258675,0.998779,-0.036378,-0.032655,0.773034,0.634327,0,0.868954,0.494827,0,1,0,0,0.965911,0,-0.258797,0.839351,0.494827,-0.224891,0.513901,0.857814,0,0.496384,0.857814,-0.133,0.746696,0.634327,-0.200079,-0.858028,-0.513565,0,-0.828791,-0.513535,0.222053,-0.481948,-0.876156,0,-0.465529,-0.876156,0.124729,0.021577,-0.999756,0,0.020844,-0.999756,-0.005585,0.514084,-0.857723,0,0.496567,-0.857723,-0.13303,0.868954,-0.494827,0,0.839351,-0.494827,-0.224891,0.839351,0.494827,0.224891,0.965911,0,0.258797,0.496384,0.857814,0.133,-0.828791,-0.513535,-0.222053,-0.465529,-0.876156,-0.124729,0.020844,-0.999756,0.005585,0.496567,-0.857723,0.13303,0.839351,-0.494827,0.224891,0.752556,0.494827,0.434462,0.865993,0,0.499985,0.445051,0.857814,0.256935,-0.743095,-0.513535,-0.428999,-0.417402,-0.876156,-0.240974,0.018708,-0.999756,0.010804,0.445204,-0.857723,0.257027,0.752556,-0.494827,0.434462,0.61446,0.494827,0.61446,0.707083,0,0.707083,0.363384,0.857814,0.363384,-0.606708,-0.513535,-0.606708,-0.3408,-0.876156,-0.3408,0.015259,-0.999756,0.015259,0.363506,-0.857723,0.363506,0.61446,-0.494827,0.61446,0.434492,0.494827,0.752556,0.499985,0,0.866024,0.256935,0.857814,0.445051,-0.429029,-0.513535,-0.743065,-0.240974,-0.876156,-0.417402,0.010804,-0.999756,0.018708,0.257027,-0.857723,0.445204,0.434492,-0.494827,0.752556,0.224891,0.494827,0.839351,0.258797,0,0.965911,0.133,0.857814,0.496384,0.199896,0.634541,0.746544,-0.222053,-0.513535,-0.828791,-0.124729,-0.876156,-0.465529,0.005585,-0.999756,0.020844,0.13303,-0.857723,0.496567,0.224891,-0.494827,0.839351,0,0.494827,0.868954,0,0,0.999969,0,0.857814,0.513901,0,-0.513565,-0.858028,0,-0.876156,-0.481979,0,-0.999756,0.021577,0,-0.857723,0.514084,0,-0.494827,0.868954,-0.224891,0.494827,0.839351,-0.258797,0,0.965911,-0.133,0.857814,0.496384,0.222053,-0.513535,-0.828791,0.124729,-0.876156,-0.465529,-0.005585,-0.999756,0.020844,-0.13303,-0.857723,0.496567,-0.224891,-0.494827,0.839351,-0.434462,0.494827,0.752556,-0.499985,0,0.865993,-0.256935,0.857814,0.445051,0.428999,-0.513535,-0.743095,0.240974,-0.876156,-0.417402,-0.010804,-0.999756,0.018708,-0.257027,-0.857723,0.445204,-0.434462,-0.494827,0.752556,-0.61446,0.494827,0.61446,-0.707083,0,0.707083,-0.363384,0.857814,0.363384,0.606739,-0.513535,-0.606708,0.3408,-0.876156,-0.3408,-0.015259,-0.999756,0.015259,-0.363506,-0.857723,0.363506,-0.61446,-0.494827,0.61446,-0.752556,0.494827,0.434462,-0.866024,0,0.499985,-0.445051,0.857814,0.256935,0.743095,-0.513535,-0.429029,0.417402,-0.876156,-0.240974,-0.018708,-0.999756,0.010804,-0.445204,-0.857723,0.257027,-0.752556,-0.494827,0.434492,-0.839351,0.494827,0.224891,-0.965911,0,0.258797,-0.496384,0.857814,0.133,0.828791,-0.513535,-0.222053,0.465529,-0.876156,-0.124729,-0.020844,-0.999756,0.005585,-0.496567,-0.857723,0.13303,-0.839351,-0.494827,0.224891,-0.868954,0.494827,0,-0.999969,0,0,-0.513901,0.857814,0,0.858028,-0.513565,0,0.481948,-0.876156,0,-0.021577,-0.999756,0,-0.514084,-0.857723,0,-0.868954,-0.494827,0,-0.839351,0.494827,-0.224891,-0.965911,0,-0.258797,-0.496384,0.857814,-0.133,0.828791,-0.513535,0.222053,0.465529,-0.876156,0.124729,-0.020844,-0.999756,-0.005585,-0.496567,-0.857723,-0.13303,-0.839351,-0.494827,-0.224891,-0.752556,0.494827,-0.434492,-0.866024,0,-0.499985,-0.445051,0.857814,-0.256935,0.743095,-0.513535,0.428999,0.417402,-0.876156,0.240974,-0.018708,-0.999756,-0.010773,-0.445204,-0.857723,-0.257027,-0.752556,-0.494827,-0.434492,-0.61446,0.494797,-0.61446,-0.707083,0,-0.707083,-0.363384,0.857814,-0.363384,0.606708,-0.513535,0.606739,0.3408,-0.876156,0.3408,-0.015259,-0.999756,-0.015259,-0.363506,-0.857723,-0.363506,-0.61446,-0.494797,-0.61446,-0.434492,0.494827,-0.752556,-0.499985,0,-0.866024,-0.256935,0.857814,-0.445051,-0.386608,0.634388,-0.669362,0.429029,-0.513535,0.743095,0.240974,-0.876156,0.417402,-0.010773,-0.999756,-0.018708,-0.257027,-0.857723,-0.445204,-0.434492,-0.494827,-0.752556,-0.224891,0.494827,-0.839351,-0.258797,0,-0.965911,-0.133,0.857814,-0.496384,-0.200232,0.634114,-0.746818,0.222053,-0.513535,0.828791,0.124729,-0.876156,0.465529,-0.005585,-0.999756,-0.020844,-0.13303,-0.857723,-0.496567,-0.224891,-0.494827,-0.839351,0,0.494827,-0.868954,0,0,-1,0,0.857814,-0.513901,0,-0.513565,0.858028,0,-0.876156,0.481948,0,-0.999756,-0.021577,0,-0.857723,-0.514084,0,-0.494827,-0.868954,0.224891,0.494827,-0.839351,0.258797,0,-0.965911,0.133,0.857814,-0.496384,-0.222053,-0.513535,0.828791,-0.124729,-0.876156,0.465529,0.005585,-0.999756,-0.020844,0.13303,-0.857723,-0.496567,0.224891,-0.494827,-0.839351,0.434462,0.494827,-0.752556,0.499985,0,-0.866024,0.256966,0.857814,-0.445051,-0.429029,-0.513535,0.743095,-0.240974,-0.876156,0.417402,0.010773,-0.999756,-0.018708,0.257027,-0.857723,-0.445204,0.434462,-0.494827,-0.752556,0.61446,0.494827,-0.61446,0.707083,0,-0.707083,0.363384,0.857814,-0.363384,0.546617,0.634327,-0.546617,-0.606739,-0.513535,0.606739,-0.3408,-0.876156,0.3408,0.015259,-0.999756,-0.015259,0.363506,-0.857723,-0.363506,0.61446,-0.494827,-0.61446,0.752556,0.494827,-0.434462,0.866024,0,-0.499985,0.445051,0.857814,-0.256966,0.669454,0.634327,-0.386517,-0.743095,-0.513535,0.429029,-0.417402,-0.876156,0.240974,0.018708,-0.999756,-0.010773,0.445204,-0.857723,-0.257027,0.752556,-0.494827,-0.434462,0.514054,-0.857723,0,0.496536,-0.857723,-0.13303,0.773431,-0.633839,0,0.747124,-0.633808,-0.200171,-0.858028,0.513565,0,-0.828791,0.513535,0.222053,-0.481948,0.876156,0,-0.465529,0.876156,0.124729,0.021577,0.999756,0,0.020844,0.999756,-0.005585,0.514084,0.857723,0,0.496567,0.857723,-0.13303,0.496536,-0.857723,0.13303,0.747032,-0.6339,0.200201,-0.828791,0.513535,-0.222053,-0.465529,0.876156,-0.124729,0.020844,0.999756,0.005585,0.496567,0.857723,0.13303,0.445174,-0.857723,0.257027,0.669515,-0.634022,0.386944,-0.743095,0.513535,-0.428999,-0.417371,0.876156,-0.240974,0.018708,0.999756,0.010804,0.445204,0.857723,0.257027,0.363475,-0.857723,0.363475,0.546525,-0.634114,0.546953,-0.606708,0.513535,-0.606708,-0.3408,0.876156,-0.3408,0.015259,0.999756,0.015259,0.363506,0.857723,0.363506,0.257027,-0.857723,0.445174,0.386578,-0.634175,0.669576,-0.429029,0.513535,-0.743065,-0.240974,0.876156,-0.417402,0.010804,0.999756,0.018708,0.257027,0.857723,0.445204,0.13303,-0.857723,0.496536,0.20011,-0.634175,0.746818,-0.222053,0.513535,-0.828791,-0.124729,0.876156,-0.465529,0.005585,0.999756,0.020844,0.13303,0.857723,0.496567,0,-0.857723,0.514054,0,-0.634175,0.773156,0,0.513565,-0.858028,0,0.876156,-0.481979,0,0.999756,0.021577,0,0.857723,0.514084,-0.13303,-0.857723,0.496536,-0.20011,-0.634175,0.746818,0.222053,0.513535,-0.828791,0.124729,0.876156,-0.465529,-0.005585,0.999756,0.020844,-0.13303,0.857723,0.496567,-0.257027,-0.857723,0.445174,-0.386578,-0.634175,0.669576,0.428999,0.513535,-0.743095,0.240974,0.876156,-0.417371,-0.010804,0.999756,0.018708,-0.257027,0.857723,0.445204,-0.363475,-0.857753,0.363475,-0.546709,-0.634175,0.546709,0.606708,0.513535,-0.606708,0.3408,0.876156,-0.3408,-0.015259,0.999756,0.015259,-0.363506,0.857723,0.363506,-0.752556,-0.494827,0.434462,-0.445174,-0.857753,0.256996,-0.669576,-0.634175,0.386578,0.743095,0.513535,-0.429029,0.417402,0.876156,-0.240974,-0.018708,0.999756,0.010804,-0.445204,0.857723,0.257027,-0.752556,0.494827,0.434492,-0.496536,-0.857753,0.13303,-0.746818,-0.634175,0.20011,0.828791,0.513535,-0.222053,0.465529,0.876156,-0.124729,-0.020844,0.999756,0.005585,-0.496567,0.857723,0.13303,-1,0,0,-0.514054,-0.857723,0,-0.773156,-0.634175,0,0.858028,0.513565,0,0.481948,0.876156,0,-0.021577,0.999756,0,-0.514084,0.857723,0,-0.496536,-0.857723,-0.13303,-0.746666,-0.634297,-0.200354,0.828791,0.513535,0.222053,0.465529,0.876156,0.124729,-0.020844,0.999756,-0.005585,-0.496567,0.857723,-0.13303,-0.445174,-0.857723,-0.257027,-0.669332,-0.634327,-0.3867,0.743095,0.513535,0.428999,0.417402,0.876156,0.240974,-0.018708,0.999756,-0.010773,-0.445204,0.857723,-0.257027,-0.363475,-0.857723,-0.363475,0.606708,0.513535,0.606708,0.3408,0.876156,0.3408,-0.015259,0.999756,-0.015259,-0.363506,0.857723,-0.363506,-0.257027,-0.857723,-0.445174,0.429029,0.513535,0.743095,0.240974,0.876156,0.417402,-0.010773,0.999756,-0.018708,-0.257027,0.857723,-0.445204,-0.13303,-0.857723,-0.496536,0.222053,0.513535,0.828791,0.124729,0.876156,0.465529,-0.005585,0.999756,-0.020844,-0.13303,0.857723,-0.496567,0,-0.857723,-0.514054,0,0.513565,0.858028,0,0.876156,0.481979,0,0.999756,-0.021577,0,0.857723,-0.514084,0.13303,-0.857723,-0.496536,0.20011,-0.633931,-0.747032,-0.222053,0.513535,0.828791,-0.124729,0.876156,0.465529,0.005585,0.999756,-0.020844,0.13303,0.857723,-0.496567,0.257027,-0.857723,-0.445174,0.38667,-0.633869,-0.66982,-0.429029,0.513535,0.743095,-0.240974,0.876156,0.417402,0.010773,0.999756,-0.018708,0.257027,0.857723,-0.445204,0.546892,-0.633808,-0.546922,-0.606739,0.513535,0.606739,-0.3408,0.876156,0.3408,0.015259,0.999756,-0.015259,0.363506,0.857723,-0.363506,0.445174,-0.857723,-0.257027,0.669851,-0.633808,-0.386731,-0.743095,0.513535,0.429029,-0.417402,0.876156,0.240974,0.018708,0.999756,-0.010773,0.445204,0.857723,-0.257027,0.669698,0.720603,-0.179418,0.420148,0.900418,-0.112552,0.43498,0.900418,0,0.693319,0.720603,0,0.912412,0.328196,-0.244453,0.944578,0.328196,0,0.912412,-0.328196,-0.244453,0.944578,-0.328196,0,0.669698,-0.720603,-0.179418,0.693319,-0.720603,0,0.420148,-0.900418,-0.112552,0.43498,-0.900418,0,0.420148,0.900418,0.112552,0.669668,0.720603,0.179418,0.912412,0.328196,0.244484,0.912412,-0.328196,0.244484,0.669668,-0.720603,0.179418,0.420148,-0.900418,0.112552,0.37669,0.900418,0.217475,0.600421,0.720603,0.34666,0.818049,0.328196,0.472304,0.866024,0,0.499985,0.818049,-0.328196,0.472304,0.600421,-0.720603,0.34666,0.37669,-0.900418,0.217475,0.307566,0.900418,0.307566,0.490249,0.720603,0.490249,0.667928,0.328196,0.667928,0.667928,-0.328196,0.667928,0.490249,-0.720603,0.490249,0.307566,-0.900418,0.307566,0.217475,0.900418,0.37669,0.346629,0.720603,0.600421,0.472304,0.328196,0.818049,0.472274,-0.328196,0.818049,0.34666,-0.720603,0.600421,0.217475,-0.900418,0.37669,0.112583,0.900418,0.420148,0.179418,0.720603,0.669668,0.244453,0.328196,0.912412,0.244453,-0.328196,0.912412,0.179418,-0.720603,0.669698,0.112583,-0.900418,0.420148,0,0.900418,0.43498,0,0.720603,0.693319,0,0.328196,0.944578,0,0,1,0,-0.328196,0.944578,0,-0.720603,0.693319,0,-0.900418,0.43498,-0.112552,0.900418,0.420148,-0.179418,0.720603,0.669668,-0.244484,0.328196,0.912412,-0.244484,-0.328196,0.912412,-0.179418,-0.720603,0.669668,-0.112552,-0.900418,0.420148,-0.217475,0.900418,0.37669,-0.34666,0.720603,0.600421,-0.472304,0.328196,0.818049,-0.499985,0,0.866024,-0.472304,-0.328196,0.818049,-0.34666,-0.720603,0.600421,-0.217475,-0.900418,0.37669,-0.307566,0.900418,0.307566,-0.490249,0.720603,0.490249,-0.667928,0.328196,0.667928,-0.667928,-0.328196,0.667928,-0.490249,-0.720603,0.490249,-0.307566,-0.900418,0.307566,-0.37669,0.900418,0.217475,-0.600421,0.720603,0.346629,-0.818049,0.328196,0.472304,-0.818018,-0.328196,0.472304,-0.600421,-0.720603,0.346629,-0.37669,-0.900418,0.217475,-0.420148,0.900418,0.112552,-0.669668,0.720603,0.179418,-0.912412,0.328196,0.244453,-0.912412,-0.328196,0.244453,-0.669668,-0.720603,0.179418,-0.420148,-0.900418,0.112552,-0.43498,0.900418,0,-0.693319,0.720603,0,-0.944578,0.328196,0,-0.944578,-0.328196,0,-0.693319,-0.720603,0,-0.43498,-0.900418,0,-0.420148,0.900418,-0.112552,-0.669668,0.720603,-0.179418,-0.912412,0.328196,-0.244484,-0.912412,-0.328196,-0.244484,-0.669668,-0.720603,-0.179418,-0.420148,-0.900418,-0.112552,-0.37669,0.900418,-0.217475,-0.600421,0.720603,-0.34666,-0.818049,0.328196,-0.472304,-0.818049,-0.328196,-0.472304,-0.600421,-0.720603,-0.34666,-0.37669,-0.900418,-0.217475,-0.307566,0.900418,-0.307566,-0.490249,0.720603,-0.490249,-0.667928,0.328196,-0.667928,-0.667928,-0.328196,-0.667928,-0.490249,-0.720603,-0.490249,-0.307566,-0.900418,-0.307566,-0.217475,0.900418,-0.37669,-0.34666,0.720603,-0.600421,-0.472304,0.328196,-0.818049,-0.472304,-0.328196,-0.818018,-0.346629,-0.720603,-0.600421,-0.217475,-0.900418,-0.37669,-0.112552,0.900418,-0.420148,-0.179418,0.720603,-0.669698,-0.244453,0.328196,-0.912412,-0.244453,-0.328196,-0.912412,-0.179418,-0.720603,-0.669698,-0.112552,-0.900418,-0.420148,0,0.900418,-0.43498,0,0.720603,-0.693319,0,0.328196,-0.944578,0,-0.328196,-0.944578,0,-0.720603,-0.693319,0,-0.900418,-0.43498,0.112552,0.900418,-0.420148,0.179418,0.720603,-0.669698,0.244453,0.328196,-0.912412,0.244453,-0.328196,-0.912412,0.179418,-0.720603,-0.669698,0.112552,-0.900418,-0.420148,0.217475,0.900418,-0.37669,0.34666,0.720603,-0.600421,0.472304,0.328196,-0.818049,0.472304,-0.328196,-0.818049,0.34666,-0.720603,-0.600421,0.217475,-0.900418,-0.37669,0.307566,0.900418,-0.307566,0.490249,0.720603,-0.490249,0.667928,0.328196,-0.667928,0.667928,-0.328196,-0.667928,0.490249,-0.720603,-0.490249,0.307566,-0.900418,-0.307566,0.37669,0.900418,-0.217475,0.600421,0.720603,-0.34666,0.818049,0.328196,-0.472304,0.818049,-0.328196,-0.472304,0.600421,-0.720603,-0.34666,0.37669,-0.900418,-0.217475,0.669668,0.720634,-0.179418,0.420026,0.900479,-0.112522,0.434858,0.900479,0,0.693289,0.720634,0,0.912412,0.328166,-0.244453,0.944609,0.328166,0,0.669668,-0.720603,-0.179418,0.420026,0.900479,0.112522,0.669668,0.720634,0.179418,0.912412,0.328166,0.244484,0.376598,0.900479,0.217414,0.600391,0.720634,0.346629,0.818049,0.328166,0.472304,0.307474,0.900479,0.307474,0.490219,0.720634,0.490219,0.667928,0.328166,0.667928,0.217414,0.900479,0.376598,0.346629,0.720634,0.600391,0.472304,0.328166,0.818049,0.112552,0.900479,0.420026,0.179418,0.720634,0.669668,0.244453,0.328166,0.912412,0.112552,-0.900418,0.420148,0,0.900479,0.434858,0,0.720634,0.693289,0,0.328166,0.944609,-0.112522,0.900479,0.420026,-0.179418,0.720634,0.669668,-0.244484,0.328166,0.912412,-0.217414,0.900479,0.376598,-0.346629,0.720634,0.600391,-0.472304,0.328166,0.818049,-0.307474,0.900479,0.307474,-0.490219,0.720634,0.490219,-0.667928,0.328166,0.667928,-0.376598,0.900479,0.217414,-0.600391,0.720634,0.346629,-0.818049,0.328166,0.472304,-0.818049,-0.328196,0.472274,-0.600421,-0.720603,0.34666,-0.420026,0.900479,0.112552,-0.669668,0.720634,0.179418,-0.912412,0.328166,0.244453,-0.669698,-0.720603,0.179418,-0.434858,0.900479,0,-0.693289,0.720634,0,-0.944609,0.328166,0,-0.420026,0.900479,-0.112522,-0.669668,0.720634,-0.179418,-0.912412,0.328166,-0.244484,-0.376598,0.900479,-0.217414,-0.600391,0.720634,-0.346629,-0.818049,0.328166,-0.472304,-0.307474,0.900479,-0.307474,-0.490219,0.720634,-0.490219,-0.667928,0.328166,-0.667928,-0.217414,0.900479,-0.376598,-0.346629,0.720634,-0.600391,-0.112522,0.900479,-0.420026,-0.179418,0.720664,-0.669637,-0.179418,-0.720603,-0.669668,0,0.900479,-0.434858,0,0.720664,-0.693258,0.112522,0.900479,-0.420026,0.179418,0.720664,-0.669637,0.179418,-0.720603,-0.669668,0.217414,0.900479,-0.376598,0.346629,0.720634,-0.600391,0.307474,0.900479,-0.307474,0.490219,0.720634,-0.490219,0.667928,0.328166,-0.667928,0.376598,0.900479,-0.217414,0.600391,0.720634,-0.346629,0.818049,0.328166,-0.472304,0.203497,0.957671,-0.203497,0.28779,0.957671,0,0.107883,0.99414,0,0.076296,0.99414,-0.076296,0,0.957671,-0.28779,0,0.99414,-0.107883,-0.203497,0.957671,-0.203497,-0.076296,0.99414,-0.076296,-0.28779,0.957671,0,-0.107883,0.99414,0,-0.203497,0.957671,0.203497,-0.076296,0.99414,0.076296,0,0.957671,0.28779,0,0.99414,0.107883,0.203497,0.957671,0.203497,0.076296,0.99414,0.076296,-0.056978,0.99762,0.038057,0.056978,0.99762,0.038057,0.067202,0.99762,0.013337,-0.067202,0.99762,0.013337,0.850612,0.525773,0,0.601459,0.525773,-0.601459,0,0.525773,-0.850612,-0.601459,0.525773,-0.601459,-0.850612,0.525773,0,-0.601459,0.525773,0.601459,0,0.525773,0.850612,0.601459,0.525773,0.601459,0.548967,0.630238,-0.548967,0.77636,0.630238,0,0,0.630238,-0.77636,-0.548967,0.630238,-0.548967,-0.77636,0.630238,0,-0.548967,0.630238,0.548967,0,0.630238,0.77636,0.548967,0.630238,0.548967,0.546373,0.753746,-0.365062,0.64452,0.753746,-0.128178,0.128178,0.753746,-0.64449,0.365062,0.753746,-0.546373,-0.365062,0.753746,-0.546373,-0.128178,0.753746,-0.64449,-0.64452,0.753746,-0.128178,-0.546373,0.753746,-0.365062,-0.546373,0.753746,0.365062,-0.64452,0.753746,0.128178,-0.128178,0.753746,0.64449,-0.365062,0.753746,0.546373,0.365062,0.753746,0.546373,0.128178,0.753746,0.64449,0.64452,0.753746,0.128178,0.546373,0.753746,0.365062,0.546373,-0.753746,-0.365062,0.64452,-0.753746,-0.128178,0.365062,-0.753746,-0.546373,0.128178,-0.753746,-0.64452,-0.128178,-0.753746,-0.64452,-0.365062,-0.753746,-0.546373,-0.546373,-0.753746,-0.365062,-0.64452,-0.753746,-0.128178,-0.64452,-0.753746,0.128178,-0.546373,-0.753746,0.365062,-0.365062,-0.753746,0.546373,-0.128178,-0.753746,0.64452,0.128178,-0.753746,0.64452,0.365062,-0.753746,0.546373,0.546373,-0.753746,0.365062,0.64452,-0.753746,0.128178,0.620441,-0.6657,-0.414563,0.731864,-0.6657,-0.145573,0.414563,-0.6657,-0.620441,0.145573,-0.6657,-0.731864,-0.145573,-0.6657,-0.731864,-0.414563,-0.6657,-0.620441,-0.620441,-0.6657,-0.414563,-0.731834,-0.6657,-0.145573,-0.731864,-0.6657,0.145573,-0.620441,-0.6657,0.414563,-0.414563,-0.6657,0.620441,-0.145573,-0.6657,0.731834,0.145573,-0.6657,0.731834,0.414563,-0.6657,0.620441,0.620441,-0.6657,0.414563,0.731834,-0.6657,0.145573,0.719352,0.501419,-0.480667,0.848537,0.501419,-0.168767,0.480667,0.501419,-0.719352,0.168767,0.501419,-0.848537,-0.168767,0.501419,-0.848537,-0.480667,0.501419,-0.719352,-0.719352,0.501419,-0.480667,-0.848537,0.501419,-0.168767,-0.848537,0.501419,0.168767,-0.719352,0.501419,0.480667,-0.480667,0.501419,0.719352,-0.168767,0.501419,0.848537,0.168767,0.501419,0.848537,0.480667,0.501419,0.719352,0.719352,0.501419,0.480667,0.848537,0.501419,0.168767,0.252602,0.952727,-0.168767,0.297952,0.952727,-0.059236,0.168767,0.952727,-0.252602,0.059267,0.952727,-0.297952,-0.059267,0.952727,-0.297952,-0.168767,0.952727,-0.252602,-0.252602,0.952727,-0.168767,-0.297952,0.952727,-0.059236,-0.297952,0.952727,0.059236,-0.252602,0.952727,0.168767,-0.168767,0.952727,0.252602,-0.059267,0.952727,0.297952,0.059267,0.952727,0.297952,0.168767,0.952727,0.252602,0.252602,0.952727,0.168767,0.297952,0.952727,0.059236,0.056978,0.99762,-0.038057,0.067202,0.99762,-0.013337,0.038057,0.99762,-0.056978,0.013367,0.99762,-0.067202,-0.013367,0.99762,-0.067202,-0.038057,0.99762,-0.056978,-0.056978,0.99762,-0.038057,-0.067202,0.99762,-0.013337,-0.038057,0.99762,0.056978,-0.013367,0.99762,0.067202,0.013367,0.99762,0.067202,0.038057,0.99762,0.056978,0.321238,0.766228,-0.556444,0.642537,0.766228,0,0.309641,0.950835,0,0.15482,0.950835,-0.268166,-0.321238,0.766228,-0.556444,-0.15482,0.950835,-0.268166,-0.642537,0.766228,0,-0.309641,0.950835,0,-0.321238,0.766228,0.556444,-0.15482,0.950835,0.268166,0.321238,0.766228,0.556444,0.15482,0.950835,0.268166,-0.411206,0.904813,0.110233,-0.301035,0.904843,0.301035,-0.110172,0.904843,0.411206,-0.301004,0.904843,-0.301004,0.110172,0.904843,0.411206,0.301035,0.904843,0.301004,0.411206,0.904843,-0.110202,0.411206,0.904813,0.110233,0.301004,0.904843,-0.301004,0.110172,0.904843,-0.411206,-0.110172,0.904843,-0.411206,-0.411206,0.904843,-0.110202,0.718741,0.695242,0,0.359355,0.695273,-0.622425,-0.359355,0.695273,-0.622425,-0.718741,0.695242,0,-0.359355,0.695273,0.622425,0.359355,0.695273,0.622425,0.450942,0.770257,-0.450911,0.615986,0.770257,-0.165014,-0.165075,0.770257,-0.615955,0.165075,0.770257,-0.615955,-0.615986,0.770257,-0.165044,-0.450942,0.770226,-0.450911,-0.450942,0.770226,0.450942,-0.615955,0.770257,0.165044,0.165075,0.770257,0.615955,-0.165075,0.770257,0.615955,0.615955,0.770257,0.165075,0.450942,0.770226,0.450942,0.357036,0.863155,-0.356975,0.487686,0.863155,-0.13068,0.13068,0.863124,-0.487716,-0.13068,0.863124,-0.487716,-0.357006,0.863155,-0.357006,-0.487686,0.863155,-0.130711,-0.487747,0.863124,0.13068,-0.357006,0.863155,0.357006,-0.13068,0.863124,0.487716,0.13068,0.863124,0.487716,0.356975,0.863155,0.357006,0.487716,0.863124,0.130711,0.218604,0.005799,0.975768,0.229835,-0.354106,0.906491,0.214881,-0.157933,0.963775,0.452345,-0.164342,0.876553,0.252571,-0.209174,0.94467,0.308786,-0.128513,0.942381,-0.852687,0.238014,0.46498,-0.998749,0.033082,0.036775,-0.999756,0.018159,0.012024,-0.948698,0.103549,0.298654,-0.800989,0.351756,0.48442,-0.861934,0.161321,0.480636,-0.804163,0.158574,0.572832,-0.744682,0.095462,0.660512,-0.220191,-0.041292,0.974578,0.034303,-0.187902,0.981567,0.685812,-0.030702,0.727103,0.259285,-0.000732,0.965789,-0.218085,0.041475,0.975036,0.685568,0.030274,0.727348,0.93408,-0.207648,-0.290353,0.781152,-0.065493,-0.620838,0.831813,-0.372417,-0.411512,0.908872,-0.01883,-0.416608,0.832667,-0.26722,-0.48497,0.726127,-0.530351,-0.437513,0.853023,-0.067904,-0.517411,0.728813,-0.198309,-0.655324,0.934629,-0.069948,-0.348613,0.762841,-0.398267,-0.509323,-0.965789,-0.000397,-0.259255,-0.500168,-0.000214,0.865902,-0.998688,0.004212,0.050691,-0.998871,-0.024415,0.040315,-0.991424,0,-0.130497,-0.999725,-0.016053,0.016541,-0.950499,-0.073428,0.301889,-0.760979,0.039521,0.647542,-0.860988,-0.170598,0.47911,-0.866756,-0.108127,0.486801,-0.825556,-0.258492,0.501602,-0.74987,0.040681,0.660298,-0.760338,-0.08179,0.644307,-0.845668,0.018372,0.533372,-0.818323,-0.116794,0.562731,-0.608753,0,0.793329],
+
+"colors" : [],
+
+"uvs" : [[0.3286,0.7764,0.468,0.7764,0.468,0.739,0.3237,0.739,0.161,0.741,0.3054,0.741,0.3004,0.7784,0.161,0.7784,0.3004,0.7037,0.161,0.7036,0.286,0.8132,0.161,0.8132,0.2631,0.8431,0.161,0.8431,0.2332,0.866,0.161,0.8661,0.1984,0.8804,0.161,0.8853,0.286,0.6689,0.161,0.6688,0.2631,0.639,0.161,0.6389,0.2332,0.616,0.161,0.6159,0.1984,0.6016,0.161,0.5967,0.1237,0.8804,0.0889,0.866,0.059,0.8431,0.0361,0.8132,0.0216,0.7784,0.0167,0.741,0.0216,0.7037,0.0361,0.6689,0.059,0.639,0.0889,0.616,0.1237,0.6016,0.3286,0.7017,0.468,0.7017,0.343,0.8112,0.468,0.8112,0.3659,0.8411,0.468,0.8412,0.3958,0.864,0.468,0.8641,0.4306,0.8784,0.468,0.8834,0.343,0.6669,0.468,0.6668,0.3659,0.637,0.468,0.6369,0.3958,0.6141,0.468,0.614,0.4306,0.5996,0.468,0.5947,0.5053,0.8784,0.5401,0.864,0.57,0.8411,0.593,0.8112,0.6074,0.7764,0.6123,0.739,0.6074,0.7017,0.593,0.6669,0.57,0.637,0.5401,0.6141,0.5053,0.5996,0.0589,0.0562,0.0578,0.0884,0.0209,0.0568,0.1003,0.0541,0.0996,0.089,0.1422,0.0563,0.1415,0.0885,0.1792,0.0599,0.1594,0.1231,0.1793,0.0557,0.2186,0.1693,0.1776,0.1692,0.2203,0.055,0.2601,0.0547,0.2594,0.1693,0.2613,0.4672,0.3001,0.1692,0.3016,0.4672,0.3407,0.1691,0.3418,0.4671,0.3813,0.1691,0.3819,0.4671,0.3815,0.0549,0.4218,0.0548,0.4218,0.169,0.462,0.0547,0.4621,0.1689,0.5021,0.0545,0.5021,0.1687,0.5421,0.0544,0.5421,0.1685,0.5821,0.0543,0.5822,0.1683,0.6221,0.0543,0.6224,0.1684,0.6621,0.0542,0.6628,0.1685,0.702,0.0537,0.703,0.1682,0.7421,0.053,0.7429,0.1669,0.7853,0.214,0.7413,0.2301,0.7435,0.1974,0.7825,0.1965,0.8214,0.1977,0.8252,0.2383,0.8225,0.1669,0.8226,0.0529,0.8628,0.0534,0.8624,0.1679,0.9033,0.0534,0.9028,0.1679,0.9441,0.0531,0.9439,0.1678,0.9853,0.0578,0.9848,0.1677,0.9851,0.0533,0.0209,0.0439,0.0209,0.0392,0.0589,0.0392,0.0589,0.0435,0.0209,0.0484,0.0589,0.0477,0.0209,0.0528,0.0589,0.0522,0.021,0.018,0.021,0.0141,0.0593,0.0141,0.0593,0.0184,0.021,0.0216,0.0592,0.0225,0.021,0.0256,0.0591,0.0267,0.0209,0.0298,0.059,0.031,0.0209,0.0343,0.0589,0.0351,0.9441,0.0442,0.9441,0.0397,0.9851,0.0384,0.9851,0.0436,0.9441,0.0485,0.9851,0.0485,0.9442,0.0173,0.9442,0.0129,0.9851,0.0126,0.9851,0.0165,0.9442,0.0216,0.9851,0.0203,0.9442,0.0261,0.9851,0.0244,0.9441,0.0307,0.9851,0.0288,0.9441,0.0352,0.9851,0.0334,0.9033,0.0443,0.9033,0.0398,0.9033,0.0488,0.9031,0.0175,0.9031,0.0129,0.9031,0.022,0.9032,0.0265,0.9032,0.031,0.9032,0.0353,0.8628,0.0443,0.8628,0.0397,0.8628,0.0488,0.8628,0.0173,0.8628,0.0127,0.8628,0.0218,0.8628,0.0263,0.8628,0.0309,0.8628,0.0352,0.8225,0.0442,0.8225,0.0398,0.8226,0.0485,0.8222,0.0179,0.8222,0.0134,0.8223,0.0222,0.8223,0.0267,0.8224,0.0311,0.8225,0.0354,0.7823,0.0438,0.7823,0.0394,0.7823,0.0482,0.7823,0.0526,0.7821,0.0174,0.7821,0.0128,0.7822,0.0217,0.7822,0.0262,0.7822,0.0307,0.7823,0.035,0.7421,0.0442,0.7421,0.0397,0.7421,0.0485,0.7419,0.0176,0.7419,0.0131,0.7419,0.022,0.742,0.0264,0.742,0.0309,0.742,0.0353,0.702,0.0449,0.7018,0.0403,0.702,0.0492,0.7011,0.018,0.701,0.0134,0.7012,0.0224,0.7014,0.0269,0.7015,0.0314,0.7017,0.0358,0.6619,0.0453,0.6618,0.0407,0.662,0.0497,0.6613,0.0183,0.6612,0.0138,0.6614,0.0227,0.6615,0.0273,0.6616,0.0318,0.6617,0.0362,0.6219,0.0455,0.6218,0.041,0.622,0.0498,0.6214,0.0186,0.6214,0.0141,0.6215,0.023,0.6215,0.0275,0.6216,0.0321,0.6217,0.0365,0.5819,0.0455,0.5818,0.041,0.582,0.0498,0.5815,0.0187,0.5815,0.0141,0.5815,0.0231,0.5816,0.0276,0.5817,0.0321,0.5817,0.0365,0.5419,0.0455,0.5418,0.0411,0.542,0.0499,0.5416,0.0187,0.5416,0.0142,0.5416,0.0231,0.5416,0.0276,0.5417,0.0321,0.5417,0.0365,0.5018,0.0456,0.5018,0.0411,0.5019,0.05,0.5016,0.0187,0.5016,0.0142,0.5016,0.0231,0.5017,0.0277,0.5017,0.0322,0.5017,0.0366,0.4617,0.0457,0.4617,0.0412,0.4618,0.0501,0.4617,0.0188,0.4617,0.0143,0.4617,0.0232,0.4617,0.0277,0.4617,0.0323,0.4617,0.0366,0.4216,0.0458,0.4216,0.0412,0.4217,0.0502,0.4217,0.0188,0.4217,0.0143,0.4217,0.0232,0.4217,0.0278,0.4217,0.0323,0.4216,0.0367,0.3815,0.0458,0.3815,0.0413,0.3815,0.0503,0.3818,0.0189,0.3818,0.0143,0.3818,0.0233,0.3817,0.0278,0.3817,0.0324,0.3816,0.0367,0.3409,0.0457,0.341,0.0411,0.3408,0.05,0.3408,0.0546,0.3415,0.0187,0.3415,0.0141,0.3414,0.0231,0.3413,0.0276,0.3412,0.0322,0.3411,0.0366,0.3007,0.0457,0.3008,0.0412,0.3005,0.0501,0.3004,0.0546,0.3016,0.0188,0.3017,0.0142,0.3015,0.0232,0.3014,0.0277,0.3012,0.0323,0.301,0.0367,0.2604,0.0458,0.2607,0.0412,0.2603,0.0501,0.2618,0.0187,0.2619,0.0142,0.2617,0.0231,0.2614,0.0277,0.2612,0.0323,0.2609,0.0367,0.2208,0.046,0.2211,0.0414,0.2206,0.0504,0.2227,0.0187,0.2229,0.0142,0.2225,0.0232,0.2221,0.0278,0.2218,0.0324,0.2214,0.0369,0.1794,0.0466,0.1795,0.0419,0.1793,0.0511,0.1803,0.0186,0.1804,0.014,0.1802,0.0232,0.18,0.0279,0.1798,0.0326,0.1797,0.0372,0.1423,0.0436,0.1423,0.0392,0.1422,0.0479,0.1422,0.0524,0.1429,0.0187,0.1429,0.0143,0.1428,0.0229,0.1427,0.0271,0.1425,0.0312,0.1424,0.0351,0.1003,0.0433,0.1003,0.0393,0.1002,0.047,0.1003,0.0509,0.1006,0.0186,0.1006,0.0143,0.1005,0.0227,0.1004,0.027,0.1004,0.0311,0.1003,0.0351,0.0174,0.4776,0.0589,0.4767,0.0589,0.4811,0.0174,0.4827,0.0174,0.4728,0.0589,0.4723,0.0174,0.468,0.0589,0.4676,0.0177,0.504,0.0591,0.5038,0.0591,0.5082,0.0178,0.5079,0.0177,0.5003,0.059,0.4994,0.0176,0.4964,0.059,0.4949,0.0175,0.4921,0.0589,0.4902,0.0174,0.4876,0.0589,0.4857,0.9407,0.4755,0.9856,0.4759,0.9856,0.4811,0.9407,0.4801,0.9407,0.4711,0.9856,0.471,0.9407,0.4664,0.9856,0.4661,0.9404,0.5028,0.9856,0.5035,0.9856,0.5075,0.9403,0.5073,0.9404,0.4985,0.9857,0.4996,0.9405,0.4939,0.9858,0.4954,0.9406,0.4892,0.9855,0.4909,0.9407,0.4847,0.9856,0.4862,0.9012,0.4754,0.9012,0.48,0.9012,0.4709,0.9012,0.4662,0.9009,0.5026,0.9008,0.5072,0.9009,0.4981,0.901,0.4935,0.9011,0.4889,0.9012,0.4846,0.861,0.4753,0.8611,0.4799,0.8611,0.4709,0.8611,0.4662,0.8617,0.5028,0.8617,0.5074,0.8616,0.4983,0.8614,0.4936,0.8613,0.489,0.8612,0.4845,0.8227,0.4764,0.8225,0.4808,0.8227,0.472,0.8227,0.4676,0.8207,0.503,0.8206,0.5075,0.8209,0.4986,0.8213,0.4941,0.8218,0.4896,0.8222,0.4853,0.7826,0.477,0.7824,0.4814,0.7826,0.4727,0.7827,0.4683,0.7811,0.5034,0.781,0.5079,0.7813,0.499,0.7816,0.4946,0.7819,0.4901,0.7821,0.4859,0.7425,0.4768,0.7423,0.4812,0.7427,0.4724,0.7427,0.4679,0.7414,0.5033,0.7414,0.5078,0.7415,0.4989,0.7417,0.4945,0.7419,0.49,0.7422,0.4857,0.7025,0.4759,0.7024,0.4804,0.7027,0.4715,0.703,0.467,0.7016,0.503,0.7016,0.5075,0.7017,0.4986,0.7019,0.494,0.702,0.4894,0.7022,0.485,0.6625,0.4758,0.6624,0.4803,0.6627,0.4714,0.663,0.4668,0.6618,0.5029,0.6618,0.5075,0.6619,0.4985,0.662,0.4939,0.6621,0.4893,0.6622,0.4849,0.6225,0.4763,0.6224,0.4808,0.6226,0.472,0.6227,0.4675,0.622,0.5031,0.6219,0.5076,0.622,0.4987,0.6221,0.4942,0.6222,0.4897,0.6223,0.4853,0.5824,0.4764,0.5823,0.4808,0.5825,0.4721,0.5826,0.4676,0.5821,0.5031,0.582,0.5076,0.5821,0.4987,0.5821,0.4942,0.5822,0.4897,0.5823,0.4853,0.5424,0.4763,0.5423,0.4808,0.5425,0.472,0.5425,0.4676,0.5421,0.5031,0.5421,0.5076,0.5422,0.4987,0.5422,0.4942,0.5422,0.4897,0.5423,0.4853,0.5023,0.4762,0.5023,0.4807,0.5024,0.4718,0.5025,0.4673,0.5022,0.5031,0.5022,0.5076,0.5022,0.4987,0.5022,0.4942,0.5022,0.4896,0.5023,0.4853,0.4623,0.4761,0.4622,0.4807,0.4623,0.4717,0.4624,0.4671,0.4623,0.5031,0.4623,0.5076,0.4623,0.4987,0.4622,0.4941,0.4622,0.4896,0.4622,0.4852,0.4222,0.4761,0.4222,0.4806,0.4222,0.4716,0.4222,0.4671,0.4223,0.503,0.4223,0.5076,0.4223,0.4986,0.4223,0.4941,0.4222,0.4896,0.4222,0.4852,0.382,0.4761,0.3821,0.4806,0.382,0.4716,0.3824,0.503,0.3824,0.5076,0.3824,0.4986,0.3823,0.4941,0.3822,0.4895,0.3822,0.4851,0.3419,0.476,0.342,0.4805,0.3418,0.4716,0.3425,0.5029,0.3425,0.5075,0.3425,0.4985,0.3424,0.494,0.3422,0.4894,0.3421,0.485,0.3017,0.476,0.3019,0.4806,0.3016,0.4717,0.3027,0.5029,0.3027,0.5075,0.3026,0.4985,0.3024,0.494,0.3022,0.4895,0.3021,0.4851,0.2615,0.4761,0.2617,0.4806,0.2614,0.4717,0.2629,0.503,0.263,0.5076,0.2627,0.4986,0.2625,0.4941,0.2622,0.4895,0.262,0.4851,0.2213,0.4762,0.2216,0.4808,0.2211,0.4719,0.221,0.4673,0.2232,0.5033,0.2233,0.5079,0.223,0.4989,0.2226,0.4943,0.2222,0.4897,0.2219,0.4853,0.1804,0.476,0.1806,0.4805,0.1803,0.4715,0.1803,0.467,0.1817,0.5033,0.1818,0.5079,0.1815,0.4988,0.1813,0.4942,0.181,0.4896,0.1808,0.4851,0.1399,0.4764,0.14,0.481,0.1398,0.4718,0.1398,0.467,0.1407,0.5033,0.1407,0.5079,0.1406,0.4988,0.1404,0.4943,0.1402,0.4898,0.1401,0.4855,0.0995,0.4769,0.0996,0.4813,0.0995,0.4726,0.0995,0.4681,0.1007,0.5035,0.1007,0.5081,0.1005,0.4991,0.1002,0.4945,0.1,0.4901,0.0997,0.4858,0.9693,0.5432,0.9687,0.5463,0.93,0.5462,0.9301,0.5432,0.9699,0.5392,0.9303,0.5392,0.9701,0.5343,0.9304,0.5343,0.9699,0.5294,0.9303,0.5294,0.9693,0.5254,0.9301,0.5254,0.9687,0.5223,0.93,0.5224,0.8908,0.5462,0.8909,0.5432,0.8909,0.5392,0.891,0.5343,0.8909,0.5294,0.8909,0.5254,0.8908,0.5223,0.8516,0.5462,0.8516,0.5432,0.8516,0.5392,0.8516,0.5343,0.8516,0.5294,0.8516,0.5254,0.8516,0.5223,0.8122,0.5462,0.8123,0.5432,0.8123,0.5392,0.8123,0.5343,0.8123,0.5294,0.8123,0.5254,0.8122,0.5223,0.7729,0.5462,0.7729,0.5432,0.7729,0.5392,0.7729,0.5343,0.7729,0.5294,0.7729,0.5254,0.7729,0.5223,0.7336,0.5462,0.7336,0.5432,0.7336,0.5392,0.7336,0.5343,0.7336,0.5294,0.7336,0.5254,0.7336,0.5223,0.6943,0.5462,0.6943,0.5432,0.6943,0.5392,0.6943,0.5343,0.6943,0.5294,0.6943,0.5254,0.6943,0.5223,0.655,0.5462,0.655,0.5432,0.655,0.5392,0.655,0.5343,0.655,0.5294,0.655,0.5254,0.655,0.5223,0.6157,0.5462,0.6157,0.5432,0.6157,0.5392,0.6157,0.5343,0.6157,0.5294,0.6157,0.5254,0.6157,0.5223,0.5763,0.5462,0.5763,0.5432,0.5763,0.5392,0.5763,0.5343,0.5763,0.5294,0.5763,0.5254,0.5763,0.5223,0.537,0.5462,0.537,0.5432,0.537,0.5392,0.537,0.5343,0.537,0.5294,0.537,0.5254,0.537,0.5223,0.4977,0.5462,0.4977,0.5432,0.4977,0.5392,0.4977,0.5343,0.4977,0.5294,0.4977,0.5254,0.4977,0.5223,0.4584,0.5462,0.4584,0.5432,0.4584,0.5392,0.4584,0.5343,0.4584,0.5294,0.4584,0.5254,0.4584,0.5223,0.4191,0.5462,0.4191,0.5432,0.4191,0.5392,0.4191,0.5343,0.4191,0.5294,0.4191,0.5254,0.4191,0.5223,0.3798,0.5462,0.3798,0.5432,0.3798,0.5392,0.3798,0.5343,0.3798,0.5294,0.3798,0.5254,0.3798,0.5223,0.3404,0.5462,0.3404,0.5432,0.3404,0.5392,0.3404,0.5343,0.3404,0.5294,0.3404,0.5254,0.3404,0.5223,0.3011,0.5463,0.3011,0.5432,0.3011,0.5392,0.3011,0.5343,0.3011,0.5294,0.3011,0.5254,0.3011,0.5223,0.2618,0.5462,0.2618,0.5432,0.2618,0.5392,0.2618,0.5343,0.2618,0.5294,0.2618,0.5254,0.2618,0.5223,0.2225,0.5462,0.2225,0.5432,0.2225,0.5392,0.2225,0.5343,0.2225,0.5294,0.2225,0.5254,0.2225,0.5223,0.1832,0.5462,0.1832,0.5432,0.1832,0.5392,0.1832,0.5343,0.1832,0.5294,0.1832,0.5254,0.1832,0.5223,0.1439,0.5462,0.1439,0.5432,0.1438,0.5392,0.1438,0.5343,0.1438,0.5294,0.1439,0.5254,0.1439,0.5223,0.1046,0.5462,0.1046,0.5432,0.1045,0.5392,0.1045,0.5343,0.1045,0.5294,0.1046,0.5254,0.1046,0.5223,0.0654,0.5462,0.0653,0.5432,0.0651,0.5392,0.065,0.5343,0.0651,0.5294,0.0653,0.5254,0.0654,0.5224,0.0267,0.5463,0.0261,0.5432,0.0255,0.5392,0.0253,0.5343,0.0255,0.5294,0.0261,0.5254,0.0267,0.5223,0.9709,0.5783,0.9704,0.5813,0.9316,0.5813,0.9317,0.5782,0.9715,0.5742,0.932,0.5742,0.9718,0.5693,0.9321,0.5693,0.9715,0.5644,0.932,0.5644,0.9709,0.5604,0.9317,0.5604,0.9704,0.5573,0.9316,0.5574,0.8925,0.5813,0.8925,0.5782,0.8926,0.5742,0.8926,0.5693,0.8926,0.5644,0.8925,0.5604,0.8925,0.5574,0.8532,0.5813,0.8532,0.5782,0.8532,0.5742,0.8532,0.5693,0.8532,0.5644,0.8532,0.5604,0.8532,0.5574,0.8139,0.5813,0.8139,0.5782,0.8139,0.5742,0.8139,0.5693,0.8139,0.5644,0.8139,0.5604,0.8139,0.5574,0.7746,0.5813,0.7746,0.5782,0.7746,0.5742,0.7746,0.5693,0.7746,0.5644,0.7746,0.5604,0.7746,0.5574,0.7352,0.5813,0.7353,0.5782,0.7353,0.5742,0.7353,0.5693,0.7353,0.5644,0.7352,0.5604,0.7352,0.5574,0.6959,0.5813,0.6959,0.5782,0.6959,0.5742,0.6959,0.5693,0.6959,0.5644,0.6959,0.5604,0.6959,0.5574,0.6566,0.5813,0.6566,0.5782,0.6566,0.5742,0.6566,0.5693,0.6566,0.5644,0.6566,0.5604,0.6566,0.5574,0.6173,0.5813,0.6173,0.5782,0.6173,0.5742,0.6173,0.5693,0.6173,0.5644,0.6173,0.5604,0.6173,0.5574,0.578,0.5813,0.578,0.5782,0.578,0.5742,0.578,0.5693,0.578,0.5644,0.578,0.5604,0.578,0.5574,0.5387,0.5813,0.5387,0.5782,0.5387,0.5742,0.5387,0.5693,0.5387,0.5644,0.5387,0.5604,0.5387,0.5574,0.4993,0.5813,0.4993,0.5782,0.4993,0.5742,0.4993,0.5693,0.4993,0.5644,0.4993,0.5604,0.4993,0.5574,0.46,0.5813,0.46,0.5782,0.46,0.5742,0.46,0.5693,0.46,0.5644,0.46,0.5604,0.46,0.5574,0.4207,0.5813,0.4207,0.5782,0.4207,0.5742,0.4207,0.5693,0.4207,0.5644,0.4207,0.5604,0.4207,0.5574,0.3814,0.5813,0.3814,0.5782,0.3814,0.5742,0.3814,0.5693,0.3814,0.5644,0.3814,0.5604,0.3814,0.5574,0.3421,0.5813,0.3421,0.5782,0.3421,0.5742,0.3421,0.5693,0.3421,0.5644,0.3421,0.5604,0.3421,0.5574,0.3028,0.5813,0.3028,0.5782,0.3027,0.5742,0.3027,0.5693,0.3027,0.5644,0.3028,0.5604,0.3028,0.5574,0.2634,0.5813,0.2634,0.5782,0.2634,0.5742,0.2634,0.5693,0.2634,0.5644,0.2634,0.5604,0.2634,0.5574,0.2241,0.5813,0.2241,0.5782,0.2241,0.5742,0.2241,0.5693,0.2241,0.5644,0.2241,0.5604,0.2241,0.5574,0.1848,0.5813,0.1848,0.5782,0.1848,0.5742,0.1848,0.5693,0.1848,0.5644,0.1848,0.5604,0.1848,0.5574,0.1455,0.5813,0.1455,0.5782,0.1455,0.5742,0.1455,0.5693,0.1455,0.5644,0.1455,0.5604,0.1455,0.5574,0.1062,0.5813,0.1062,0.5782,0.1061,0.5742,0.1061,0.5693,0.1061,0.5644,0.1062,0.5604,0.1062,0.5574,0.0671,0.5813,0.0669,0.5782,0.0667,0.5742,0.0666,0.5693,0.0667,0.5644,0.0669,0.5604,0.0671,0.5574,0.0283,0.5813,0.0278,0.5783,0.0272,0.5742,0.0269,0.5693,0.0272,0.5644,0.0278,0.5604,0.0283,0.5573,0.6842,0.786,0.7535,0.8145,0.7535,0.839,0.6669,0.8034,0.6553,0.7168,0.6309,0.7168,0.6842,0.6477,0.6669,0.6303,0.7535,0.6192,0.7535,0.5947,0.8229,0.6477,0.8402,0.6303,0.8517,0.7168,0.8762,0.7168,0.8229,0.786,0.8402,0.8034,0.8735,0.8886,0.9244,0.8886,0.9281,0.8972,0.8699,0.8972,0.7535,0.8036,0.6919,0.7783,0.6663,0.7168,0.6919,0.6554,0.7535,0.6301,0.8151,0.6554,0.8408,0.7168,0.8151,0.7783,0.6976,0.7726,0.7535,0.7956,0.6742,0.7168,0.6976,0.6611,0.7535,0.6381,0.8095,0.6611,0.8329,0.7168,0.8095,0.7726,0.6748,0.9656,0.6933,0.9647,0.7128,0.9728,0.7252,0.9865,0.6539,0.9152,0.6677,0.9277,0.6757,0.9471,0.6748,0.8648,0.6757,0.8833,0.6677,0.9028,0.7252,0.844,0.7128,0.8577,0.6933,0.8658,0.7756,0.8648,0.7571,0.8658,0.7376,0.8577,0.7965,0.9152,0.7828,0.9028,0.7747,0.8833,0.7756,0.9656,0.7747,0.9471,0.7828,0.9277,0.7376,0.9728,0.7571,0.9647,0.4007,0.8913,0.4007,0.8949,0.3909,0.8949,0.3909,0.8913,0.2418,0.8913,0.2418,0.895,0.2303,0.895,0.2303,0.8914,0.2516,0.8913,0.2516,0.895,0.2631,0.8913,0.2631,0.895,0.2729,0.8913,0.2729,0.895,0.2844,0.8913,0.2844,0.895,0.2942,0.8913,0.2942,0.895,0.3057,0.8913,0.3057,0.895,0.3155,0.8913,0.3155,0.895,0.327,0.8913,0.327,0.895,0.3368,0.8913,0.3368,0.895,0.3483,0.8913,0.3483,0.8949,0.3581,0.8913,0.3581,0.8949,0.3696,0.8913,0.3696,0.8949,0.3794,0.8913,0.3794,0.8949,0.9704,0.7665,0.977,0.7709,0.9821,0.7585,0.9744,0.757,0.9619,0.7751,0.9662,0.7816,0.9524,0.779,0.9539,0.7867,0.9402,0.779,0.9387,0.7867,0.9308,0.7751,0.9264,0.7816,0.9222,0.7665,0.9156,0.7709,0.9182,0.757,0.9105,0.7585,0.9182,0.7449,0.9105,0.7433,0.9222,0.7354,0.9156,0.731,0.9308,0.7268,0.9264,0.7203,0.9402,0.7229,0.9387,0.7152,0.9524,0.7229,0.9539,0.7152,0.9619,0.7268,0.9662,0.7203,0.9704,0.7354,0.977,0.731,0.9744,0.7449,0.9821,0.7433,0.0489,0.9426,0.0489,0.9733,0.0225,0.9733,0.0225,0.9426,0.0789,0.9426,0.0789,0.9733,0.1053,0.9426,0.1053,0.9733,0.1354,0.9426,0.1354,0.9733,0.1617,0.9426,0.1618,0.9733,0.1918,0.9426,0.1918,0.9733,0.2182,0.9426,0.2182,0.9733,0.2483,0.9426,0.2483,0.9733,0.2746,0.9426,0.2746,0.9733,0.3047,0.9426,0.3047,0.9732,0.3311,0.9426,0.3311,0.9732,0.3611,0.9426,0.3612,0.9732,0.3875,0.9426,0.3875,0.9732,0.4176,0.9426,0.4176,0.9732,0.444,0.9426,0.444,0.9732,0.474,0.9426,0.474,0.9732,0.9716,0.9511,0.9549,0.9398,0.9639,0.918,0.9838,0.922,0.9462,0.9764,0.935,0.9595,0.9169,0.9884,0.913,0.9686,0.881,0.9884,0.8849,0.9686,0.8518,0.9764,0.8629,0.9595,0.8263,0.9511,0.8431,0.9398,0.8142,0.922,0.834,0.918,0.8142,0.8861,0.834,0.8901,0.8263,0.857,0.8431,0.8683,0.8518,0.8317,0.8629,0.8486,0.881,0.8197,0.8849,0.8395,0.9169,0.8197,0.913,0.8395,0.9462,0.8317,0.935,0.8486,0.9716,0.857,0.9549,0.8683,0.9838,0.8861,0.9639,0.8901,0.9244,0.9195,0.9281,0.9109,0.9147,0.9292,0.9059,0.9327,0.8921,0.9327,0.8833,0.9292,0.8735,0.9195,0.8699,0.9109,0.8833,0.879,0.8921,0.8754,0.9059,0.8754,0.9147,0.879,0.9276,0.619,0.9142,0.6422,0.9,0.6415,0.9199,0.607,0.9574,0.6186,0.964,0.6072,0.9719,0.6446,0.9862,0.6452,0.9585,0.6677,0.9663,0.6797,0.9288,0.6682,0.9222,0.6796,0.608,0.9194,0.6075,0.9327,0.5988,0.9468,0.5889,0.8978,0.587,0.953,0.5705,0.9525,0.5514,0.9308,0.5592,0.9455,0.5518,0.9176,0.5606,0.9035,0.5723,0.8972,0.6001,0.9048,0.9243,0.643,0.9333,0.6273,0.9525,0.6271,0.9619,0.6438,0.9528,0.6595,0.9337,0.6597,0.9323,0.6332,0.9288,0.6392,0.9466,0.6289,0.9396,0.6289,0.9573,0.6392,0.9539,0.6332,0.9539,0.6536,0.9573,0.6476,0.9396,0.6578,0.9466,0.6578,0.9288,0.6476,0.9323,0.6536,0.3171,0.9043,0.3171,0.9153,0.305,0.9153,0.305,0.9043,0.3319,0.9043,0.3319,0.9153,0.344,0.9043,0.344,0.9153,0.3588,0.9043,0.3588,0.9153,0.371,0.9043,0.371,0.9153,0.3857,0.9043,0.3857,0.9153,0.3979,0.9043,0.3979,0.9153,0.2511,0.9043,0.2511,0.9153,0.2364,0.9153,0.2364,0.9043,0.2633,0.9043,0.2633,0.9153,0.2781,0.9043,0.2781,0.9153,0.2902,0.9043,0.2902,0.9153,0.6117,0.9339,0.6122,0.9184,0.6018,0.95,0.588,0.9573,0.5692,0.9567,0.556,0.9485,0.5471,0.9318,0.5476,0.9163,0.5576,0.9003,0.5713,0.8929,0.5901,0.8936,0.6033,0.9018,0.788,0.2602,0.7854,0.3134,0.7465,0.2858,0.8213,0.325,0.7825,0.3261,0.8241,0.2846,0.5438,0.3732,0.5024,0.3775,0.5024,0.3594,0.5422,0.3514,0.5718,0.3744,0.5821,0.3502,0.6228,0.3772,0.6222,0.3592,0.7042,0.324,0.7437,0.3255,0.8607,0.3236,0.7827,0.1664,0.7041,0.1997,0.8608,0.1993,0.0213,0.1691,0.0602,0.1716,0.0567,0.1227,0.058,0.1478,0.0391,0.1229,0.0996,0.1733,0.0996,0.1468,0.1,0.1219,0.1388,0.1714,0.1424,0.1227,0.1413,0.1478,0.4628,0.3953,0.6623,0.395,0.5024,0.3954,0.5026,0.4177,0.4826,0.3954,0.5026,0.4393,0.5425,0.459,0.5444,0.3954,0.5441,0.428,0.5826,0.4595,0.5722,0.4268,0.5636,0.3958,0.6225,0.4394,0.6238,0.3953,0.623,0.4179,0.6425,0.3952]],
+
+"faces" : [41,0,1,2,3,0,1,2,3,0,1,1,2,41,4,5,6,7,4,5,6,7,3,4,5,3,41,8,5,4,9,8,5,4,9,6,4,3,3,41,10,11,7,6,10,11,7,6,7,3,3,5,41,12,13,11,10,12,13,11,10,8,9,3,7,41,14,15,13,12,14,15,13,12,10,11,9,8,41,16,17,15,14,16,17,15,14,12,13,11,10,41,18,8,9,19,18,8,9,19,14,6,3,3,41,20,18,19,21,20,18,19,21,15,14,3,16,41,22,20,21,23,22,20,21,23,17,15,16,18,41,24,22,23,25,24,22,23,25,19,17,18,20,41,26,27,15,17,26,27,15,17,21,22,11,13,41,27,28,13,15,27,28,13,15,22,23,9,11,41,28,29,11,13,28,29,11,13,23,24,3,9,41,29,30,7,11,29,30,7,11,24,25,3,3,41,30,31,4,7,30,31,4,7,25,26,3,3,41,4,31,32,9,4,31,32,9,3,26,27,3,41,9,32,33,19,9,32,33,19,3,27,28,3,41,19,33,34,21,19,33,34,21,3,28,29,16,41,21,34,35,23,21,34,35,23,16,29,30,18,41,23,35,36,25,23,35,36,25,18,30,31,20,41,37,3,2,38,37,3,2,38,32,2,1,1,41,1,0,39,40,1,0,39,40,1,0,33,1,41,41,42,40,39,41,42,40,39,34,35,1,33,41,43,44,42,41,43,44,42,41,36,37,35,34,41,45,46,44,43,45,46,44,43,38,39,37,36,41,47,37,38,48,47,37,38,48,40,32,1,1,41,49,47,48,50,49,47,48,50,41,40,1,42,41,51,49,50,52,51,49,50,52,43,41,42,44,41,53,51,52,54,53,51,52,54,45,43,44,46,41,55,56,44,46,55,56,44,46,47,48,37,39,41,56,57,42,44,56,57,42,44,48,49,35,37,41,57,58,40,42,57,58,40,42,49,50,1,35,41,58,59,1,40,58,59,1,40,50,51,1,1,41,59,60,2,1,59,60,2,1,51,52,1,1,41,2,60,61,38,2,60,61,38,1,52,53,1,41,38,61,62,48,38,61,62,48,1,53,54,1,41,48,62,63,50,48,62,63,50,1,54,55,42,41,50,63,64,52,50,63,64,52,42,55,56,44,41,52,64,65,54,52,64,65,54,44,56,57,46,40,66,67,68,66,67,68,58,59,60,41,67,66,69,70,67,66,69,70,59,58,61,62,41,71,72,70,69,71,72,70,69,63,64,62,61,41,73,74,72,71,73,74,72,71,65,66,64,63,41,73,75,76,77,73,75,76,77,65,67,68,69,40,76,75,78,76,75,78,68,67,70,41,76,78,79,80,76,78,79,80,68,70,71,72,41,81,80,82,83,81,80,82,83,73,72,74,75,41,83,82,84,85,83,82,84,85,75,74,76,77,41,85,84,86,87,85,84,86,87,77,76,78,79,41,86,88,89,90,86,88,89,90,78,80,81,82,41,90,89,91,92,90,89,91,92,82,81,83,84,41,92,91,93,94,92,91,93,94,84,83,85,86,41,94,93,95,96,94,93,95,96,86,85,87,88,41,96,95,97,98,96,95,97,98,88,87,89,90,41,98,97,99,100,98,97,99,100,90,89,91,92,41,100,99,101,102,100,99,101,102,92,91,93,94,41,102,101,103,104,102,101,103,104,94,93,95,96,41,104,103,105,106,104,103,105,106,96,95,97,98,41,107,108,109,110,107,108,109,110,99,100,101,102,41,111,112,107,110,111,112,107,110,103,104,99,102,41,113,114,115,116,113,114,115,116,105,106,107,108,41,116,115,117,118,116,115,117,118,108,107,109,110,41,118,117,119,120,118,117,119,120,110,109,111,112,41,68,121,120,119,121,122,120,119,60,113,112,111,40,68,119,122,121,119,123,60,111,114,41,123,124,125,126,124,125,126,127,115,116,117,118,41,127,123,126,128,128,124,127,129,119,115,118,120,41,122,127,128,129,130,128,129,131,114,119,120,121,41,130,3,37,131,132,133,134,135,122,2,32,123,41,132,130,131,133,136,132,135,137,124,122,123,125,41,134,132,133,135,138,136,137,139,126,124,125,127,41,136,134,135,137,140,138,139,141,128,126,127,129,41,138,136,137,139,142,140,141,143,130,128,129,131,41,124,138,139,125,125,142,143,126,116,130,131,117,41,140,141,124,123,144,145,146,147,132,133,116,115,41,142,140,123,127,148,144,147,149,134,132,115,119,41,119,142,127,122,119,148,149,123,111,134,119,114,41,143,0,3,130,150,151,152,153,135,0,2,122,41,144,143,130,132,154,150,153,155,136,135,122,124,41,145,144,132,134,156,154,155,157,137,136,124,126,41,146,145,134,136,158,156,157,159,138,137,126,128,41,147,146,136,138,160,158,159,161,139,138,128,130,41,141,147,138,124,145,160,161,146,133,139,130,116,41,148,149,141,140,162,163,145,144,140,141,133,132,41,150,148,140,142,164,162,144,148,142,140,132,134,41,117,150,142,119,117,164,148,119,109,142,134,111,41,0,143,151,39,151,150,165,166,0,135,143,33,41,152,151,143,144,167,165,150,154,144,143,135,136,41,153,152,144,145,168,167,154,156,145,144,136,137,41,154,153,145,146,169,168,156,158,146,145,137,138,41,155,154,146,147,170,169,158,160,147,146,138,139,41,149,155,147,141,163,170,160,145,141,147,139,133,41,156,157,149,148,171,172,163,162,148,149,141,140,41,158,156,148,150,173,171,162,164,150,148,140,142,41,115,158,150,117,115,173,164,117,107,150,142,109,41,159,41,39,151,174,175,166,165,151,34,33,143,41,160,159,151,152,176,174,165,167,152,151,143,144,41,161,160,152,153,177,176,167,168,153,152,144,145,41,162,161,153,154,178,177,168,169,154,153,145,146,41,163,162,154,155,179,178,169,170,155,154,146,147,41,157,163,155,149,172,179,170,163,149,155,147,141,41,164,165,157,156,180,181,172,171,156,157,149,148,41,166,164,156,158,182,180,171,173,158,156,148,150,41,114,166,158,115,114,182,173,115,106,158,150,107,41,167,43,41,159,183,184,175,174,159,36,34,151,41,168,167,159,160,185,183,174,176,160,159,151,152,41,169,168,160,161,186,185,176,177,161,160,152,153,41,170,169,161,162,187,186,177,178,162,161,153,154,41,171,170,162,163,188,187,178,179,163,162,154,155,41,165,171,163,157,181,188,179,172,157,163,155,149,41,172,173,165,164,189,190,181,180,164,165,157,156,41,174,172,164,166,191,189,180,182,166,164,156,158,41,175,174,166,114,192,191,182,114,167,166,158,106,41,176,45,43,167,193,194,184,183,168,38,36,159,41,177,176,167,168,195,193,183,185,169,168,159,160,41,178,177,168,169,196,195,185,186,170,169,160,161,41,179,178,169,170,197,196,186,187,171,170,161,162,41,180,179,170,171,198,197,187,188,172,171,162,163,41,173,180,171,165,190,198,188,181,165,172,163,157,41,181,182,173,172,199,200,190,189,173,174,165,164,41,183,181,172,174,201,199,189,191,175,173,164,166,41,105,183,174,175,105,201,191,192,97,175,166,167,41,184,46,45,176,202,203,194,193,176,39,38,168,41,185,184,176,177,204,202,193,195,177,176,168,169,41,186,185,177,178,205,204,195,196,178,177,169,170,41,187,186,178,179,206,205,196,197,179,178,170,171,41,188,187,179,180,207,206,197,198,180,179,171,172,41,182,188,180,173,200,207,198,190,174,180,172,165,41,189,190,182,181,208,209,200,199,181,182,174,173,41,191,189,181,183,210,208,199,201,183,181,173,175,41,103,191,183,105,103,210,201,105,95,183,175,97,41,192,55,46,184,211,212,203,202,184,47,39,176,41,193,192,184,185,213,211,202,204,185,184,176,177,41,194,193,185,186,214,213,204,205,186,185,177,178,41,195,194,186,187,215,214,205,206,187,186,178,179,41,196,195,187,188,216,215,206,207,188,187,179,180,41,190,196,188,182,209,216,207,200,182,188,180,174,41,197,198,190,189,217,218,209,208,189,190,182,181,41,199,197,189,191,219,217,208,210,191,189,181,183,41,101,199,191,103,101,219,210,103,93,191,183,95,41,200,56,55,192,220,221,212,211,192,48,47,184,41,201,200,192,193,222,220,211,213,193,192,184,185,41,202,201,193,194,223,222,213,214,194,193,185,186,41,203,202,194,195,224,223,214,215,195,194,186,187,41,204,203,195,196,225,224,215,216,196,195,187,188,41,198,204,196,190,218,225,216,209,190,196,188,182,41,205,206,198,197,226,227,218,217,197,198,190,189,41,207,205,197,199,228,226,217,219,199,197,189,191,41,99,207,199,101,99,228,219,101,91,199,191,93,41,208,57,56,200,229,230,221,220,200,49,48,192,41,209,208,200,201,231,229,220,222,201,200,192,193,41,210,209,201,202,232,231,222,223,202,201,193,194,41,211,210,202,203,233,232,223,224,203,202,194,195,41,212,211,203,204,234,233,224,225,204,203,195,196,41,206,212,204,198,227,234,225,218,198,204,196,190,41,213,214,206,205,235,236,227,226,205,206,198,197,41,215,213,205,207,237,235,226,228,207,205,197,199,41,97,215,207,99,97,237,228,99,89,207,199,91,41,216,58,57,208,238,239,230,229,208,50,49,200,41,217,216,208,209,240,238,229,231,209,208,200,201,41,218,217,209,210,241,240,231,232,210,209,201,202,41,219,218,210,211,242,241,232,233,211,210,202,203,41,220,219,211,212,243,242,233,234,212,211,203,204,41,214,220,212,206,236,243,234,227,206,212,204,198,41,221,222,214,213,244,245,236,235,213,214,206,205,41,223,221,213,215,246,244,235,237,215,213,205,207,41,95,223,215,97,95,246,237,97,87,215,207,89,41,224,59,58,216,247,248,239,238,216,51,50,208,41,225,224,216,217,249,247,238,240,217,216,208,209,41,226,225,217,218,250,249,240,241,218,217,209,210,41,227,226,218,219,251,250,241,242,219,218,210,211,41,228,227,219,220,252,251,242,243,220,219,211,212,41,222,228,220,214,245,252,243,236,214,220,212,206,41,229,230,222,221,253,254,245,244,221,222,214,213,41,231,229,221,223,255,253,244,246,223,221,213,215,41,93,231,223,95,93,255,246,95,85,223,215,87,41,232,60,59,224,256,257,248,247,224,52,51,216,41,233,232,224,225,258,256,247,249,225,224,216,217,41,234,233,225,226,259,258,249,250,226,225,217,218,41,235,234,226,227,260,259,250,251,227,226,218,219,41,236,235,227,228,261,260,251,252,228,227,219,220,41,230,236,228,222,254,261,252,245,222,228,220,214,41,237,238,230,229,262,263,254,253,229,230,222,221,41,239,237,229,231,264,262,253,255,231,229,221,223,41,91,239,231,93,91,264,255,93,83,231,223,85,41,240,61,60,232,265,266,257,256,232,53,52,224,41,241,240,232,233,267,265,256,258,233,232,224,225,41,242,241,233,234,268,267,258,259,234,233,225,226,41,243,242,234,235,269,268,259,260,235,234,226,227,41,244,243,235,236,270,269,260,261,236,235,227,228,41,238,244,236,230,263,270,261,254,230,236,228,222,41,245,246,238,237,271,272,263,262,237,238,230,229,41,247,245,237,239,273,271,262,264,239,237,229,231,41,89,247,239,91,89,273,264,91,81,239,231,83,41,248,62,61,240,274,275,266,265,240,54,53,232,41,249,248,240,241,276,274,265,267,241,240,232,233,41,250,249,241,242,277,276,267,268,242,241,233,234,41,251,250,242,243,278,277,268,269,243,242,234,235,41,252,251,243,244,279,278,269,270,244,243,235,236,41,246,252,244,238,272,279,270,263,238,244,236,230,41,253,254,246,245,280,281,272,271,245,246,238,237,41,255,253,245,247,282,280,271,273,247,245,237,239,41,88,255,247,89,88,282,273,89,80,247,239,81,41,256,63,62,248,283,284,275,274,248,55,54,240,41,257,256,248,249,285,283,274,276,249,248,240,241,41,258,257,249,250,286,285,276,277,250,249,241,242,41,259,258,250,251,287,286,277,278,251,250,242,243,41,260,259,251,252,288,287,278,279,252,251,243,244,41,254,260,252,246,281,288,279,272,246,252,244,238,41,261,262,254,253,289,290,281,280,253,254,246,245,41,263,261,253,255,291,289,280,282,255,253,245,247,41,264,263,255,88,292,291,282,88,256,255,247,80,41,265,64,63,256,293,294,284,283,257,56,55,248,41,266,265,256,257,295,293,283,285,258,257,248,249,41,267,266,257,258,296,295,285,286,259,258,249,250,41,268,267,258,259,297,296,286,287,260,259,250,251,41,269,268,259,260,298,297,287,288,261,260,251,252,41,262,269,260,254,290,298,288,281,254,261,252,246,41,270,271,262,261,299,300,290,289,262,263,254,253,41,272,270,261,263,301,299,289,291,264,262,253,255,41,273,272,263,264,302,301,291,292,265,264,255,256,41,274,65,64,265,303,304,294,293,266,57,56,257,41,275,274,265,266,305,303,293,295,267,266,257,258,41,276,275,266,267,306,305,295,296,268,267,258,259,41,277,276,267,268,307,306,296,297,269,268,259,260,41,278,277,268,269,308,307,297,298,270,269,260,261,41,271,278,269,262,300,308,298,290,263,270,261,254,41,279,280,271,270,309,310,300,299,271,272,263,262,41,281,279,270,272,311,309,299,301,273,271,262,264,41,79,281,272,273,79,311,301,302,71,273,264,265,41,282,54,65,274,312,313,304,303,274,46,57,266,41,283,282,274,275,314,312,303,305,275,274,266,267,41,284,283,275,276,315,314,305,306,276,275,267,268,41,285,284,276,277,316,315,306,307,277,276,268,269,41,286,285,277,278,317,316,307,308,278,277,269,270,41,280,286,278,271,310,317,308,300,272,278,270,263,41,287,288,280,279,318,319,310,309,279,280,272,271,41,289,287,279,281,320,318,309,311,281,279,271,273,41,78,289,281,79,78,320,311,79,70,281,273,71,41,290,53,54,282,321,322,313,312,282,45,46,274,41,291,290,282,283,323,321,312,314,283,282,274,275,41,292,291,283,284,324,323,314,315,284,283,275,276,41,293,292,284,285,325,324,315,316,285,284,276,277,41,294,293,285,286,326,325,316,317,286,285,277,278,41,288,294,286,280,319,326,317,310,280,286,278,272,41,295,296,288,287,327,328,319,318,287,288,280,279,41,297,295,287,289,329,327,318,320,289,287,279,281,41,75,297,289,78,75,329,320,78,67,289,281,70,41,298,51,53,290,330,331,322,321,290,43,45,282,41,299,298,290,291,332,330,321,323,291,290,282,283,41,300,299,291,292,333,332,323,324,292,291,283,284,41,301,300,292,293,334,333,324,325,293,292,284,285,41,302,301,293,294,335,334,325,326,294,293,285,286,41,296,302,294,288,328,335,326,319,288,294,286,280,41,303,304,296,295,336,337,328,327,295,296,288,287,41,305,303,295,297,338,336,327,329,297,295,287,289,41,306,305,297,75,339,338,329,75,298,297,289,67,41,307,49,51,298,340,341,331,330,299,41,43,290,41,308,307,298,299,342,340,330,332,300,299,290,291,41,309,308,299,300,343,342,332,333,301,300,291,292,41,310,309,300,301,344,343,333,334,302,301,292,293,41,311,310,301,302,345,344,334,335,303,302,293,294,41,304,311,302,296,337,345,335,328,296,303,294,288,41,312,313,304,303,346,347,337,336,304,305,296,295,41,314,312,303,305,348,346,336,338,306,304,295,297,41,315,314,305,306,349,348,338,339,307,306,297,298,41,316,47,49,307,350,351,341,340,308,40,41,299,41,317,316,307,308,352,350,340,342,309,308,299,300,41,318,317,308,309,353,352,342,343,310,309,300,301,41,319,318,309,310,354,353,343,344,311,310,301,302,41,320,319,310,311,355,354,344,345,312,311,302,303,41,313,320,311,304,347,355,345,337,305,312,303,296,41,126,125,313,312,127,126,347,346,118,117,305,304,41,128,126,312,314,129,127,346,348,120,118,304,306,41,129,128,314,315,131,129,348,349,121,120,306,307,41,131,37,47,316,135,134,351,350,123,32,40,308,41,133,131,316,317,137,135,350,352,125,123,308,309,41,135,133,317,318,139,137,352,353,127,125,309,310,41,137,135,318,319,141,139,353,354,129,127,310,311,41,139,137,319,320,143,141,354,355,131,129,311,312,41,125,139,320,313,126,143,355,347,117,131,312,305,41,321,322,323,324,356,357,358,359,130,131,117,116,41,325,326,322,321,360,361,357,356,313,314,131,130,41,327,328,326,325,362,363,361,360,315,316,314,313,41,329,330,32,31,364,365,366,367,317,318,27,26,41,331,332,330,329,368,369,365,364,319,320,318,317,41,333,334,332,331,370,371,369,368,321,322,320,319,41,335,336,334,333,372,373,371,370,323,324,322,321,41,337,338,336,335,374,375,373,372,115,118,324,323,41,324,323,338,337,359,358,375,374,116,117,118,115,41,339,321,324,340,376,377,378,379,139,130,116,133,41,341,325,321,339,380,381,377,376,325,313,130,139,41,342,327,325,341,382,383,381,380,326,315,313,325,41,343,329,31,30,384,385,386,387,327,317,26,25,41,344,331,329,343,388,389,385,384,328,319,317,327,41,345,333,331,344,390,391,389,388,329,321,319,328,41,346,335,333,345,392,393,391,390,330,323,321,329,41,347,337,335,346,394,395,393,392,132,115,323,330,41,340,324,337,347,379,378,395,394,133,116,115,132,41,348,339,340,349,396,376,379,397,147,139,133,141,41,350,341,339,348,398,380,376,396,331,325,139,147,41,351,342,341,350,399,382,380,398,332,326,325,331,41,352,343,30,29,400,384,387,401,333,327,25,24,41,353,344,343,352,402,388,384,400,334,328,327,333,41,354,345,344,353,403,390,388,402,335,329,328,334,41,355,346,345,354,404,392,390,403,336,330,329,335,41,356,347,346,355,405,394,392,404,140,132,330,336,41,349,340,347,356,397,379,394,405,141,133,132,140,41,357,348,349,358,406,396,397,407,155,147,141,149,41,359,350,348,357,408,398,396,406,337,331,147,155,41,360,351,350,359,409,399,398,408,338,332,331,337,41,361,352,29,28,410,400,401,411,339,333,24,23,41,362,353,352,361,412,402,400,410,340,334,333,339,41,363,354,353,362,413,403,402,412,341,335,334,340,41,364,355,354,363,414,404,403,413,342,336,335,341,41,365,356,355,364,415,405,404,414,148,140,336,342,41,358,349,356,365,407,397,405,415,149,141,140,148,41,366,357,358,367,416,406,407,417,163,155,149,157,41,368,359,357,366,418,408,406,416,343,337,155,163,41,369,360,359,368,419,409,408,418,344,338,337,343,41,370,361,28,27,420,410,411,421,345,339,23,22,41,371,362,361,370,422,412,410,420,346,340,339,345,41,372,363,362,371,423,413,412,422,347,341,340,346,41,373,364,363,372,424,414,413,423,348,342,341,347,41,374,365,364,373,425,415,414,424,156,148,342,348,41,367,358,365,374,417,407,415,425,157,149,148,156,41,375,366,367,376,426,416,417,427,172,163,157,165,41,377,368,366,375,428,418,416,426,349,343,163,172,41,378,369,368,377,429,419,418,428,350,344,343,349,41,379,370,27,26,430,420,421,431,351,345,22,21,41,380,371,370,379,432,422,420,430,352,346,345,351,41,381,372,371,380,433,423,422,432,353,347,346,352,41,382,373,372,381,434,424,423,433,354,348,347,353,41,383,374,373,382,435,425,424,434,164,156,348,354,41,376,367,374,383,427,417,425,435,165,157,156,164,41,384,375,376,385,436,426,427,437,180,172,165,174,41,386,377,375,384,438,428,426,436,355,349,172,180,41,387,378,377,386,439,429,428,438,356,350,349,355,41,388,379,26,17,440,430,431,441,357,351,21,13,41,389,380,379,388,442,432,430,440,358,352,351,357,41,390,381,380,389,443,433,432,442,359,353,352,358,41,391,382,381,390,444,434,433,443,360,354,353,359,41,392,383,382,391,445,435,434,444,173,164,354,360,41,385,376,383,392,437,427,435,445,174,165,164,173,41,393,384,385,394,446,436,437,447,188,180,174,182,41,395,386,384,393,448,438,436,446,361,355,180,188,41,396,387,386,395,449,439,438,448,362,356,355,361,41,397,388,17,16,450,440,441,451,363,357,13,12,41,398,389,388,397,452,442,440,450,364,358,357,363,41,399,390,389,398,453,443,442,452,365,359,358,364,41,400,391,390,399,454,444,443,453,366,360,359,365,41,401,392,391,400,455,445,444,454,181,173,360,366,41,394,385,392,401,447,437,445,455,182,174,173,181,41,402,393,394,403,456,446,447,457,196,188,182,190,41,404,395,393,402,458,448,446,456,367,361,188,196,41,405,396,395,404,459,449,448,458,368,362,361,367,41,406,397,16,14,460,450,451,461,369,363,12,10,41,407,398,397,406,462,452,450,460,370,364,363,369,41,408,399,398,407,463,453,452,462,371,365,364,370,41,409,400,399,408,464,454,453,463,372,366,365,371,41,410,401,400,409,465,455,454,464,189,181,366,372,41,403,394,401,410,457,447,455,465,190,182,181,189,41,411,402,403,412,466,456,457,467,204,196,190,198,41,413,404,402,411,468,458,456,466,373,367,196,204,41,414,405,404,413,469,459,458,468,374,368,367,373,41,415,406,14,12,470,460,461,471,375,369,10,8,41,416,407,406,415,472,462,460,470,376,370,369,375,41,417,408,407,416,473,463,462,472,377,371,370,376,41,418,409,408,417,474,464,463,473,378,372,371,377,41,419,410,409,418,475,465,464,474,197,189,372,378,41,412,403,410,419,467,457,465,475,198,190,189,197,41,420,411,412,421,476,466,467,477,379,204,198,206,41,422,413,411,420,478,468,466,476,380,373,204,379,41,423,414,413,422,479,469,468,478,381,374,373,380,41,424,415,12,10,480,470,471,481,382,375,8,7,41,425,416,415,424,482,472,470,480,383,376,375,382,41,426,417,416,425,483,473,472,482,384,377,376,383,41,427,418,417,426,484,474,473,483,385,378,377,384,41,428,419,418,427,485,475,474,484,386,197,378,385,41,421,412,419,428,477,467,475,485,206,198,197,386,41,429,420,421,430,486,476,477,487,220,379,206,214,41,431,422,420,429,488,478,476,486,387,380,379,220,41,432,423,422,431,489,479,478,488,388,381,380,387,41,433,424,10,6,490,480,481,491,389,382,7,5,41,434,425,424,433,492,482,480,490,390,383,382,389,41,435,426,425,434,493,483,482,492,391,384,383,390,41,436,427,426,435,494,484,483,493,392,385,384,391,41,437,428,427,436,495,485,484,494,213,386,385,392,41,430,421,428,437,487,477,485,495,214,206,386,213,41,438,429,430,439,496,486,487,497,228,220,214,393,41,440,431,429,438,498,488,486,496,394,387,220,228,41,441,432,431,440,499,489,488,498,395,388,387,394,41,442,433,6,5,500,490,491,501,396,389,5,4,41,443,434,433,442,502,492,490,500,397,390,389,396,41,444,435,434,443,503,493,492,502,398,391,390,397,41,445,436,435,444,504,494,493,503,399,392,391,398,41,446,437,436,445,505,495,494,504,221,213,392,399,41,439,430,437,446,497,487,495,505,393,214,213,221,41,447,438,439,448,506,496,497,507,236,228,393,230,41,449,440,438,447,508,498,496,506,400,394,228,236,41,450,441,440,449,509,499,498,508,401,395,394,400,41,451,442,5,8,510,500,501,511,402,396,4,6,41,452,443,442,451,512,502,500,510,403,397,396,402,41,453,444,443,452,513,503,502,512,404,398,397,403,41,454,445,444,453,514,504,503,513,405,399,398,404,41,455,446,445,454,515,505,504,514,229,221,399,405,41,448,439,446,455,507,497,505,515,230,393,221,229,41,456,447,448,457,516,506,507,517,244,236,230,238,41,458,449,447,456,518,508,506,516,406,400,236,244,41,459,450,449,458,519,509,508,518,407,401,400,406,41,460,451,8,18,520,510,511,521,408,402,6,14,41,461,452,451,460,522,512,510,520,409,403,402,408,41,462,453,452,461,523,513,512,522,410,404,403,409,41,463,454,453,462,524,514,513,523,411,405,404,410,41,464,455,454,463,525,515,514,524,237,229,405,411,41,457,448,455,464,517,507,515,525,238,230,229,237,41,465,456,457,466,526,516,517,527,252,244,238,246,41,467,458,456,465,528,518,516,526,412,406,244,252,41,87,459,458,467,87,519,518,528,79,407,406,412,41,468,460,18,20,529,520,521,530,413,408,14,15,41,469,461,460,468,531,522,520,529,414,409,408,413,41,470,462,461,469,532,523,522,531,415,410,409,414,41,471,463,462,470,533,524,523,532,416,411,410,415,41,472,464,463,471,534,525,524,533,245,237,411,416,41,466,457,464,472,527,517,525,534,246,238,237,245,41,473,465,466,474,535,526,527,536,261,252,246,254,41,475,467,465,473,537,528,526,535,417,412,252,261,41,85,87,467,475,85,87,528,537,77,79,412,417,41,476,468,20,22,538,529,530,539,418,413,15,17,41,477,469,468,476,540,531,529,538,419,414,413,418,41,478,470,469,477,541,532,531,540,420,415,414,419,41,479,471,470,478,542,533,532,541,421,416,415,420,41,480,472,471,479,543,534,533,542,253,245,416,421,41,474,466,472,480,536,527,534,543,254,246,245,253,41,481,473,474,482,544,535,536,545,270,261,254,263,41,483,475,473,481,546,537,535,544,422,417,261,270,41,83,85,475,483,83,85,537,546,75,77,417,422,41,484,476,22,24,547,538,539,548,423,418,17,19,41,485,477,476,484,549,540,538,547,424,419,418,423,41,486,478,477,485,550,541,540,549,425,420,419,424,41,487,479,478,486,551,542,541,550,426,421,420,425,41,488,480,479,487,552,543,542,551,262,253,421,426,41,482,474,480,488,545,536,543,552,263,254,253,262,41,489,481,482,490,553,544,545,554,278,270,263,272,41,491,483,481,489,555,546,544,553,427,422,270,278,41,81,83,483,491,81,83,546,555,73,75,422,427,41,492,484,24,25,556,547,548,557,428,423,19,20,41,493,485,484,492,558,549,547,556,429,424,423,428,41,494,486,485,493,559,550,549,558,430,425,424,429,41,495,487,486,494,560,551,550,559,431,426,425,430,41,496,488,487,495,561,552,551,560,271,262,426,431,41,490,482,488,496,554,545,552,561,272,263,262,271,41,497,489,490,498,562,553,554,563,286,278,272,280,41,499,491,489,497,564,555,553,562,432,427,278,286,41,500,81,491,499,565,81,555,564,433,73,427,432,41,501,492,25,36,566,556,557,567,434,428,20,31,41,502,493,492,501,568,558,556,566,435,429,428,434,41,503,494,493,502,569,559,558,568,436,430,429,435,41,504,495,494,503,570,560,559,569,437,431,430,436,41,505,496,495,504,571,561,560,570,279,271,431,437,41,498,490,496,505,563,554,561,571,280,272,271,279,41,506,497,498,507,572,562,563,573,294,286,280,288,41,508,499,497,506,574,564,562,572,438,432,286,294,41,509,500,499,508,575,565,564,574,439,433,432,438,41,510,501,36,35,576,566,567,577,440,434,31,30,41,511,502,501,510,578,568,566,576,441,435,434,440,41,512,503,502,511,579,569,568,578,442,436,435,441,41,513,504,503,512,580,570,569,579,443,437,436,442,41,514,505,504,513,581,571,570,580,287,279,437,443,41,507,498,505,514,573,563,571,581,288,280,279,287,41,515,506,507,516,582,572,573,583,303,294,288,296,41,517,508,506,515,584,574,572,582,302,438,294,303,41,518,509,508,517,585,575,574,584,444,439,438,302,41,519,510,35,34,586,576,577,587,445,440,30,29,41,520,511,510,519,588,578,576,586,446,441,440,445,41,521,512,511,520,589,579,578,588,447,442,441,446,41,522,513,512,521,590,580,579,589,448,443,442,447,41,523,514,513,522,591,581,580,590,295,287,443,448,41,516,507,514,523,583,573,581,591,296,288,287,295,41,524,515,516,525,592,582,583,593,312,303,296,305,41,526,517,515,524,594,584,582,592,449,302,303,312,41,527,518,517,526,595,585,584,594,450,444,302,449,41,528,519,34,33,596,586,587,597,451,445,29,28,41,529,520,519,528,598,588,586,596,452,446,445,451,41,530,521,520,529,599,589,588,598,453,447,446,452,41,531,522,521,530,600,590,589,599,454,448,447,453,41,532,523,522,531,601,591,590,600,304,295,448,454,41,525,516,523,532,593,583,591,601,305,296,295,304,41,322,524,525,323,357,592,593,358,131,312,305,117,41,326,526,524,322,361,594,592,357,314,449,312,131,41,328,527,526,326,363,595,594,361,316,450,449,314,41,330,528,33,32,365,596,597,366,318,451,28,27,41,332,529,528,330,369,598,596,365,320,452,451,318,41,334,530,529,332,371,599,598,369,322,453,452,320,41,336,531,530,334,373,600,599,371,324,454,453,322,41,338,532,531,336,375,601,600,373,118,304,454,324,41,323,525,532,338,358,593,601,375,117,305,304,118,41,533,534,535,536,602,603,604,605,455,456,457,458,41,537,533,536,538,606,602,605,607,459,455,458,460,41,539,537,538,540,608,606,607,609,117,459,460,116,41,541,539,540,542,610,608,609,611,461,117,116,462,41,543,541,542,544,612,610,611,613,463,461,462,464,41,545,543,544,546,614,612,613,615,465,463,464,466,41,536,535,547,548,605,604,616,617,458,457,467,468,41,538,536,548,549,607,605,617,618,460,458,468,469,41,540,538,549,550,609,607,618,619,116,460,469,133,41,542,540,550,551,611,609,619,620,462,116,133,470,41,544,542,551,552,613,611,620,621,464,462,470,471,41,546,544,552,553,615,613,621,622,466,464,471,472,41,548,547,554,555,617,616,623,624,468,467,473,474,41,549,548,555,556,618,617,624,625,469,468,474,475,41,550,549,556,557,619,618,625,626,133,469,475,476,41,551,550,557,558,620,619,626,627,470,133,476,477,41,552,551,558,559,621,620,627,628,471,470,477,478,41,553,552,559,560,622,621,628,629,472,471,478,479,41,555,554,561,562,624,623,630,631,474,473,480,481,41,556,555,562,563,625,624,631,632,475,474,481,482,41,557,556,563,564,626,625,632,633,476,475,482,149,41,558,557,564,565,627,626,633,634,477,476,149,483,41,559,558,565,566,628,627,634,635,478,477,483,484,41,560,559,566,567,629,628,635,636,479,478,484,485,41,562,561,568,569,631,630,637,638,481,480,486,487,41,563,562,569,570,632,631,638,639,482,481,487,488,41,564,563,570,571,633,632,639,640,149,482,488,157,41,565,564,571,572,634,633,640,641,483,149,157,489,41,566,565,572,573,635,634,641,642,484,483,489,490,41,567,566,573,574,636,635,642,643,485,484,490,491,41,569,568,575,576,638,637,644,645,487,486,492,493,41,570,569,576,577,639,638,645,646,488,487,493,494,41,571,570,577,578,640,639,646,647,157,488,494,165,41,572,571,578,579,641,640,647,648,489,157,165,495,41,573,572,579,580,642,641,648,649,490,489,495,496,41,574,573,580,581,643,642,649,650,491,490,496,497,41,576,575,582,583,645,644,651,652,493,492,498,499,41,577,576,583,584,646,645,652,653,494,493,499,500,41,578,577,584,585,647,646,653,654,165,494,500,501,41,579,578,585,586,648,647,654,655,495,165,501,502,41,580,579,586,587,649,648,655,656,496,495,502,503,41,581,580,587,588,650,649,656,657,497,496,503,504,41,583,582,589,590,652,651,658,659,499,498,505,506,41,584,583,590,591,653,652,659,660,500,499,506,507,41,585,584,591,592,654,653,660,661,501,500,507,182,41,586,585,592,593,655,654,661,662,502,501,182,508,41,587,586,593,594,656,655,662,663,503,502,508,509,41,588,587,594,595,657,656,663,664,504,503,509,510,41,590,589,596,597,659,658,665,666,506,505,511,512,41,591,590,597,598,660,659,666,667,507,506,512,513,41,592,591,598,599,661,660,667,668,182,507,513,514,41,593,592,599,600,662,661,668,669,508,182,514,515,41,594,593,600,601,663,662,669,670,509,508,515,516,41,595,594,601,602,664,663,670,671,510,509,516,517,41,597,596,603,604,666,665,672,673,512,511,518,519,41,598,597,604,605,667,666,673,674,513,512,519,520,41,599,598,605,606,668,667,674,675,514,513,520,198,41,600,599,606,607,669,668,675,676,515,514,198,521,41,601,600,607,608,670,669,676,677,516,515,521,522,41,602,601,608,609,671,670,677,678,517,516,522,523,41,604,603,610,611,673,672,679,680,519,518,524,525,41,605,604,611,612,674,673,680,681,520,519,525,526,41,606,605,612,613,675,674,681,682,198,520,526,206,41,607,606,613,614,676,675,682,683,521,198,206,527,41,608,607,614,615,677,676,683,684,522,521,527,528,41,609,608,615,616,678,677,684,685,523,522,528,529,41,611,610,617,618,680,679,686,687,525,524,530,531,41,612,611,618,619,681,680,687,688,526,525,531,532,41,613,612,619,620,682,681,688,689,206,526,532,214,41,614,613,620,621,683,682,689,690,527,206,214,533,41,615,614,621,622,684,683,690,691,528,527,533,534,41,616,615,622,623,685,684,691,692,529,528,534,535,41,618,617,624,625,687,686,693,694,531,530,536,537,41,619,618,625,626,688,687,694,695,532,531,537,538,41,620,619,626,627,689,688,695,696,214,532,538,393,41,621,620,627,628,690,689,696,697,533,214,393,539,41,622,621,628,629,691,690,697,698,534,533,539,540,41,623,622,629,630,692,691,698,699,535,534,540,541,41,625,624,631,632,694,693,700,701,537,536,542,543,41,626,625,632,633,695,694,701,702,538,537,543,544,41,627,626,633,634,696,695,702,703,393,538,544,230,41,628,627,634,635,697,696,703,704,539,393,230,545,41,629,628,635,636,698,697,704,705,540,539,545,546,41,630,629,636,637,699,698,705,706,541,540,546,547,41,632,631,638,639,701,700,707,708,543,542,548,549,41,633,632,639,640,702,701,708,709,544,543,549,550,41,634,633,640,641,703,702,709,710,230,544,550,238,41,635,634,641,642,704,703,710,711,545,230,238,551,41,636,635,642,643,705,704,711,712,546,545,551,552,41,637,636,643,644,706,705,712,713,547,546,552,553,41,639,638,645,646,708,707,714,715,549,548,554,555,41,640,639,646,647,709,708,715,716,550,549,555,556,41,641,640,647,648,710,709,716,717,238,550,556,246,41,642,641,648,649,711,710,717,718,551,238,246,557,41,643,642,649,650,712,711,718,719,552,551,557,558,41,644,643,650,651,713,712,719,720,553,552,558,559,41,646,645,652,653,715,714,721,722,555,554,560,561,41,647,646,653,654,716,715,722,723,556,555,561,562,41,648,647,654,655,717,716,723,724,246,556,562,254,41,649,648,655,656,718,717,724,725,557,246,254,563,41,650,649,656,657,719,718,725,726,558,557,563,564,41,651,650,657,658,720,719,726,727,559,558,564,565,41,653,652,659,660,722,721,728,729,561,560,566,567,41,654,653,660,661,723,722,729,730,562,561,567,568,41,655,654,661,662,724,723,730,731,254,562,568,263,41,656,655,662,663,725,724,731,732,563,254,263,569,41,657,656,663,664,726,725,732,733,564,563,569,570,41,658,657,664,665,727,726,733,734,565,564,570,571,41,660,659,666,667,729,728,735,736,567,566,572,573,41,661,660,667,668,730,729,736,737,568,567,573,574,41,662,661,668,669,731,730,737,738,263,568,574,272,41,663,662,669,670,732,731,738,739,569,263,272,575,41,664,663,670,671,733,732,739,740,570,569,575,576,41,665,664,671,672,734,733,740,741,571,570,576,577,41,667,666,673,674,736,735,742,743,573,572,578,579,41,668,667,674,675,737,736,743,744,574,573,579,580,41,669,668,675,676,738,737,744,745,272,574,580,280,41,670,669,676,677,739,738,745,746,575,272,280,581,41,671,670,677,678,740,739,746,747,576,575,581,582,41,672,671,678,679,741,740,747,748,577,576,582,583,41,674,673,680,681,743,742,749,750,579,578,584,585,41,675,674,681,682,744,743,750,751,580,579,585,586,41,676,675,682,683,745,744,751,752,280,580,586,288,41,677,676,683,684,746,745,752,753,581,280,288,587,41,678,677,684,685,747,746,753,754,582,581,587,588,41,679,678,685,686,748,747,754,755,583,582,588,589,41,681,680,687,688,750,749,756,757,585,584,590,591,41,682,681,688,689,751,750,757,758,586,585,591,592,41,683,682,689,690,752,751,758,759,288,586,592,296,41,684,683,690,691,753,752,759,760,587,288,296,593,41,685,684,691,692,754,753,760,761,588,587,593,594,41,686,685,692,693,755,754,761,762,589,588,594,595,41,688,687,694,695,757,756,763,764,591,590,596,597,41,689,688,695,696,758,757,764,765,592,591,597,598,41,690,689,696,697,759,758,765,766,296,592,598,305,41,691,690,697,698,760,759,766,767,593,296,305,599,41,692,691,698,699,761,760,767,768,594,593,599,600,41,693,692,699,700,762,761,768,769,595,594,600,601,41,695,694,534,533,764,763,770,771,597,596,456,455,41,696,695,533,537,765,764,771,772,598,597,455,459,41,697,696,537,539,766,765,772,773,305,598,459,117,41,698,697,539,541,767,766,773,774,599,305,117,461,41,699,698,541,543,768,767,774,775,600,599,461,463,41,700,699,543,545,769,768,775,776,601,600,463,465,41,701,702,703,704,777,778,779,780,602,603,604,605,41,705,701,704,706,781,777,780,782,606,602,605,607,41,707,705,706,708,783,781,782,784,117,606,607,116,41,709,707,708,710,785,783,784,786,461,117,116,462,41,711,709,710,712,787,785,786,788,608,461,462,464,41,713,711,712,714,789,787,788,790,465,608,464,466,41,704,703,715,716,780,779,791,792,605,604,609,610,41,706,704,716,717,782,780,792,793,607,605,610,611,41,708,706,717,718,784,782,793,794,116,607,611,133,41,710,708,718,719,786,784,794,795,462,116,133,470,41,712,710,719,720,788,786,795,796,464,462,470,471,41,714,712,720,721,790,788,796,797,466,464,471,472,41,716,715,722,723,792,791,798,799,610,609,612,613,41,717,716,723,724,793,792,799,800,611,610,613,614,41,718,717,724,725,794,793,800,801,133,611,614,476,41,719,718,725,726,795,794,801,802,470,133,476,477,41,720,719,726,727,796,795,802,803,471,470,477,478,41,721,720,727,728,797,796,803,804,472,471,478,479,41,723,722,729,730,799,798,805,806,613,612,615,616,41,724,723,730,731,800,799,806,807,614,613,616,617,41,725,724,731,732,801,800,807,808,476,614,617,149,41,726,725,732,733,802,801,808,809,477,476,149,483,41,727,726,733,734,803,802,809,810,478,477,483,484,41,728,727,734,735,804,803,810,811,479,478,484,485,41,730,729,736,737,806,805,812,813,616,615,618,619,41,731,730,737,738,807,806,813,814,617,616,619,620,41,732,731,738,739,808,807,814,815,149,617,620,157,41,733,732,739,740,809,808,815,816,483,149,157,489,41,734,733,740,741,810,809,816,817,484,483,489,490,41,735,734,741,742,811,810,817,818,485,484,490,491,41,737,736,743,744,813,812,819,820,619,618,621,622,41,738,737,744,745,814,813,820,821,620,619,622,623,41,739,738,745,746,815,814,821,822,157,620,623,165,41,740,739,746,747,816,815,822,823,489,157,165,495,41,741,740,747,748,817,816,823,824,490,489,495,496,41,742,741,748,749,818,817,824,825,491,490,496,624,41,744,743,750,751,820,819,826,827,622,621,625,626,41,745,744,751,752,821,820,827,828,623,622,626,627,41,746,745,752,753,822,821,828,829,165,623,627,174,41,747,746,753,754,823,822,829,830,495,165,174,502,41,748,747,754,755,824,823,830,831,496,495,502,503,41,749,748,755,756,825,824,831,832,624,496,503,504,41,751,750,757,758,827,826,833,834,626,625,628,629,41,752,751,758,759,828,827,834,835,627,626,629,630,41,753,752,759,760,829,828,835,836,174,627,630,182,41,754,753,760,761,830,829,836,837,502,174,182,508,41,755,754,761,762,831,830,837,838,503,502,508,509,41,756,755,762,763,832,831,838,839,504,503,509,510,41,758,757,764,765,834,833,840,841,629,628,631,632,41,759,758,765,766,835,834,841,842,630,629,632,633,41,760,759,766,767,836,835,842,843,182,630,633,514,41,761,760,767,768,837,836,843,844,508,182,514,515,41,762,761,768,769,838,837,844,845,509,508,515,516,41,763,762,769,770,839,838,845,846,510,509,516,517,41,765,764,771,772,841,840,847,848,632,631,634,635,41,766,765,772,773,842,841,848,849,633,632,635,636,41,767,766,773,774,843,842,849,850,514,633,636,198,41,768,767,774,775,844,843,850,851,515,514,198,521,41,769,768,775,776,845,844,851,852,516,515,521,522,41,770,769,776,777,846,845,852,853,517,516,522,523,41,772,771,778,779,848,847,854,855,635,634,637,638,41,773,772,779,780,849,848,855,856,636,635,638,639,41,774,773,780,781,850,849,856,857,198,636,639,206,41,775,774,781,782,851,850,857,858,521,198,206,640,41,776,775,782,783,852,851,858,859,522,521,640,641,41,777,776,783,784,853,852,859,860,523,522,641,529,41,779,778,785,786,855,854,861,862,638,637,642,643,41,780,779,786,787,856,855,862,863,639,638,643,644,41,781,780,787,788,857,856,863,864,206,639,644,214,41,782,781,788,789,858,857,864,865,640,206,214,533,41,783,782,789,790,859,858,865,866,641,640,533,645,41,784,783,790,791,860,859,866,867,529,641,645,535,41,786,785,792,793,862,861,868,869,643,642,646,647,41,787,786,793,794,863,862,869,870,644,643,647,648,41,788,787,794,795,864,863,870,871,214,644,648,393,41,789,788,795,796,865,864,871,872,533,214,393,539,41,790,789,796,797,866,865,872,873,645,533,539,540,41,791,790,797,798,867,866,873,874,535,645,540,541,41,793,792,799,800,869,868,875,876,647,646,649,650,41,794,793,800,801,870,869,876,877,648,647,650,651,41,795,794,801,802,871,870,877,878,393,648,651,230,41,796,795,802,803,872,871,878,879,539,393,230,545,41,797,796,803,804,873,872,879,880,540,539,545,546,41,798,797,804,805,874,873,880,881,541,540,546,547,41,800,799,806,807,876,875,882,883,650,649,652,653,41,801,800,807,808,877,876,883,884,651,650,653,654,41,802,801,808,809,878,877,884,885,230,651,654,238,41,803,802,809,810,879,878,885,886,545,230,238,551,41,804,803,810,811,880,879,886,887,546,545,551,552,41,805,804,811,812,881,880,887,888,547,546,552,553,41,807,806,813,814,883,882,889,890,653,652,655,656,41,808,807,814,815,884,883,890,891,654,653,656,657,41,809,808,815,816,885,884,891,892,238,654,657,246,41,810,809,816,817,886,885,892,893,551,238,246,557,41,811,810,817,818,887,886,893,894,552,551,557,558,41,812,811,818,819,888,887,894,895,553,552,558,559,41,814,813,820,821,890,889,896,897,656,655,658,659,41,815,814,821,822,891,890,897,898,657,656,659,562,41,816,815,822,823,892,891,898,899,246,657,562,254,41,817,816,823,824,893,892,899,900,557,246,254,563,41,818,817,824,825,894,893,900,901,558,557,563,564,41,819,818,825,826,895,894,901,902,559,558,564,565,41,821,820,827,828,897,896,903,904,659,658,660,661,41,822,821,828,829,898,897,904,905,562,659,661,568,41,823,822,829,830,899,898,905,906,254,562,568,263,41,824,823,830,831,900,899,906,907,563,254,263,569,41,825,824,831,832,901,900,907,908,564,563,569,662,41,826,825,832,833,902,901,908,909,565,564,662,571,41,828,827,834,835,904,903,910,911,661,660,663,664,41,829,828,835,836,905,904,911,912,568,661,664,574,41,830,829,836,837,906,905,912,913,263,568,574,272,41,831,830,837,838,907,906,913,914,569,263,272,575,41,832,831,838,839,908,907,914,915,662,569,575,576,41,833,832,839,840,909,908,915,916,571,662,576,577,41,835,834,841,842,911,910,917,918,664,663,665,666,41,836,835,842,843,912,911,918,919,574,664,666,580,41,837,836,843,844,913,912,919,920,272,574,580,280,41,838,837,844,845,914,913,920,921,575,272,280,581,41,839,838,845,846,915,914,921,922,576,575,581,667,41,840,839,846,847,916,915,922,923,577,576,667,583,41,842,841,848,849,918,917,924,925,666,665,668,669,41,843,842,849,850,919,918,925,926,580,666,669,586,41,844,843,850,851,920,919,926,927,280,580,586,288,41,845,844,851,852,921,920,927,928,581,280,288,587,41,846,845,852,853,922,921,928,929,667,581,587,588,41,847,846,853,854,923,922,929,930,583,667,588,589,41,849,848,855,856,925,924,931,932,669,668,670,671,41,850,849,856,857,926,925,932,933,586,669,671,672,41,851,850,857,858,927,926,933,934,288,586,672,296,41,852,851,858,859,928,927,934,935,587,288,296,593,41,853,852,859,860,929,928,935,936,588,587,593,594,41,854,853,860,861,930,929,936,937,589,588,594,595,41,856,855,862,863,932,931,938,939,671,670,673,674,41,857,856,863,864,933,932,939,940,672,671,674,675,41,858,857,864,865,934,933,940,941,296,672,675,305,41,859,858,865,866,935,934,941,942,593,296,305,599,41,860,859,866,867,936,935,942,943,594,593,599,600,41,861,860,867,868,937,936,943,944,595,594,600,601,41,863,862,702,701,939,938,945,946,674,673,603,602,41,864,863,701,705,940,939,946,947,675,674,602,606,41,865,864,705,707,941,940,947,948,305,675,606,117,41,866,865,707,709,942,941,948,949,599,305,117,461,41,867,866,709,711,943,942,949,950,600,599,461,608,41,868,867,711,713,944,943,950,951,601,600,608,465,41,869,870,871,872,952,953,954,955,676,677,678,679,41,873,869,872,874,956,952,955,957,680,676,679,681,41,875,873,874,876,958,956,957,959,682,680,681,683,41,877,875,876,878,960,958,959,961,684,682,683,685,41,879,877,878,880,962,960,961,963,686,684,685,687,41,881,879,880,882,964,962,963,965,688,686,687,689,41,883,881,882,884,966,964,965,967,690,688,689,691,41,870,883,884,871,953,966,967,954,677,690,691,678,41,885,886,887,888,968,969,970,971,692,693,694,695,41,889,870,869,890,972,953,952,973,696,677,676,697,41,890,869,873,891,973,952,956,974,697,676,680,698,41,891,873,875,892,974,956,958,975,698,680,682,699,41,892,875,877,893,975,958,960,976,699,682,684,700,41,893,877,879,894,976,960,962,977,700,684,686,701,41,894,879,881,895,977,962,964,978,701,686,688,702,41,895,881,883,896,978,964,966,979,702,688,690,703,41,896,883,870,889,979,966,953,972,703,690,677,696,41,890,897,898,889,973,980,981,972,697,704,705,696,41,891,899,897,890,974,982,980,973,698,706,704,697,41,892,900,899,891,975,983,982,974,699,707,706,698,41,893,901,900,892,976,984,983,975,700,708,707,699,41,894,902,901,893,977,985,984,976,701,709,708,700,41,895,903,902,894,978,986,985,977,702,710,709,701,41,896,904,903,895,979,987,986,978,703,711,710,702,41,889,898,904,896,972,981,987,979,696,705,711,703,41,897,905,906,898,988,989,990,991,704,712,713,705,41,899,907,908,897,992,993,994,988,706,714,715,704,41,900,909,910,899,995,996,997,992,707,716,717,706,41,901,911,912,900,998,999,1000,995,708,718,719,707,41,902,913,914,901,1001,1002,1003,998,709,720,721,708,41,903,915,916,902,1004,1005,1006,1001,710,722,723,709,41,904,917,918,903,1007,1008,1009,1004,711,724,725,710,41,898,919,920,904,991,1010,1011,1007,705,726,727,711,40,898,906,919,991,990,1010,705,713,726,40,897,908,905,988,994,989,704,715,712,40,899,910,907,992,997,993,706,717,714,40,900,912,909,995,1000,996,707,719,716,40,901,914,911,998,1003,999,708,721,718,40,902,916,913,1001,1006,1002,709,723,720,40,903,918,915,1004,1009,1005,710,725,722,40,904,920,917,1007,1011,1008,711,727,724,41,905,921,922,906,1012,1013,1014,1015,712,728,729,713,41,908,923,921,905,1016,1017,1018,1019,715,730,728,712,41,907,924,923,908,1020,1021,1017,1016,714,731,730,715,41,910,925,924,907,1022,1023,1021,1020,717,732,731,714,41,909,926,925,910,1024,1025,1023,1022,716,733,732,717,41,912,927,926,909,1026,1027,1025,1024,719,734,733,716,41,911,928,927,912,1028,1029,1027,1026,718,735,734,719,41,914,929,928,911,1030,1031,1029,1028,721,736,735,718,41,913,930,929,914,1032,1033,1031,1030,720,737,736,721,41,916,931,930,913,1034,1035,1033,1032,723,738,737,720,41,915,932,931,916,1036,1037,1035,1034,722,739,738,723,41,918,933,932,915,1038,1039,1037,1036,725,740,739,722,41,917,934,933,918,1040,1041,1039,1038,724,741,740,725,41,920,935,934,917,1042,1043,1041,1040,727,742,741,724,41,919,936,935,920,1044,1045,1043,1042,726,743,742,727,41,906,922,936,919,1015,1014,1045,1044,713,729,743,726,41,921,937,938,922,1046,1047,1048,1049,728,744,745,729,41,923,939,937,921,1050,1051,1047,1046,730,746,744,728,41,924,940,939,923,1052,1053,1051,1050,731,747,746,730,41,925,941,940,924,1054,1055,1053,1052,732,748,747,731,41,926,942,941,925,1056,1057,1055,1054,733,749,748,732,41,927,943,942,926,1058,1059,1057,1056,734,750,749,733,41,928,944,943,927,1060,1061,1059,1058,735,751,750,734,41,929,945,944,928,1062,1063,1061,1060,736,752,751,735,41,930,946,945,929,1064,1065,1063,1062,737,753,752,736,41,931,947,946,930,1066,1067,1065,1064,738,754,753,737,41,932,948,947,931,1068,1069,1067,1066,739,755,754,738,41,933,949,948,932,1070,1071,1069,1068,740,756,755,739,41,934,950,949,933,1072,1073,1071,1070,741,757,756,740,41,935,951,950,934,1074,1075,1073,1072,742,758,757,741,41,936,952,951,935,1076,1077,1075,1074,743,759,758,742,41,922,938,952,936,1049,1048,1077,1076,729,745,759,743,41,937,953,954,938,1078,1079,1080,1081,744,760,761,745,41,939,955,953,937,1082,1083,1079,1078,746,762,760,744,41,940,956,955,939,1084,1085,1083,1082,747,763,762,746,41,941,957,956,940,1086,1087,1085,1084,748,764,763,747,41,942,958,957,941,1088,1089,1087,1086,749,765,764,748,41,943,959,958,942,1090,1091,1089,1088,750,766,765,749,41,944,960,959,943,1092,1093,1091,1090,751,767,766,750,41,945,961,960,944,1094,1095,1093,1092,752,768,767,751,41,946,962,961,945,1096,1097,1095,1094,753,769,768,752,41,947,963,962,946,1098,1099,1097,1096,754,770,769,753,41,948,964,963,947,1100,1101,1099,1098,755,771,770,754,41,949,965,964,948,1102,1103,1101,1100,756,772,771,755,41,950,966,965,949,1104,1105,1103,1102,757,773,772,756,41,951,967,966,950,1106,1107,1105,1104,758,774,773,757,41,952,968,967,951,1108,1109,1107,1106,759,775,774,758,41,938,954,968,952,1110,1111,1109,1108,745,761,775,759,41,953,969,970,954,1112,1113,1114,1115,760,776,777,761,41,955,971,969,953,1116,1117,1113,1112,762,778,776,760,41,956,972,971,955,1118,1119,1117,1116,763,779,778,762,41,957,973,972,956,1120,1121,1119,1118,764,780,779,763,41,958,974,973,957,1122,1123,1121,1120,765,781,780,764,41,959,975,974,958,1124,1125,1123,1122,766,782,781,765,41,960,976,975,959,1126,1127,1125,1124,767,783,782,766,41,961,977,976,960,1128,1129,1127,1126,768,784,783,767,41,962,978,977,961,1130,1131,1129,1128,769,785,784,768,41,963,979,978,962,1132,1133,1131,1130,770,786,785,769,41,964,980,979,963,1134,1135,1133,1132,771,787,786,770,41,965,981,980,964,1136,1137,1135,1134,772,788,787,771,41,966,982,981,965,1138,1139,1137,1136,773,789,788,772,41,967,983,982,966,1140,1141,1139,1138,774,790,789,773,41,968,984,983,967,1142,1143,1141,1140,775,791,790,774,41,954,970,984,968,1115,1114,1143,1142,761,777,791,775,41,969,985,986,970,1113,1144,1145,1114,776,792,793,777,41,971,987,985,969,1117,1146,1144,1113,778,794,792,776,41,972,988,987,971,1119,1147,1146,1117,779,795,794,778,41,973,989,988,972,1121,1148,1147,1119,780,796,795,779,41,974,990,989,973,1123,1149,1148,1121,781,797,796,780,41,975,991,990,974,1125,1150,1149,1123,782,798,797,781,41,976,992,991,975,1127,1151,1150,1125,783,799,798,782,41,977,888,992,976,1129,971,1151,1127,784,695,799,783,41,978,885,888,977,1131,968,971,1129,785,692,695,784,41,979,993,885,978,1133,1152,968,1131,786,800,692,785,41,980,994,993,979,1135,1153,1152,1133,787,801,800,786,41,981,995,994,980,1137,1154,1153,1135,788,802,801,787,41,982,996,995,981,1139,1155,1154,1137,789,803,802,788,41,983,886,996,982,1141,969,1155,1139,790,693,803,789,41,984,887,886,983,1143,970,969,1141,791,694,693,790,41,970,986,887,984,1114,1145,970,1143,777,793,694,791,41,989,990,987,988,1148,1149,1146,1147,796,797,794,795,41,990,991,985,987,1149,1150,1144,1146,797,798,792,794,41,991,992,986,985,1150,1151,1145,1144,798,799,793,792,41,992,888,887,986,1151,971,970,1145,799,695,694,793,41,996,886,885,993,1155,969,968,1152,803,693,692,800,41,995,996,993,994,1154,1155,1152,1153,802,803,800,801,41,997,998,999,1000,1156,1157,1158,1159,804,805,806,807,41,1001,997,1000,1002,1160,1156,1159,1161,808,804,807,809,41,1003,1001,1002,1004,1162,1160,1161,1163,810,808,809,811,41,1005,1003,1004,1006,1164,1162,1163,1165,812,810,811,813,41,1007,1005,1006,1008,1166,1164,1165,1167,814,812,813,815,41,998,1007,1008,999,1157,1166,1167,1158,805,814,815,806,41,1009,1010,1011,1012,1168,1169,1170,1171,816,817,818,819,41,1011,1013,1014,1015,1170,1172,1173,1174,818,820,821,822,40,1014,1016,1015,1173,1175,1174,821,823,822,41,1015,1017,1018,1012,1174,1176,1177,1171,822,824,825,819,40,1018,1019,1012,1177,1178,1171,825,826,819,40,1011,1015,1012,1170,1174,1171,818,822,819,40,1020,1009,1012,1179,1168,1171,827,816,819,41,1021,998,997,1022,1180,1157,1156,1181,828,805,804,829,41,1022,997,1001,1023,1181,1156,1160,1182,829,804,808,830,41,1023,1001,1003,1024,1182,1160,1162,1183,830,808,810,831,41,1024,1003,1005,1025,1183,1162,1164,1184,831,810,812,832,41,1025,1005,1007,1026,1184,1164,1166,1185,832,812,814,833,41,1026,1007,998,1021,1185,1166,1157,1180,833,814,805,828,41,1022,1027,1028,1021,1181,1186,1187,1180,829,834,835,828,41,1023,1029,1030,1022,1182,1188,1189,1181,830,836,837,829,41,1024,1031,1032,1023,1183,1190,1191,1182,831,838,839,830,41,1025,1033,1034,1024,1184,1192,1193,1183,832,840,841,831,41,1026,1035,1036,1025,1185,1194,1195,1184,833,842,843,832,41,1021,1037,1038,1026,1180,1196,1197,1185,828,844,845,833,40,1021,1028,1037,1180,1187,1196,828,835,844,40,1022,1030,1027,1181,1189,1186,829,837,834,40,1023,1032,1029,1182,1191,1188,830,839,836,40,1024,1034,1031,1183,1193,1190,831,841,838,40,1025,1036,1033,1184,1195,1192,832,843,840,40,1026,1038,1035,1185,1197,1194,833,845,842,41,1027,1039,1040,1028,1198,1199,1200,1201,834,846,847,835,41,1030,1041,1039,1027,1202,1203,1199,1198,837,848,846,834,41,1029,1042,1041,1030,1204,1205,1203,1202,836,849,848,837,41,1032,1043,1042,1029,1206,1207,1205,1204,839,850,849,836,41,1031,1044,1043,1032,1208,1209,1207,1206,838,851,850,839,41,1034,1045,1044,1031,1210,1211,1209,1208,841,852,851,838,41,1033,1046,1045,1034,1212,1213,1211,1210,840,853,852,841,41,1036,1047,1046,1033,1214,1215,1216,1217,843,854,853,840,41,1035,1048,1047,1036,1218,1219,1215,1214,842,855,854,843,41,1038,1049,1048,1035,1220,1221,1219,1218,845,856,855,842,41,1037,1050,1049,1038,1222,1223,1221,1220,844,857,856,845,41,1028,1040,1050,1037,1201,1200,1223,1222,835,847,857,844,41,1039,1010,1009,1040,1224,1169,1168,1225,846,817,816,847,41,1041,1011,1010,1039,1226,1170,1169,1224,848,818,817,846,41,1042,1013,1011,1041,1227,1172,1170,1226,849,820,818,848,41,1043,1014,1013,1042,1228,1173,1172,1227,850,821,820,849,41,1044,1016,1014,1043,1229,1175,1173,1228,851,823,821,850,41,1045,1015,1016,1044,1230,1174,1175,1229,852,822,823,851,41,1046,1017,1015,1045,1231,1176,1174,1230,853,824,822,852,41,1047,1018,1017,1046,1232,1177,1176,1231,854,825,824,853,41,1048,1019,1018,1047,1233,1178,1177,1232,855,826,825,854,41,1049,1012,1019,1048,1234,1171,1178,1233,856,819,826,855,41,1050,1020,1012,1049,1235,1179,1171,1234,857,827,819,856,41,1040,1009,1020,1050,1225,1168,1179,1235,847,816,827,857,40,1051,1052,1053,1236,1237,1238,858,859,860,41,1054,1055,1052,1056,1239,1240,1237,1241,861,862,859,863,41,1057,1058,1059,1060,1242,1243,1244,1245,864,865,866,867,41,1061,1057,1060,1062,1246,1242,1245,1247,868,864,867,869,41,1063,1061,1062,1064,1248,1246,1247,1249,870,868,869,871,41,396,1065,1066,387,449,1250,1251,439,362,872,873,356,41,369,1054,1067,360,419,1239,1252,409,344,861,874,338,41,387,1066,1055,378,439,1251,1240,429,356,873,862,350,41,378,1055,1054,369,429,1240,1239,419,350,862,861,344,41,273,82,80,79,302,82,80,79,265,74,72,71,41,264,84,82,273,292,84,82,302,256,76,74,265,41,88,86,84,264,88,86,84,292,80,78,76,256,41,175,1068,106,105,192,1253,106,105,167,875,98,97,41,114,113,1068,175,114,113,1253,192,106,105,875,167,40,1051,1053,108,1236,1238,108,858,860,100,40,109,108,1069,109,108,1254,101,100,876,40,1067,1054,1056,1252,1239,1241,874,861,863,41,1067,1056,112,1070,1252,1241,112,1255,874,863,104,877,40,1070,112,111,1255,112,111,877,104,103,40,107,1051,108,107,1236,108,99,858,100,40,112,1051,107,112,1236,107,104,858,99,41,1052,1055,1066,1053,1237,1240,1251,1238,859,862,873,860,40,1052,1051,1056,1237,1236,1241,859,858,863,40,1053,1066,1065,1238,1251,1250,860,873,872,41,1053,1065,1069,108,1238,1250,1254,108,860,872,876,100,40,1056,1051,112,1241,1236,112,863,858,104,41,327,121,1071,328,362,1256,1257,363,315,113,878,316,40,1072,1073,1074,1258,1259,1260,879,880,881,41,129,66,68,122,131,66,68,130,121,58,60,114,41,328,1071,1075,527,363,1257,1261,595,316,878,882,450,41,1076,1073,1072,1077,1262,1259,1258,1263,883,880,879,884,41,315,69,66,129,349,69,66,131,307,61,58,121,41,527,1075,1078,518,595,1261,1264,585,450,882,885,444,41,1079,1080,1076,1077,1265,1266,1262,1263,886,887,883,884,41,306,71,69,315,339,71,69,349,298,63,61,307,41,518,1078,77,509,585,1264,77,575,444,885,69,439,41,77,1078,1080,74,77,1264,1266,74,69,885,887,66,41,75,73,71,306,75,73,71,339,67,65,63,298,41,509,77,76,500,575,77,76,565,439,69,68,433,41,500,76,80,81,565,76,80,81,433,68,72,73,41,87,86,90,459,87,86,90,519,79,78,82,407,41,1081,450,459,90,1267,509,519,90,888,401,407,82,40,92,1081,90,92,1267,90,84,888,82,41,1059,1081,92,94,1244,1267,92,94,866,888,84,86,41,1060,1059,94,96,1245,1244,94,96,867,866,86,88,41,1060,96,98,1062,1245,96,98,1247,867,88,90,869,41,1062,98,100,1064,1247,98,100,1249,869,90,92,871,41,1064,100,102,1082,1249,100,102,1268,871,92,94,889,41,396,405,1082,1065,449,459,1268,1250,362,368,889,872,41,1065,1082,102,1069,1250,1268,102,1254,872,889,94,876,40,104,1069,102,104,1254,102,96,876,94,41,109,1069,104,106,109,1254,104,106,101,876,96,98,41,1070,111,113,116,1255,111,113,116,877,103,105,108,41,351,360,1067,118,399,409,1252,118,332,338,874,110,41,118,1067,1070,116,118,1252,1255,116,110,874,877,108,41,351,118,120,342,399,118,120,382,332,110,112,326,41,327,342,120,121,383,382,120,122,315,326,112,113,41,110,109,106,1068,110,109,106,1253,102,101,98,875,41,111,110,1068,113,111,110,1253,113,103,102,875,105,40,1083,1084,1085,1269,1270,1271,890,891,892,41,441,1086,1087,432,499,1272,1273,489,395,893,894,388,41,1088,1089,1084,1083,1274,1275,1270,1269,895,896,891,890,41,432,1087,1090,423,489,1273,1276,479,388,894,897,381,41,1091,1089,1088,1092,1277,1275,1274,1278,898,896,895,899,41,414,423,1090,1093,469,479,1276,1279,374,381,897,900,41,1094,1095,1091,1092,1280,1281,1277,1278,901,902,898,899,41,1082,1093,1095,1096,1268,1279,1281,1282,889,900,902,903,41,1086,441,450,1081,1272,499,509,1267,893,395,401,888,41,1059,1058,1085,1081,1244,1243,1271,1267,866,865,892,888,41,405,414,1093,1082,459,469,1279,1268,368,374,900,889,41,1096,1063,1064,1082,1282,1248,1249,1268,903,870,871,889,41,1083,1058,1057,1088,1269,1243,1242,1274,890,865,864,895,41,1061,1092,1088,1057,1246,1278,1274,1242,868,899,895,864,41,1094,1092,1061,1063,1280,1278,1246,1248,901,899,868,870,41,1081,1085,1084,1086,1267,1271,1270,1272,888,892,891,893,41,1089,1087,1086,1084,1275,1273,1272,1270,896,894,893,891,41,1091,1090,1087,1089,1277,1276,1273,1275,898,897,894,896,41,1093,1090,1091,1095,1279,1276,1277,1281,900,897,898,902,40,1095,1094,1096,1281,1280,1282,902,901,903,40,1058,1083,1085,1243,1269,1271,865,890,892,40,1096,1094,1063,1282,1280,1248,903,901,870,40,67,1072,1074,67,1258,1260,59,879,881,41,70,1077,1072,67,70,1263,1258,67,62,884,879,59,41,1079,1077,70,72,1265,1263,70,72,886,884,62,64,40,74,1079,72,74,1265,72,66,886,64,40,1073,121,1074,1259,1256,1260,880,113,881,41,1076,1075,1071,1073,1262,1261,1257,1259,883,882,878,880,41,1078,1075,1076,1080,1264,1261,1262,1266,885,882,883,887,40,1080,1079,74,1266,1265,74,887,886,66,40,1073,1071,121,1259,1257,1256,880,878,113,40,67,1074,68,67,1260,68,59,881,60,40,1074,121,68,1260,1256,68,881,113,60,40,73,77,74,73,77,74,65,69,66],
+
+"bones" : [],
+
+"skinIndices" : [],
+
+"skinWeights" : [],
+
+"animations" : []
+
+
+}
diff --git a/examples/canvas3d/interaction/qml/interaction/glMatrix-0.9.5.min.js b/examples/canvas3d/interaction/qml/interaction/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/interaction/qml/interaction/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/interaction/qml/interaction/interaction.js b/examples/canvas3d/interaction/qml/interaction/interaction.js
new file mode 100644
index 0000000..933c6e4
--- /dev/null
+++ b/examples/canvas3d/interaction/qml/interaction/interaction.js
@@ -0,0 +1,359 @@
+Qt.include("glMatrix-0.9.5.min.js")
+Qt.include("ThreeJSLoader.js")
+
+var gl;
+
+var texturedShaderProgram = 0;
+var vertexShader = 0;
+var fragmentShader = 0;
+
+var vertexPositionAttribute;
+var textureCoordAttribute;
+var vertexNormalAttribute;
+
+var pMatrixUniform;
+var mvMatrixUniform;
+var nMatrixUniform;
+var textureSamplerUniform;
+
+var barrelTexture = 0;
+
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+var nMatrix = mat4.create();
+var startTime;
+
+var canvas3d;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+function Model() {
+ this.verticesVBO = 0;
+ this.normalsVBO = 0;
+ this.texCoordVBO = 0;
+ this.indexVBO = 0;
+ this.count = 0;
+}
+
+var theModel = new Model();
+
+function initGL(canvas, textureLoader) {
+ canvas3d = canvas
+ log("*******************************************************************************************")
+ log("initGL ENTER...")
+ try {
+ startTime = Date.now();
+
+ // Get the OpenGL context jsonObj that represents the API we call
+ log("Getting Context");
+ gl = canvas.getContext("canvas3d", {depth:true, antialias:true});
+ log("Context received "+gl);
+
+ var contextConfig = gl.getContextAttributes();
+ log("Depth: "+contextConfig.alpha);
+ log("Stencil: "+contextConfig.stencil);
+ log("Antialiasing: "+contextConfig.antialias);
+ log("Premultiplied alpha: "+contextConfig.premultipliedAlpha);
+ log("Preserve drawingbuffer: "+contextConfig.preserveDrawingBuffer);
+ log("Prefer Low Power To High Performance: "+contextConfig.preferLowPowerToHighPerformance);
+ log("Fail If Major Performance Caveat: "+contextConfig.failIfMajorPerformanceCaveat);
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.enable(gl.CULL_FACE);
+ gl.enable(gl.DEPTH_WRITE);
+ gl.depthMask(true);
+
+ gl.frontFace(gl.CCW);
+ gl.cullFace(gl.BACK);
+
+ gl.disable(gl.BLEND);
+
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.clearDepth(1.0);
+
+ // Set viewport
+ gl.viewport(0, 0,
+ canvas.width * canvas.devicePixelRatio,
+ canvas.height * canvas.devicePixelRatio);
+
+ // Initialize the shader program
+ initShaders();
+
+ // Initialize buffers
+ theModel.verticesVBO = gl.createBuffer();
+ theModel.verticesVBO.name = "BarrelModel.verticesVBO";
+ theModel.normalsVBO = gl.createBuffer();
+ theModel.normalsVBO.name = "BarrelModel.normalsVBO";
+ theModel.texCoordVBO = gl.createBuffer();
+ theModel.texCoordVBO.name = "BarrelModel.texCoordVBO";
+ theModel.indexVBO = gl.createBuffer();
+ theModel.indexVBO.name = "BarrelModel.indexVBO";
+
+ // Load the barrel texture
+ textureLoader.loadImage("qrc:/qml/interaction/barrel.jpg");
+
+ // Load the model
+ log(" Create XMLHttpRequest")
+ var request = new XMLHttpRequest();
+ log(" XMLHttpRequest.open")
+ request.open("GET", "barrel.json");
+ log(" XMLHttpRequest.onreadystatechange")
+ request.onreadystatechange = function () {
+ if (request.readyState == XMLHttpRequest.DONE) {
+ handleLoadedModel(JSON.parse(request.responseText));
+ }
+ }
+ log(" XMLHttpRequest.send")
+ request.send();
+
+ log("...initGL EXIT");
+ } catch(e) {
+ console.log("...initGL FAILURE!");
+ console.log(""+e);
+ console.log(""+e.message);
+ }
+ log("*******************************************************************************************");
+}
+
+
+function renderGL(canvas) {
+ // draw
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // draw only when we have the mesh and texture
+ if (theModel.count <= 0 || barrelTexture == 0) return;
+
+ gl.useProgram(texturedShaderProgram);
+
+ // Calculate the perspective projection
+ mat4.perspective(pMatrix, degToRad(45), canvas.width / canvas.height, 0.1, 10000.0);
+ gl.uniformMatrix4fva(pMatrixUniform, false, pMatrix);
+
+ // Bind the correct buffers
+ gl.bindBuffer(gl.ARRAY_BUFFER, theModel.verticesVBO);
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, theModel.normalsVBO);
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, theModel.texCoordVBO);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, barrelTexture);
+ gl.uniform1i(textureSamplerUniform, 0);
+
+ // Calculate and apply the modelview matrix
+ mvMatrix = mat4.identity(mvMatrix);
+ mvMatrix = mat4.translate(mvMatrix, mvMatrix, [0, -40, -700]);
+ //! [0]
+ mvMatrix = mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotSlider), [1, 0, 0]);
+ mvMatrix = mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotSlider), [0, 1, 0]);
+ mvMatrix = mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotSlider), [0, 0, 1]);
+ //! [0]
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Calculate normal matrix
+ nMatrix = mat4.invert(nMatrix, mvMatrix);
+ nMatrix = mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+
+ // Draw the barrel
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
+ //! [1]
+ gl.drawElements(gl.TRIANGLES, theModel.count, gl.UNSIGNED_SHORT, 0);
+ //! [1]
+
+ // Calculate and apply the modelview matrix
+ mvMatrix = mat4.identity(mvMatrix);
+ mvMatrix = mat4.translate(mvMatrix, mvMatrix, [-250, -50, -700]);
+ mvMatrix = mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotSlider), [0, 1, 0]);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Calculate normal matrix
+ nMatrix = mat4.invert(nMatrix, mvMatrix);
+ nMatrix = mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+
+ // Draw the barrel
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
+ //! [2]
+ gl.drawElements(gl.POINTS, theModel.count, gl.UNSIGNED_SHORT, 0);
+ //! [2]
+
+ // Calculate and apply the modelview matrix
+ mvMatrix = mat4.identity(mvMatrix);
+ mvMatrix = mat4.translate(mvMatrix, mvMatrix, [250, -50, -700]);
+ mvMatrix = mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotSlider), [0, 1, 0]);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Calculate normal matrix
+ nMatrix = mat4.invert(nMatrix, mvMatrix);
+ nMatrix = mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+
+ // Draw the barrel
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
+ //! [3]
+ gl.drawElements(gl.LINES, theModel.count, gl.UNSIGNED_SHORT, 0);
+ //! [3]
+}
+
+function handleLoadedModel(jsonObj) {
+ log("*******************************************************************************************");
+ log("handleLoadedModel ENTER...")
+ var modelData = parseJSON3DModel(jsonObj, "");
+
+ log(" "+theModel.verticesVBO);
+ gl.bindBuffer(gl.ARRAY_BUFFER, theModel.verticesVBO);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array(modelData.vertices),
+ gl.STATIC_DRAW);
+
+ log(" "+theModel.normalsVBO);
+ gl.bindBuffer(gl.ARRAY_BUFFER, theModel.normalsVBO);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array(modelData.normals),
+ gl.STATIC_DRAW);
+
+ log(" "+theModel.texCoordVBO);
+ gl.bindBuffer(gl.ARRAY_BUFFER, theModel.texCoordVBO);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array(modelData.texCoords[0]),
+ gl.STATIC_DRAW);
+
+ log(" "+theModel.indexVBO);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, theModel.indexVBO);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ Arrays.newUint16Array(modelData.indices),
+ gl.STATIC_DRAW);
+
+ theModel.count = modelData.indices.length;
+ log("...handleLoadedModel EXIT");
+ log("*******************************************************************************************");
+}
+
+function textureLoaded(textureImage) {
+ log("*******************************************************************************************");
+ log("textureLoaded ENTER...")
+
+ if (textureImage.imageState == TextureImage.LOADING_FINISHED && barrelTexture == 0) {
+ log(" processing "+textureImage.source);
+ barrelTexture = gl.createTexture();
+ barrelTexture.name = "barrelTexture"
+ gl.bindTexture(gl.TEXTURE_2D, barrelTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ log("...textureLoaded EXIT");
+ log("*******************************************************************************************");
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function initShaders()
+{
+ log(" initShaders ENTER...")
+
+ 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 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);
+
+ fragmentShader = getShader(gl,
+ "varying highp vec2 vTextureCoord;
+ varying highp vec3 vLighting;
+
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ mediump vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ gl_FragColor = vec4(texelColor.rgb * vLighting, 1.0);
+ }", gl.FRAGMENT_SHADER);
+
+ texturedShaderProgram = gl.createProgram();
+ texturedShaderProgram.name = "TexturedShaderProgram";
+ gl.attachShader(texturedShaderProgram, vertexShader);
+ gl.attachShader(texturedShaderProgram, fragmentShader);
+ gl.linkProgram(texturedShaderProgram);
+
+ if (!gl.getProgramParameter(texturedShaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialize shaders");
+ console.log(gl.getProgramInfoLog(texturedShaderProgram));
+ }
+
+ gl.useProgram(texturedShaderProgram);
+
+ // look up where the vertex data needs to go.
+ vertexPositionAttribute = gl.getAttribLocation(texturedShaderProgram, "aVertexPosition");
+ vertexPositionAttribute.name = "aVertexPosition_AttribLocation";
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ vertexNormalAttribute = gl.getAttribLocation(texturedShaderProgram, "aVertexNormal");
+ vertexPositionAttribute.name = "aVertexNormal_AttribLocation";
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ textureCoordAttribute = gl.getAttribLocation(texturedShaderProgram, "aTextureCoord");
+ vertexPositionAttribute.name = "aTextureCoord_AttribLocation";
+ gl.enableVertexAttribArray(textureCoordAttribute);
+
+ pMatrixUniform = gl.getUniformLocation(texturedShaderProgram, "uPMatrix");
+ pMatrixUniform.name = "uPMatrix_UniformLocation";
+ mvMatrixUniform = gl.getUniformLocation(texturedShaderProgram, "uMVMatrix");
+ mvMatrixUniform.name = "uMVMatrix_UniformLocation";
+ textureSamplerUniform = gl.getUniformLocation(texturedShaderProgram, "uSampler")
+ textureSamplerUniform.name = "uSampler_UniformLocation";
+ nMatrixUniform = gl.getUniformLocation(texturedShaderProgram, "uNormalMatrix");
+ nMatrixUniform.name = "uNormalMatrix_UniformLocation";
+ log(" ... initShaders EXIT");
+}
+
+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;
+}
diff --git a/examples/canvas3d/interaction/qml/interaction/main.qml b/examples/canvas3d/interaction/qml/interaction/main.qml
new file mode 100644
index 0000000..ac9be9a
--- /dev/null
+++ b/examples/canvas3d/interaction/qml/interaction/main.qml
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtCanvas3D 1.0
+//! [0]
+import QtQuick.Controls 1.0
+import QtQuick.Layouts 1.0
+//! [0]
+
+import "interaction.js" as GLCode
+
+Item {
+ id: mainview
+ width: 1280
+ height: 768
+ visible: true
+
+ Canvas3D {
+ id: canvas3d
+ anchors.fill: parent
+ imageLoader: textureImageLoader
+ focus: true
+ //! [3]
+ property double xRotSlider: 0
+ property double yRotSlider: 0
+ property double zRotSlider: 0
+ //! [3]
+
+ // Called by Canvas 3D once on Scene Graph render thread
+ // to allow one time initializations to happen
+ function initGL() {
+ GLCode.initGL(canvas3d, textureImageLoader);
+ }
+
+ // Called by Canvas 3D for every frame
+ // rendered on Scene Graph render thread
+ function renderGL() {
+ GLCode.renderGL(canvas3d);
+ }
+ }
+
+ //! [1]
+ RowLayout {
+ id: controlLayout
+ spacing: 5
+ y: parent.height - 100
+ width: parent.width
+ height: 100
+ visible: true
+ //! [1]
+
+ Label {
+ id: xRotLabel
+ Layout.alignment: Qt.AlignRight
+ Layout.fillWidth: false
+ text: "X-axis:"
+ color: "#FFFFFF"
+ }
+
+ //! [2]
+ Slider {
+ id: xSlider
+ Layout.alignment: Qt.AlignLeft
+ Layout.preferredWidth : 300
+ Layout.fillWidth: true
+ minimumValue: 0;
+ maximumValue: 360;
+ //! [4]
+ onValueChanged: canvas3d.xRotSlider = value;
+ //! [4]
+ }
+ //! [2]
+
+ Label {
+ id: yRotLabel
+ Layout.alignment: Qt.AlignRight
+ Layout.fillWidth: false
+ text: "Y-axis:"
+ color: "#FFFFFF"
+ }
+
+ Slider {
+ id: ySlider
+ Layout.alignment: Qt.AlignLeft
+ Layout.preferredWidth : 300
+ Layout.fillWidth: true
+ minimumValue: 0;
+ maximumValue: 360;
+ onValueChanged: canvas3d.yRotSlider = value;
+ }
+
+ Label {
+ id: zRotLabel
+ Layout.alignment: Qt.AlignRight
+ Layout.fillWidth: false
+ text: "Z-axis:"
+ color: "#FFFFFF"
+ }
+
+ Slider {
+ id: zSlider
+ Layout.alignment: Qt.AlignLeft
+ Layout.preferredWidth : 300
+ Layout.fillWidth: true
+ minimumValue: 0;
+ maximumValue: 360;
+ onValueChanged: canvas3d.zRotSlider = value;
+ }
+ }
+
+ TextureImageLoader {
+ id: textureImageLoader
+
+ function imageLoaded(textureImage) {
+ if (canvas3d.logAllCalls)
+ console.log("Texture loaded, size "+textureImage.width+"x"+textureImage.height);
+ GLCode.textureLoaded(textureImage);
+ }
+
+ function imageLoadingError(textureImage) {
+ if (GLCode.textureLoadError !== undefined) {
+ GLCode.textureLoadError(textureImage);
+ }
+ console.log("Texture load FAILED, "+textureImage.errorString);
+ }
+ }
+}
diff --git a/examples/canvas3d/interaction/readme.txt b/examples/canvas3d/interaction/readme.txt
new file mode 100644
index 0000000..0996800
--- /dev/null
+++ b/examples/canvas3d/interaction/readme.txt
@@ -0,0 +1,3 @@
+3D Models and textures used in the example courtesy of http://nobiax.deviantart.com/
+
+See 3dmodels.txt for more information about the models. \ No newline at end of file
diff --git a/examples/canvas3d/jsonmodels/3dmodels.txt b/examples/canvas3d/jsonmodels/3dmodels.txt
new file mode 100644
index 0000000..3aea437
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/3dmodels.txt
@@ -0,0 +1,19 @@
+Provided by Nobiax.
+
+ CC0 1.0 Universal (CC0 1.0)
+ Public Domain Dedication
+ No Copyright
+ This license is acceptable for Free Cultural Works
+
+ The person who associated a work with this deed has dedicated the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.
+
+ You can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission.
+
+So absolutely free to use or to modify in any kind of work (personal, commercial or else) =)
+
+Please (no obligation), send me a link of the result at nobiax.deviantart.com or my other account on OpenGameArt.com (yughues) or ShareCG.com (yughues)
+( watch my journal on deviantart to find them ) ;)
+
+Or on Youtube.
+
+For any commissions details are on my DeviantArt account. \ No newline at end of file
diff --git a/examples/canvas3d/jsonmodels/ThreeJSLoader.js b/examples/canvas3d/jsonmodels/ThreeJSLoader.js
new file mode 100644
index 0000000..0131128
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/ThreeJSLoader.js
@@ -0,0 +1,427 @@
+function GLModel() {
+ this.vertices = [];
+ this.normals = [];
+ this.texCoords = [];
+ this.indices = [];
+}
+
+function Geometry() {
+ this.vertices = [];
+ this.faceVertexUvs = [];
+ this.faces = [];
+}
+
+function Face3( a, b, c, normal, color, materialIndex ) {
+
+ this.a = a;
+ this.b = b;
+ this.c = c;
+
+ this.normal = normal instanceof Vector3 ? normal : new Vector3();
+ this.vertexNormals = normal instanceof Array ? normal : [ ];
+
+ this.color = color instanceof Array ? color : [ ];
+ this.vertexColors = color instanceof Array ? color : [];
+
+ this.vertexTangents = [];
+
+ this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
+
+ this.centroid = new Vector3()
+};
+
+function Vector2( x, y ) {
+ this.x = x || 0;
+ this.y = y || 0;
+};
+
+function Vector3( x, y, z ) {
+ this.x = x || 0;
+ this.y = y || 0;
+ this.z = z || 0;
+};
+
+Vector3.prototype = {
+
+ constructor: Vector3,
+
+ set: function ( x, y, z ) {
+
+ this.x = x;
+ this.y = y;
+ this.z = z;
+
+ return this;
+ },
+
+ copy: function ( v ) {
+
+ this.x = v.x;
+ this.y = v.y;
+ this.z = v.z;
+
+ return this;
+
+ }
+};
+
+Face3.prototype = {
+
+ constructor: Face3,
+
+ clone: function () {
+
+ var face = new Face3( this.a, this.b, this.c );
+
+ face.normal.copy( this.normal );
+ face.color.copy( this.color );
+ face.centroid.copy( this.centroid );
+
+ face.materialIndex = this.materialIndex;
+
+ var i, il;
+ for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone();
+ for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone();
+ for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone();
+
+ return face;
+ }
+};
+
+function parseJSON3DModel( json, texturePath )
+{
+ var formatVersion = json.metadata.formatVersion;
+
+ if (formatVersion < 4.0 ) {
+ var i, j;
+ var geometry = new Geometry();
+ var scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0;
+ parseModel( json, geometry, scale );
+
+ // Translate to model we can use from GL
+ var glModel = new GLModel();
+
+ for (i = 0; i < geometry.vertices.length; i++) {
+ glModel.vertices.push(geometry.vertices[i].x);
+ glModel.vertices.push(geometry.vertices[i].y);
+ glModel.vertices.push(geometry.vertices[i].z);
+ }
+
+ glModel.texCoords[0] = [];
+ for (var faceIdx = 0; faceIdx < geometry.faces.length; faceIdx++) {
+ var face = geometry.faces[faceIdx];
+ // Array indices
+ glModel.indices.push(face.a);
+ glModel.indices.push(face.b);
+ glModel.indices.push(face.c);
+
+ // Materials
+ // face.materialIndex
+
+ // Only parse first layer of UVs for this face
+ for(var uvLayer = 0; uvLayer < geometry.faceVertexUvs.length; uvLayer++) {
+ var faceUVs = geometry.faceVertexUvs[uvLayer][faceIdx];
+ var idxUVA = face.a * 2;
+ var idxUVB = face.b * 2;
+ var idxUVC = face.c * 2;
+
+ glModel.texCoords[uvLayer][idxUVA++] = faceUVs[0].x;
+ glModel.texCoords[uvLayer][idxUVA ] = faceUVs[0].y;
+ glModel.texCoords[uvLayer][idxUVB++] = faceUVs[1].x;
+ glModel.texCoords[uvLayer][idxUVB ] = faceUVs[1].y;
+ glModel.texCoords[uvLayer][idxUVC++] = faceUVs[2].x;
+ glModel.texCoords[uvLayer][idxUVC ] = faceUVs[2].y;
+ }
+
+ // Normal
+ if (face.vertexNormals !== undefined) {
+ // Per vertex normals
+ var idxA = face.a * 3;
+ var idxB = face.b * 3;
+ var idxC = face.c * 3;
+ var vrtNormals = face.vertexNormals;
+
+ glModel.normals[idxA++] = vrtNormals[0].x;
+ glModel.normals[idxA++] = vrtNormals[0].y;
+ glModel.normals[idxA ] = vrtNormals[0].z;
+
+ glModel.normals[idxB++] = vrtNormals[1].x;
+ glModel.normals[idxB++] = vrtNormals[1].y;
+ glModel.normals[idxB ] = vrtNormals[1].z;
+
+ glModel.normals[idxC++] = vrtNormals[2].x;
+ glModel.normals[idxC++] = vrtNormals[2].y;
+ glModel.normals[idxC ] = vrtNormals[2].z;
+ } else if (face.normal !== undefined) {
+ // Per face normal
+ glModel.normals[idxA++] = face.normal.x;
+ glModel.normals[idxA++] = face.normal.y;
+ glModel.normals[idxA ] = face.normal.z;
+
+ glModel.normals[idxB++] = face.normal.x;
+ glModel.normals[idxB++] = face.normal.y;
+ glModel.normals[idxB ] = face.normal.z;
+
+ glModel.normals[idxC++] = face.normal.x;
+ glModel.normals[idxC++] = face.normal.y;
+ glModel.normals[idxC ] = face.normal.z;
+ }
+ }
+ }
+
+ return glModel;
+};
+
+function parseModel( json, geometry, scale ) {
+
+ function isBitSet( value, position )
+ {
+ return value & ( 1 << position );
+ }
+
+ var i, j, fi,
+
+ offset, zLength,
+
+ colorIndex, normalIndex, uvIndex, materialIndex,
+
+ type,
+ isQuad,
+ hasMaterial,
+ hasFaceVertexUv,
+ hasFaceNormal, hasFaceVertexNormal,
+ hasFaceColor, hasFaceVertexColor,
+
+ vertex, face, faceA, faceB, color, hex, normal,
+
+ uvLayer, uv, u, v,
+
+ faces = json.faces,
+ vertices = json.vertices,
+ normals = json.normals,
+ colors = json.colors,
+
+ nUvLayers = 0;
+
+ if ( json.uvs !== undefined ) {
+ // disregard empty arrays
+ for ( i = 0; i < json.uvs.length; i++ ) {
+ if ( json.uvs[ i ].length > 0 ) nUvLayers ++;
+ }
+
+ for ( i = 0; i < nUvLayers; i++ ) {
+ geometry.faceVertexUvs[ i ] = [];
+ }
+ }
+
+ offset = 0;
+ zLength = vertices.length;
+
+ while ( offset < zLength ) {
+ vertex = new Vector3();
+
+ vertex.x = vertices[ offset ++ ] * scale;
+ vertex.y = vertices[ offset ++ ] * scale;
+ vertex.z = vertices[ offset ++ ] * scale;
+
+ geometry.vertices.push( vertex );
+ }
+
+ offset = 0;
+ zLength = faces.length;
+
+ while ( offset < zLength ) {
+ type = faces[ offset ++ ];
+
+ isQuad = isBitSet( type, 0 );
+ hasMaterial = isBitSet( type, 1 );
+ hasFaceVertexUv = isBitSet( type, 3 );
+ hasFaceNormal = isBitSet( type, 4 );
+ hasFaceVertexNormal = isBitSet( type, 5 );
+ hasFaceColor = isBitSet( type, 6 );
+ hasFaceVertexColor = isBitSet( type, 7 );
+
+ // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor);
+
+ if ( isQuad ) {
+ faceA = new Face3();
+ faceA.a = faces[ offset ];
+ faceA.b = faces[ offset + 1 ];
+ faceA.c = faces[ offset + 3 ];
+
+ faceB = new Face3();
+ faceB.a = faces[ offset + 1 ];
+ faceB.b = faces[ offset + 2 ];
+ faceB.c = faces[ offset + 3 ];
+
+ offset += 4;
+
+ if ( hasMaterial ) {
+ materialIndex = faces[ offset ++ ];
+ faceA.materialIndex = materialIndex;
+ faceB.materialIndex = materialIndex;
+ }
+
+ // to get face <=> uv index correspondence
+ fi = geometry.faces.length;
+
+ if ( hasFaceVertexUv ) {
+ for ( i = 0; i < nUvLayers; i++ ) {
+ uvLayer = json.uvs[ i ];
+ geometry.faceVertexUvs[ i ][ fi ] = [];
+ geometry.faceVertexUvs[ i ][ fi + 1 ] = []
+
+ for ( j = 0; j < 4; j ++ ) {
+ uvIndex = faces[ offset ++ ];
+
+ u = uvLayer[ uvIndex * 2 ];
+ v = uvLayer[ uvIndex * 2 + 1 ];
+
+ uv = new Vector2( u, v );
+
+ if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv );
+ if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv );
+ }
+ }
+ }
+
+ if ( hasFaceNormal ) {
+ normalIndex = faces[ offset ++ ] * 3;
+ faceA.normal.set(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+ faceB.normal.copy( faceA.normal );
+ }
+
+ if ( hasFaceVertexNormal ) {
+ for ( i = 0; i < 4; i++ ) {
+ normalIndex = faces[ offset ++ ] * 3;
+ normal = new Vector3(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+
+ if ( i !== 2 ) faceA.vertexNormals.push( normal );
+ if ( i !== 0 ) faceB.vertexNormals.push( normal );
+ }
+ }
+
+ if ( hasFaceColor ) {
+ colorIndex = faces[ offset ++ ];
+ hex = colors[ colorIndex ];
+ // faceA.color.setHex( hex );
+ // faceB.color.setHex( hex );
+ }
+
+ if ( hasFaceVertexColor ) {
+ for ( i = 0; i < 4; i++ ) {
+ colorIndex = faces[ offset ++ ];
+ hex = colors[ colorIndex ];
+
+ // if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) );
+ // if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) );
+ }
+ }
+
+ geometry.faces.push( faceA );
+ geometry.faces.push( faceB );
+
+ } else {
+ face = new Face3();
+ face.a = faces[ offset ++ ];
+ face.b = faces[ offset ++ ];
+ face.c = faces[ offset ++ ];
+
+ if ( hasMaterial ) {
+ materialIndex = faces[ offset ++ ];
+ face.materialIndex = materialIndex;
+ }
+
+ // to get face <=> uv index correspondence
+
+ fi = geometry.faces.length;
+
+ if ( hasFaceVertexUv ) {
+
+ for ( i = 0; i < nUvLayers; i++ ) {
+
+ uvLayer = json.uvs[ i ];
+
+ geometry.faceVertexUvs[ i ][ fi ] = [];
+
+ for ( j = 0; j < 3; j ++ ) {
+
+ uvIndex = faces[ offset ++ ];
+
+ u = uvLayer[ uvIndex * 2 ];
+ v = uvLayer[ uvIndex * 2 + 1 ];
+
+ uv = new Vector2( u, v );
+
+ geometry.faceVertexUvs[ i ][ fi ].push( uv );
+
+ }
+
+ }
+
+ }
+
+ if ( hasFaceNormal ) {
+
+ normalIndex = faces[ offset ++ ] * 3;
+
+ face.normal.set(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+
+ }
+
+ if ( hasFaceVertexNormal ) {
+
+ for ( i = 0; i < 3; i++ ) {
+
+ normalIndex = faces[ offset ++ ] * 3;
+
+ normal = new Vector3(
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ++ ],
+ normals[ normalIndex ]
+ );
+
+ face.vertexNormals.push( normal );
+
+ }
+
+ }
+
+
+ if ( hasFaceColor ) {
+ // colorIndex = faces[ offset ];
+ offset++;
+ // face.color.setHex( colors[ colorIndex ] );
+ }
+
+
+ if ( hasFaceVertexColor ) {
+
+ for ( i = 0; i < 3; i++ ) {
+
+ // colorIndex = faces[offset];
+ offset++;
+ // face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) );
+
+ }
+
+ }
+
+ geometry.faces.push( face );
+
+ }
+
+ }
+};
diff --git a/examples/canvas3d/jsonmodels/bush.json b/examples/canvas3d/jsonmodels/bush.json
new file mode 100644
index 0000000..f05ed58
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/bush.json
@@ -0,0 +1,47 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "generatedBy" : "Blender 2.7 Exporter",
+ "vertices" : 1225,
+ "faces" : 324,
+ "normals" : 325,
+ "colors" : 0,
+ "uvs" : [49],
+ "materials" : 1,
+ "morphTargets" : 0,
+ "bones" : 0
+ },
+
+ "scale" : 30.000000,
+
+ "materials" : [ {
+ "DbgColor" : 15658734,
+ "DbgIndex" : 0,
+ "DbgName" : "default",
+ "vertexColors" : false
+ }],
+
+ "vertices" : [0,13,1.54972e-06,0,10.6569,-5.6569,-4,10.6569,-4,-5.6569,10.6569,1.2704e-06,-4,10.6569,4,0,10.6569,5.6569,4,10.6569,4,5.6569,10.6569,1.2704e-06,4,10.6569,-4,-5.6569,5,-5.6569,0,5,-8,-8,5,5.96046e-07,-5.6569,5,5.6569,0,5,8,5.6569,5,5.6569,8,5,5.96046e-07,5.6569,5,-5.6569,-4,-0.6569,-4,0,-0.656899,-5.6569,-5.6569,-0.6569,-7.83086e-08,-4,-0.6569,4,0,-0.656901,5.6569,4,-0.6569,4,5.6569,-0.6569,-7.83086e-08,4,-0.6569,-4,4.7194,2.8729,-5.1337,5.8136,7.6082,-8.3581,1.9049,8.4542,-8.442,0.8108,3.7189,-5.2176,5.6035,7.0429,-4.2721,5.0209,3.8692,-9.1306,1.1123,4.7152,-9.2146,1.6948,7.8889,-4.3561,3.3392,9.9719,-5.9958,2.1984,4.9781,-3.2071,1.8658,3.0928,-6.7193,3.0066,8.0867,-9.5079,0.2502,16.042,-1.429,3.912,15.7558,3.1015,2.7438,11.996,3.8083,-0.9181,12.2822,-0.722299,4.3995,14.8523,-0.899098,0.1916,16.8225,2.6264,-0.9766,13.0627,3.3331,3.2312,11.0925,-0.192399,5.3372,12.0368,1.9064,1.3226,12.4936,-2.2996,-1.3334,13.8226,0.379802,2.6812,13.3658,4.5859,-0.0344,1.8099,10.1176,-2.3699,5.5228,6.2736,1.295,6.6733,5.1581,3.6305,2.9604,9.0021,-1.2288,1.5671,5.943,-1.299,5.7405,10.0167,2.366,6.891,8.9012,2.4361,2.7176,4.8275,0.2345,4.291,3.2754,2.555,0.955899,7.4598,2.3675,4.0291,10.0133,0.047,7.3642,5.8288,6.5189,2.7133,-2.9158,4.6298,3.6351,2.5246,6.3282,7.2566,2.5007,8.2173,6.3348,-2.9397,2.923,4.4114,-1.1555,7.854,2.1126,0.9462,9.5524,5.7341,0.922401,4.6214,8.0328,-1.1794,3.2572,7.4405,1.5629,5.5689,6.3219,-3.6737,8.8249,4.8065,-1.9125,6.5132,5.9251,3.324,-9.8922,2.3123,5.3327,-8.1886,6.7503,8.7119,-5.1192,7.4508,6.2445,-6.8228,3.0128,2.8654,-10.7494,6.5735,5.4761,-7.4201,2.9296,8.5833,-4.3507,3.6301,6.1159,-7.68,7.274,3.0088,-7.6607,9.2445,5.4271,-9.0676,4.5059,2.3316,-6.6912,2.2816,4.6564,-5.2842,7.0202,7.7519,2.9989,-4.578,0.251099,8.5664,-3.6386,-1.2109,7.598,0.000200305,-2.5605,2.0305,-0.9392,-1.0985,6.4685,-2.9056,2.2706,5.4555,-5.1381,-3.0216,4.4871,-1.4993,-4.3712,5.5001,0.7332,0.9209,8.5365,0.1456,0.5124,2.9019,-0.9849,1.5076,2.5426,-2.454,-2.1954,8.1771,-1.3236,-3.1906,-3.0509,0.281101,-6.7854,-2.7346,5.709,-4.6749,-5.4973,4.8019,-1.928,-5.8136,-0.626,-4.0386,-0.6666,2.2598,-3.7339,-4.8725,3.9348,-7.411,-7.6352,3.0277,-4.6642,-3.4292,1.3528,-0.9871,-2.5391,4.3337,-0.755599,-3.2207,-0.9276,-3.1787,-6.0754,0.541201,-5.5648,-5.3937,5.8024,-3.1417,-2.5498,5.4297,-3.9385,-6.522,8.3182,-7.0841,-6.7993,11.0768,-4.2008,-2.8271,8.1883,-1.0552,-2.4026,8.5773,-6.9358,-6.654,5.496,-4.3966,-6.9313,8.2546,-1.5133,-2.6798,11.3359,-4.0525,-4.6304,11.9586,-6.4061,-1.0438,8.8125,-3.0512,-4.186,6.88,-1.5044,-7.7725,10.0261,-4.8593,-5.8734,2.2994,8.3259,-0.9108,-0.541301,9.4748,-0.2436,-0.961701,5.5533,-5.2062,1.879,4.4044,-1.7249,3.4679,8.9064,-4.6306,-1.589,8.9542,-3.9633,-2.0094,5.0327,-1.0577,3.0474,4.9849,1.1923,1.6918,6.6676,-4.0046,4.0809,5.5272,-5.6932,0.456199,5.6285,-0.4962,-1.9329,6.7689,-0.8272,-0.7778,-3.75,2.675,2.8765,-0.8522,4.4775,3.8691,-4.2823,0.9753,0.214701,-7.1801,-1.012,3.4208,-2.6321,2.8407,-0.8882,-1.8545,4.6432,0.104401,-5.2846,0.7905,4.4134,-6.0623,2.0706,5.9031,-3.6386,-1.0825,1.8871,-6.4577,1.7591,-0.838499,-5.7531,4.9122,3.1775,-2.9341,3.0086,6.4469,-5.969,0.9486,8.1718,-0.792299,-0.141,11.6722,-2.3923,1.9189,9.9473,-7.569,-0.8298,6.1784,-3.9423,4.3902,8.4125,-2.6095,3.3006,11.9129,-4.2095,-1.9195,9.6788,-5.5423,-2.5766,9.5739,-2.4945,-0.0695,8.0503,-7.5353,3.3738,9.6798,-6.3153,0.8667,11.2034,-1.2745,-0.1877,1.5359,2.2305,2.0005,1.3303,7.633,5.3279,-0.382101,6.2201,3.1397,-0.1765,0.8177,2.2238,4.2045,4.6752,-0.1616,-1.0624,5.441,3.1657,-2.7748,4.0281,5.5511,2.492,3.2624,5.6721,2.8126,6.3631,3.2843,2.5583,1.0479,1.7854,-1.0524,1.894,4.1731,-0.798201,7.2092,-8.0959,8.1617,3.595,-4.7676,10.3891,-0.645099,-2.1695,11.7162,2.0914,-5.4978,9.4889,6.3315,-4.7959,6.6835,1.1788,-7.7265,11.7145,1.5213,-5.1284,13.0416,4.2578,-2.1978,8.0106,3.9153,-1.3088,8.8038,1.0322,-4.8798,7.0234,5.286,-6.6831,10.5938,5.2666,-3.1121,12.3742,1.0128,-5.9036,11.0855,-5.0806,-0.6182,9.6246,-7.0674,-1.5384,5.7524,-6.6682,-6.8238,7.2133,-4.6813,-4.2079,10.2781,-9.003,-2.1387,10.3485,-3.5504,-3.0589,6.4763,-3.1512,-5.1281,6.4059,-8.6037,-2.2099,6.7744,-9.643,-7.2948,8.2359,-7.1885,-5.5652,8.1967,-3.582,-0.4803,6.7353,-6.0365,-0.9092,6.2484,11.2494,-2.9525,2.5212,7.2557,-2.7595,5.3925,4.4774,-0.7162,9.1196,8.4711,0.8899,3.4334,8.4652,-4.5656,5.0453,9.7521,-4.3726,7.9165,6.9738,1.0829,6.3046,5.6869,-0.0536,3.6538,4.4981,1.5064,7.5073,8.5888,-2.343,8.3857,9.2293,-3.9031,4.5323,5.1386,8.7229,5.8525,-5.5726,11.2542,1.9693,-2.0328,7.8148,1.5488,-0.0345998,5.2834,5.432,-3.5743,9.231,1.5335,-5.6071,10.7987,5.8418,-2.0019,7.3592,5.4213,-0.00359935,5.7915,1.113,-3.6088,8.0444,-0.6526,-2.3683,5.6593,3.5913,-5.5803,6.8818,6.3027,-2.9057,9.2668,2.0588,0.3064,7.9968,11.6918,-6.7289,6.7074,6.0893,-7.7115,3.7563,6.2963,-5.0193,5.0457,11.8989,-4.0367,5.3556,9.5777,-9.4616,9.0756,7.9849,-5.2614,6.1245,8.1919,-2.5692,2.4045,9.7847,-6.7693,2.6406,6.9158,-7.9716,4.2493,12.3582,-6.6267,6.7138,10.9351,-3.8158,5.105,5.4927,-5.1607,-2.3193,6.0733,-8.0278,2.015,4.158,-4.6274,0.1177,0.6656,-4.1761,-4.2165,2.5809,-7.5765,1.4174,3.9553,-8.7091,-1.3354,6.0571,-4.0164,-3.2327,2.5647,-3.5652,-0.4799,0.462901,-8.2579,2.1845,0.521301,-6.6363,-2.3732,2.6125,-9.6148,-3.9949,3.934,-6.2054,0.5628,1.8428,-3.227,4.2853,8.5226,-0.753099,7.8803,5.2585,2.4776,6.4676,6.9875,5.7965,2.8726,10.2516,2.5657,4.0165,4.6273,1.1618,8.1214,8.7512,0.760701,6.7086,10.4802,4.0795,2.6038,6.3563,4.4806,4.8429,4.2888,5.1467,1.6193,7.9,1.8933,4.6387,10.5223,1.8123,7.8623,6.9112,5.0658,-6.4325,7.3393,5.3516,-10.5544,5.0704,1.905,-8.7078,6.5879,-1.3023,-4.5859,8.8568,2.1443,-6.9571,3.5615,3.2622,-10.084,8.4577,3.7785,-8.2374,9.9752,0.571101,-5.1105,5.079,0.0548006,-7.7234,3.5763,-0.749,-3.8898,6.2633,2.7295,-6.2725,9.4728,2.8762,-10.1062,6.7858,-0.602199,-5.4709,9.7015,-1.9262,-0.9997,13.2305,-3.1798,-0.1315,13.5139,0.714502,-4.6027,9.9849,1.9681,-1.2551,9.1236,-2.824,-4.7797,13.7487,-2.3748,-3.9115,14.0321,1.5195,-0.3869,9.4069,1.0703,1.5541,11.1393,-0.650999,-3.2072,8.0268,0.636901,-5.348,11.3978,0.868901,-0.5867,14.5102,-0.418998,-0.8009,11.3101,1.1889,1.6426,7.2736,4.6171,5.2171,8.9898,4.09,2.7736,13.0263,0.661802,-0.0076,10.9669,5.451,0.9313,7.5814,0.795501,4.5058,9.2976,0.268401,3.5669,12.6831,4.9239,3.784,10.1465,6.7269,1.4316,13.8726,2.906,2.2192,11.3183,-0.0697986,4.5715,7.5922,3.7511,-3.9863,1.4432,-0.7391,-4.2798,2.8304,4.9183,-7.3618,5.2653,4.1614,-7.0683,3.8781,-1.496,-6.0952,-0.1529,2.7131,-2.3889,4.2616,1.823,-5.4709,6.6965,1.0661,-9.1772,2.2819,1.9562,-8.408,2.3358,4.979,-7.7926,1.3387,-0.7345,-5.278,4.4377,-1.0045,-5.8934,5.4348,4.709,1.0236,1.8137,6.2869,3.1632,2.746,0.9419,6.462,4.3458,2.5414,4.3225,3.4134,7.8864,3.4754,-0.47,3.5145,0.9648,4.7937,3.4277,4.2637,6.3934,5.0272,6.7742,1.1297,5.114,6.8775,1.2032,1.997,4.5273,0.733199,7.3142,2.94,4.3851,6.9354,5.2902,4.8552,1.6182,0.545,-3.6903,6.8027,4.4561,-0.4172,3.973,2.3864,2.8727,4.9176,-1.5247,-0.400301,7.7473,4.2418,-1.6796,7.8997,1.1415,-2.2201,2.9893,-0.9283,1.0699,3.934,2.1721,1.6104,8.8444,4.6703,2.3041,7.1097,0.5039,-1.0036,9.5006,-1.3805,-1.1773,5.9766,2.7859,2.1304,3.5857,-2.354,-0.938801,7.8529,0.2278,3.0821,11.197,-0.5234,5.8682,8.427,-3.1053,1.8473,5.0829,-3.689,1.7927,10.9624,1.4248,0.632899,8.4089,0.6735,3.419,5.6389,-4.4403,4.5789,8.1924,-2.8814,5.7805,10.6127,-5.0077,1.6738,7.0587,-1.3596,1.1217,5.514,0.7668,5.2284,9.0679,-3.6669,8.0967,7.6795,-3.9356,12.0627,3.4116,0.0351,12.5153,3.5822,0.3037,8.5492,7.8501,-3.4647,7.9601,3.3374,-4.1169,12.1852,7.3048,-0.1462,12.6378,7.4754,0.5059,8.4126,3.5081,-0.7591,10.3102,1.3796,-0.5483,6.7275,5.977,-1.0099,9.8512,8.4324,-1.2207,13.4339,3.835,2.6072,1.1597,-3.656,5.1887,1.1671,-8.8859,6.5009,4.8889,-8.233,3.9193,4.8816,-3.0031,6.5346,0.0369006,-5.1483,1.6672,2.1739,-7.5479,2.9794,5.8957,-6.895,7.8468,3.7587,-4.4953,8.705,2.7342,-7.3141,5.709,2.9132,-2.3133,2.5378,4.3736,-4.2654,5.5338,4.1947,-9.2662,2.1764,1.9597,-1.0969,6.3322,6.0519,-1.119,8.0304,4.3445,2.0748,3.8746,0.2523,2.0969,6.0853,2.3628,-2.9599,2.8273,5.6904,0.551401,4.5256,3.983,3.7452,7.7836,0.6554,0.2339,9.3357,3.2165,-0.6398,4.9118,-0.57,-0.3117,2.9343,1.948,2.0859,7.3582,5.7346,1.7579,7.9339,-3.1221,-4.1082,7.9747,1.6614,-0.7716,4.5302,2.8444,-2.4255,4.4894,-1.9391,-5.7621,6.3923,-2.106,-0.1707,9.357,0.750301,-4.3021,5.9124,1.9333,-5.956,2.9477,-0.923,-1.8246,3.9774,1.1592,0.2576,4.1951,-3.3572,-3.4263,6.2231,-1.1197,-6.0495,6.0054,3.3967,-2.3656,-2.1935,3.3566,-0.9037,-1.7006,-2.4542,-0.8125,-5.6246,-2.776,-0.1066,-6.1175,3.0348,-0.1978,-2.4704,0.1998,-3.8821,-1.4523,0.3762,1.858,-5.3763,0.0543997,2.5639,-6.3945,-0.122,-3.1762,-5.0266,-2.9243,-3.2634,-5.4289,2.8798,-2.8539,-4.7038,2.653,1.0733,-4.3015,-3.1511,0.6638,-4.4762,2.1415,-5.161,0.1401,5.42,-3.7618,2.5433,2.846,-5.6591,-2.073,-0.432499,-7.0583,-2.3874,5.4678,-7.028,-1.7327,2.4375,-2.0878,0.6704,-0.1364,-3.9851,0.0158,2.8938,-8.9253,1.6437,5.2203,-7.6335,-2.898,1.6902,-8.5968,-2.1748,-0.184199,-5.1379,2.3669,3.346,-4.1746,-1.2941,7.9051,6.9961,-1.6922,10.8832,1.9972,2.1295,12.0065,2.3621,2.5276,9.0284,7.361,-0.6206,6.9763,2.8013,-2.296,11.716,5.7584,1.5256,12.8393,6.1233,3.2011,8.0996,3.1661,1.9018,9.3211,0.606601,2.1523,6.7674,5.8442,0.9838,10.1837,7.5657,0.7333,12.7374,2.3281,-3.2567,15.2428,-6.5248,-6.6195,10.4887,-6.1983,-3.5965,8.4646,-4.5355,-0.2337,13.2188,-4.862,-5.9846,13.6034,-3.5612,-4.1735,11.9587,-8.8556,-1.1506,9.9346,-7.1928,-2.9617,11.5793,-1.8983,-5.4715,9.7639,-2.268,-1.9637,14.3566,-3.0547,-0.9273,12.9487,-6.6525,-4.4351,8.356,-5.8658,-4.3276,9.7841,-3.0407,-1.4189,9.3181,1.9931,1.1954,12.0729,0.737501,-1.7133,12.5389,-4.2963,-4.5447,11.7544,0.830101,-1.2242,7.5514,-1.4776,1.3901,10.3063,-2.7332,-1.9304,14.5092,-0.425498,-1.182,13.4484,2.4111,-3.7902,13.5463,-2.8047,-1.3477,10.6469,-4.0805,1.2605,10.549,1.1353,4.7489,16.1406,-1.2419,6.3294,11.419,1.7954,3.8216,9.1831,-0.375299,2.2411,13.9047,-3.4126,7.8283,13.0994,-1.667,3.5682,14.1458,2.1766,1.0605,11.91,0.00580142,5.3206,10.8635,-3.8378,6.7679,9.1557,-1.6651,4.8221,13.9505,-4.3559,2.006,14.3833,-1.5483,3.9518,9.5884,1.1424,-7.0522,1.5254,7.0965,-6.7425,6.6242,4.2818,-5.8072,4.7013,0.901301,-6.1169,-0.3976,3.716,-9.8743,4.0047,4.9053,-4.2121,4.4011,6.2465,-3.2768,2.4782,2.866,-8.939,2.0818,1.5249,-8.9831,5.1712,1.0945,-8.7982,0.1263,4.0154,-4.9111,0.701899,4.7635,-5.0961,5.7468,1.8426,-2.0625,4.7705,11.4486,1.0273,0.884799,8.3874,2.2793,3.7997,5.9511,-0.8105,7.6854,9.0122,1.9907,3.2089,11.663,-2.6068,2.285,8.1952,-1.3549,5.1999,5.7588,3.2426,6.1238,9.2266,4.3742,3.352,8.3501,0.8955,7.1424,11.0974,-2.0609,6.2789,8.5452,1.4178,2.4885,5.7979,-1.8262,6.3621,0.358201,-6.5496,8.8639,-1.9757,-7.2789,10.7212,1.491,-2.5555,8.2194,3.825,-2.602,10.064,-1.7882,-5.854,5.5447,-0.0511993,-6.5833,7.402,3.4156,-3.3313,11.9213,1.6785,-5.5165,12.5895,-0.445099,-1.0946,9.7033,2.0314,-3.5987,6.7652,3.0787,-8.0207,9.6514,0.602201,8.8713,9.9014,4.0968,3.2043,8.5691,3.7409,3.2922,9.2482,-0.200099,8.9592,10.5805,0.155801,6.6073,6.251,3.4173,5.2343,11.8422,4.3501,5.3221,12.5213,0.409202,6.6952,6.9301,-0.523699,3.8305,6.1395,0.425001,9.3563,7.954,0.860901,8.0794,11.6943,1.477,2.5536,9.8798,1.0411,3.6215,-1.2971,-6.8084,3.2455,4.3773,-8.1034,5.1367,5.2802,-4.6963,5.5126,-0.3942,-3.4013,6.1257,1.5408,-8.9504,1.0001,1.8328,-6.1828,2.8913,2.7357,-2.7757,8.0169,2.4436,-5.5433,7.2345,5.019,-7.1203,7.1623,-0.608299,-5.589,3.6379,-0.0695996,-3.7756,3.7101,5.5577,-5.3068,-5.5774,-0.850999,-5.1155,-8.8912,3.3865,-7.3694,-5.9066,5.998,-6.8477,-2.5928,1.7605,-4.5939,-6.2574,0.724401,-9.1116,-8.2815,1.9739,-3.7864,-5.2969,4.5854,-3.2647,-3.2728,3.3359,-8.59,-5.7922,4.723,-9.7984,-2.6674,0.610601,-7.089,-4.2484,1.7176,-3.5854,-7.3732,5.83,-6.2948,-3.7975,8.4394,4.7323,-1.412,4.9794,8.7764,2.1537,6.6682,8.118,-0.2317,10.1282,4.0739,-3.1397,8.7229,9.0218,-2.0018,4.7252,4.9303,1.5639,6.414,4.2719,0.4261,10.4117,8.3634,0.619,8.163,10.517,-1.6581,11.2614,6.1317,-0.7381,8.3233,3.578,1.539,5.2249,7.9633,-4.3932,1.9941,-6.2004,1.1911,3.0445,-4.8854,0.7471,6.8488,-6.0386,-4.8372,5.7985,-7.3536,-2.268,3.3198,-2.6453,-0.7144,1.8558,-8.073,-1.1584,5.6602,-9.2262,-2.712,7.1241,-3.7985,0.2144,6.5539,-2.8804,-5.2132,5.38,-4.6635,-3.818,4.4425,-8.2932,1.6096,5.6165,-6.5101,-9.6761,2.2394,-4.7451,-11.1848,7.638,-3.1339,-7.8836,7.8907,-0.889399,-6.3749,2.4921,-2.5006,-8.928,6.2333,-6.295,-11.8556,4.057,-1.7442,-8.5543,4.3097,0.500301,-5.6268,6.486,-4.0505,-7.3469,9.0791,-3.8296,-6.0991,3.5114,-5.038,-8.1894,2.3472,-1.8325,-9.4372,7.9149,-0.624099,-5.1216,-0.5802,-1.4904,-4.4101,-4.4609,2.8051,-4.3084,-1.4854,5.4764,-5.0199,2.3953,1.181,-7.7976,-2.8192,1.1055,-2.0107,-2.4533,0.4775,-1.909,0.5222,3.1489,-7.6959,0.1563,3.7769,-7.3025,-2.6151,5.154,-7.5069,1.2827,0.8202,-3.5107,1.3007,0.6479,-3.3062,-2.5971,4.9817,3.5958,6.2413,-2.1714,6.7069,1.5887,-3.8117,9.179,2.1509,-0.7177,6.0679,6.8035,0.922601,3.4602,1.9849,-1.2896,6.8285,5.4051,-4.6023,9.3006,5.9673,-1.5083,5.9323,2.5471,1.8044,6.8224,0.1097,0.0728,4.0167,5.0427,1.4182,6.5039,7.1013,-0.943099,9.3096,2.1683,-2.2885,6.5063,7.2567,2.3908,2.4925,10.0851,-0.756699,4.0799,8.6007,-4.1148,8.0936,5.7723,-0.967299,2.5222,6.3128,0.924801,6.0648,10.9315,0.557701,7.6521,9.4471,-2.8004,4.1096,4.8284,-2.4333,1.7018,6.7118,-3.0557,6.0091,4.2967,0.0478005,8.1895,7.6213,-0.391199,3.8822,10.0364,-3.4947,2.115,7.7606,-4.6177,4.2247,2.3539,-5.1952,1.2793,1.4781,-7.7559,-0.8305,6.8848,-7.1785,4.9856,5.8463,-7.2649,1.6508,4.0704,-2.8217,-1.2946,3.1945,-5.3824,2.0402,4.9704,-9.8256,3.8859,2.5034,-9.3368,1.4935,7.7347,-8.3743,-0.6588,6.1982,-5.3731,1.7336,0.966901,-6.3357,2.5905,-1.9232,9.476,5.9234,-3.4478,4.939,4.2566,-0.5509,2.7412,0.9238,0.973699,7.2782,6.5219,-0.764701,8.0215,2.3984,-4.4865,6.2431,0.7317,-1.5896,4.0453,4.8551,2.1321,5.8237,6.9392,0.5092,4.1641,3.2597,1.7036,8.5288,0.6417,-0.930201,7.0426,4.3212,-2.1247,2.6779,2.6349,6.2304,6.0906,1.071,11.1131,8.8709,-2.4908,11.007,7.0537,-0.927,6.1243,4.2734,0.6797,7.1249,9.8708,2.8241,10.3111,5.4814,-0.7378,10.205,3.6643,-2.8822,7.0188,8.0536,-2.6285,9.5191,9.9019,-0.8837,4.9326,6.7496,0.4879,7.4013,3.9169,-1.2569,11.9878,7.0692,6.2631,3.1482,-0.3756,2.9135,7.9152,-0.644799,4.3967,9.1552,2.8569,7.7464,4.3883,3.1262,6.7413,7.155,-1.9971,2.4847,4.3225,0.809101,3.968,5.5626,4.3108,8.2246,8.3951,1.5046,6.086,10.3864,0.412501,9.052,5.3907,0.925301,5.9435,3.7404,2.8264,2.9776,8.7361,2.3136,-3.1459,9.5527,-7.1467,0.6761,13.8549,-6.198,3.4473,11.164,-5.1591,-0.3747,6.8618,-6.1078,-0.205,11.6442,-9.5736,-1.9607,11.9796,-4.0219,0.8105,9.2887,-2.983,2.5661,8.9532,-8.5347,3.6659,11.8623,-8.2911,-0.2945,7.6057,-8.7523,-1.2656,8.0921,-4.9025,2.6949,12.3487,-4.4413,-4.7382,12.9248,-6.8928,-4.9831,11.0736,-1.3674,-3.7057,7.4628,-2.5206,-3.4608,9.3139,-8.0459,-1.9561,12.8419,-3.5513,-7.4776,11.148,-4.3636,-6.2002,7.5371,-5.5167,-0.6787,9.231,-4.7044,-1.2267,9.3105,-1.6344,-1.464,11.007,-7.2095,-5.251,9.739,-7.4342,-5.0138,8.0426,-1.8591,6.56,11.9741,-1.4648,2.7145,16.2757,-2.3159,-0.1073,13.5796,-3.1925,3.7382,9.278,-2.3415,3.733,14.1143,1.0531,5.2493,14.3567,-4.5735,2.4275,11.6606,-5.4501,0.9111,11.4182,0.176401,-0.1889,14.3274,-0.0653983,3.7742,10.0633,0.292101,4.5804,10.486,-3.603,0.6173,14.7501,-3.9604,-11.2149,4.6551,-2.0186,-5.9228,7.0832,-2.3577,-4.3195,3.8223,-0.6857,-9.6115,1.3942,-0.3466,-8.0352,4.6973,-4.9853,-8.7738,7.0454,0.302201,-7.1704,3.7845,1.9743,-6.4319,1.4364,-3.3132,-4.2572,3.5965,-3.8935,-9.5935,1.3822,-3.0948,-9.7818,3.1316,0.4974,-4.4455,5.3459,-0.301199,6.6985,10.7684,3.4579,2.7906,12.567,7.3962,1.0877,8.9478,7.3593,4.9956,7.1492,3.421,6.5081,10.8137,7.8024,2.9614,12.5264,3.5008,1.2585,8.9071,3.4639,4.8052,7.1945,7.7655,3.2983,9.1348,9.688,6.8823,7.4923,5.3898,4.2255,8.77,2.6863,0.6415,10.4125,6.9845,-9.4148,11.377,1.0715,-6.3166,11.0525,6.0024,-4.3524,7.8808,4.5594,-7.4505,8.2054,-0.371399,-5.6581,13.0718,2.4601,-9.6849,9.5329,4.7573,-7.7207,6.3612,3.3143,-3.6939,9.9002,1.0172,-2.753,10.5945,3.9093,-6.1903,10.6094,-0.802599,-8.7563,8.1721,1.0617,-5.319,8.1572,5.7735,-2.2657,7.0978,2.1537,-2.3419,12.2985,4.7924,-3.4487,14.0248,1.3581,-3.3724,8.824,-1.2807,-5.2607,9.4204,4.2863,0.3435,10.216,2.8802,-0.7633,11.9423,-0.554099,-6.3674,11.1467,0.852001,-6.0268,13.259,3.1222,-5.4623,8.1473,0.370901,-1.638,9.0018,-0.431999,-2.2025,14.1134,2.3192,-5.0721,-1.2715,8.3905,-1.342,-1.3374,3.9074,-1.9225,2.5831,3.3668,-5.6527,2.649,7.8499,-0.784,-0.697401,7.9494,-5.1869,-1.8522,4.3029,-5.7675,2.0683,3.7623,-1.3645,3.2232,7.4088,0.607,2.0675,5.2852,-3.4927,2.0324,9.4335,-6.2779,1.2395,6.6742,-2.1783,1.2745,2.5259,4.7605,4.1187,3.626,2.3354,-0.3667,0.7945,5.321,-0.301,-1.8667,7.7461,4.1844,0.9648,5.0798,-0.2112,3.8773,2.0492,3.5156,0.5692,5.0347,3.5813,-2.092,8.0654,-0.1455,1.2161,5.9767,-2.3555,0.5195,8.1285,2.4376,3.0519,5.9129,4.7157,0.622501,3.7612,-0.0773998,-1.9098,-9.0828,-0.381899,-5.1538,-6.284,-4.501,-2.1179,-2.9434,-2.3031,-2.2155,-5.7422,1.816,-5.2514,-8.4337,-1.1809,-0.9285,-6.866,-3.7846,-5.9064,-3.5254,-1.5867,-6.004,-5.0931,1.0171,-1.0261,-4.6254,-1.6878,0.4561,-7.2769,2.1887,-3.0022,-6.0385,0.163601,-6.2217,-3.387,-3.7129,-2.7635,-3.5183,11.6175,-0.0227986,2.2238,10.7936,-0.627299,2.6861,11.1094,3.3333,-3.0561,11.9333,3.9378,-0.8958,8.1485,-0.052299,-0.1277,13.904,-0.600798,0.3346,14.2198,3.3598,-0.4335,8.4643,3.9083,2.3059,8.0317,2.48,-3.3474,9.3541,3.0344,-2.4794,13.2371,2.6235,3.1739,11.9147,2.0691,6.0535,3.9604,4.7958,1.8368,7.9378,4.1503,4.0593,9.8528,1.4312,8.276,5.8754,2.0768,2.5677,4.3571,2.2258,4.9623,7.5821,6.4546,7.1848,9.4971,3.7355,4.7902,6.2721,-0.493199,2.0882,7.7498,0.00400092,6.4976,4.0687,1.0156,7.8815,6.5098,3.8662,3.4722,10.1909,2.8545,4.4101,0.1637,0.1873,1.2883,-3.974,-2.4867,1.5692,-1.96,-5.9312,4.6911,2.1778,-3.2573,5.3527,-3.5343,-1.8981,0.4432,-0.6582,-0.6169,0.7241,1.3558,-4.0614,5.6336,-1.5203,-5.3427,3.9411,-4.1183,-5.6854,6.6232,0.2543,-2.91,3.0824,1.972,-2.1944,0.4003,-2.4006,-4.9699,7.0354,8.9356,-2.0722,6.4395,9.7775,-7.8127,2.6168,10.8193,-7.263,3.2128,9.9774,-1.5226,7.5705,12.3151,-4.7565,5.9597,6.7473,-5.4059,2.1371,7.7891,-4.8562,3.7478,13.3569,-4.2068,4.5137,13.4165,-7.2303,4.967,12.0925,-1.5683,3.8309,8.3389,-2.3551,3.3776,9.6628,-8.0171,-3.3249,15.1893,2.4037,2.1382,13.1821,2.0271,1.1133,9.9846,4.201,-4.3498,11.9918,4.5776,-1.1784,12.6164,-0.368499,0.2136,15.489,4.5128,-0.8114,12.2915,6.6867,-2.2033,9.419,1.8053,0.8252,9.3571,1.0596,-4.4958,11.6071,1.8603,-3.2183,13.4497,5.1728,2.1028,11.1997,4.3721,8.6759,3.4054,-5.4567,2.8735,2.8866,-5.1742,2.5652,6.7869,-4.3423,8.3676,7.3058,-4.6248,5.4144,3.7567,-8.312,5.7978,2.5716,-2.6141,5.4895,6.472,-1.7822,5.1062,7.657,-7.48,2.3066,6.281,-7.508,8.1203,6.6946,-7.2928,8.0354,5.8539,-3.3831,2.2217,5.4404,-3.5983,5.1007,-2.0987,6.6281,5.8461,2.8993,9.5403,3.2915,4.7244,7.0617,2.5462,-0.273601,4.1495,3.1602,-0.200601,10.0258,7.586,1.1974,6.4938,5.0314,3.0225,4.0152,0.6057,1.6245,7.5472,1.7516,3.6149,9.6584,1.3949,-1.2423,6.4494,4.4632,0.0115995,4.2104,4.8199,4.8688,7.4193,-8.5748,1.735,-4.0755,-10.5165,1.0398,1.3801,-8.7781,4.4836,2.4376,-6.8364,5.1787,-3.018,-12.1719,2.8893,-1.9212,-7.2912,0.00490007,-0.5516,-5.5528,3.4486,0.506,-10.4335,6.333,-0.863599,-11.8358,4.9785,1.5716,-9.4761,5.4196,-3.7438,-6.2576,3.4074,-2.482,-8.6173,2.9663,2.8334,0.45,8.1776,-4.5071,4.9467,5.3129,-2.1429,5.1155,2.9301,-5.3513,0.6188,5.7948,-7.7155,4.7749,8.6215,-4.6092,1.0688,4.9149,-2.0514,1.2376,2.5321,-5.2598,4.9437,6.2387,-7.8176,7.0933,5.4421,-5.7018,2.2907,7.9729,-7.8341,0.0274,5.2693,-5.9452,4.83,2.7385,-3.813,3.2538,11.6071,-6.6055,3.0582,6.1741,-4.4933,-0.8801,6.0483,-5.1815,-0.6845,11.4813,-7.2936,3.6785,7.6283,-8.309,2.6774,9.7416,-2.9659,-1.2609,9.6158,-3.6541,-0.2598,7.5025,-8.9971,0.7454,4.8556,-7.6875,0.853,10.4521,-9.3259,0.1573,11.5712,-5.5492,0.0498,5.9747,-3.9107,-9.8299,3.8657,-1.0937,-10.4113,9.0466,-3.7086,-6.5242,9.7816,-3.1166,-5.9428,4.6008,-0.501699,-9.4788,5.3029,-5.1832,-10.7261,7.7579,-0.0418991,-6.839,8.493,0.550201,-5.5918,6.0379,-4.5912,-6.9959,8.4402,-6.0016,-6.5254,3.4931,-2.9485,-7.4124,5.48,0.407801,-7.8828,10.4272,-2.6452,-8.955,0.607901,-3.8478,-10.5175,5.7761,-1.642,-7.0662,7.3574,-2.9024,-5.5038,2.1892,-5.1081,-11.0971,4.0767,-5.3616,-8.5968,2.6659,-0.2847,-5.1455,4.2472,-1.5451,-7.6459,5.658,-6.6219,-9.3718,7.7693,-5.1068,-7.5973,2.4978,-6.8617,-5.9824,1.8428,-3.2613,-7.7569,7.1143,-1.5064,1.5394,0.775199,4.8021,3.5153,-4.361,2.8703,6.216,-2.4701,0.6052,4.2401,2.6661,2.537,4.5962,-2.0306,6.1045,0.7745,-1.8452,1.7026,3.4752,0.0457001,-0.5625,7.2969,-0.1397,3.8394,7.4726,-3.2319,3.4662,5.1711,1.9009,5.0071,2.6781,1.7206,1.8841,4.9796,-3.4122,0.3433,9.1669,4.5457,7.9834,8.9375,7.2598,2.8261,4.9436,7.3253,3.0382,5.173,4.6112,8.1955,9.1663,8.6982,6.6911,8.938,3.5367,3.9849,4.9441,3.6021,4.197,5.1725,8.7636,6.9032,6.1856,10.0372,4.2417,6.3942,6.8835,9.1435,6.2245,3.5193,6.9863,6.0159,6.673,2.0845,3.8172,13.9173,-6.8111,7.3581,13.9917,-2.1772,6.0892,10.3403,-1.149,2.5483,10.2659,-5.7829,7.9246,12.7016,-6.0596,3.6753,15.0817,-2.851,2.4065,11.4303,-1.8228,6.6557,9.0502,-5.0315,8.7294,10.1483,-2.9758,4.8317,10.2816,-7.3125,2.1402,11.9122,-4.8433,6.0379,11.7789,-0.506599,-5.4035,-2.1816,-7.1661,-3.9203,-1.3113,-1.593,-0.4401,0.2732,-2.7666,-1.9233,-0.597199,-8.3397,-5.9201,1.0633,-4.3172,-3.4571,-4.2208,-4.1474,0.0231,-2.6363,-5.3211,-2.4398,2.6478,-5.4908,-2.6568,2.5713,-2.3797,-3.9196,1.2437,-7.9168,-2.1483,-2.3144,-7.4677,-0.8854,-0.9868,-1.9306,-7.673,0.152001,-5.6713,-10.8165,1.2354,-0.8796,-7.9819,3.7443,0.4128,-4.8383,2.6609,-4.3789,-10.7305,3.0492,-4.5893,-8.075,-1.3623,-1.8498,-5.2404,1.1466,-0.5574,-7.8959,5.558,-3.2968,-10.2333,5.3364,-1.2428,-6.8702,3.8727,-5.7776,-5.2439,0.9235,-3.6196,-8.607,2.3871,0.9152,-2.6843,8.8107,2.3521,1.1581,11.9284,-0.735399,-1.6586,12.6906,-3.4712,-5.5011,9.5729,-0.383799,-1.4725,12.9865,2.2678,0.0716,8.1842,-0.659799,-2.7452,8.9464,-3.3957,-4.2893,13.7487,-0.468098,-1.5596,15.0304,-1.2666,-5.2528,11.506,1.5539,-3.9682,8.4114,-0.630799,-0.2749,11.9358,-3.4513,3.7205,9.2795,5.1581,9.032,8.9932,2.7659,8.8275,4.9985,2.7901,3.516,5.2848,5.1823,5.2604,9.1761,1.0923,7.6512,9.0859,6.4114,7.4468,5.0912,6.4356,5.056,5.1814,1.1165,7.7884,6.1681,-0.0201993,2.7055,6.4454,2.8266,4.6564,6.3667,6.3177,9.7393,6.0893,3.4709,2.1846,3.3414,1.1299,2.0009,-0.641501,5.3866,3.9669,1.8594,7.8115,4.1506,5.8423,3.5548,-0.5886,2.4032,4.3458,4.4874,0.1997,2.503,6.4534,2.7006,4.928,1.3775,4.9041,6.7707,0.789,2.1861,8.1841,1.4144,5.9618,3.783,4.8714,4.2182,2.7784,4.246,0.442499,7.1795,0.7515,2.9236,-4.9858,-0.1978,7.4479,-8.5421,3.2322,9.1155,-7.3361,4.1814,4.5912,-3.7799,1.7519,3.8521,-9.115,-1.0948,6.6154,-4.8397,2.3352,8.283,-3.6338,5.1818,5.5197,-7.909,3.705,7.3345,-9.9723,4.4025,3.0683,-6.057,2.4009,5.2267,-3.3486,1.7034,9.4929,-7.2639,-2.8919,8.0489,-8.3322,-7.6552,8.9873,-5.1001,-7.721,5.1216,-4.0746,-2.9577,4.1831,-7.3067,-3.6296,9.1595,-4.1928,-6.9938,7.9915,-8.8117,-7.0596,4.1257,-7.7862,-3.6953,5.2938,-3.1673,-6.0896,6.8416,-1.901,-1.6376,5.8049,-5.5233,-4.2208,5.063,-8.4858,-8.6728,6.0996,-4.8635,-6.3935,2.659,-9.8433,-3.2805,-0.855599,-6.3831,-1.5603,2.3343,-4.6905,-4.6733,5.849,-8.1507,-6.9912,0.896001,-5.913,-2.7445,0.725201,-9.9071,-1.0243,3.9152,-8.2145,-5.271,4.0859,-4.2204,-4.157,1.43,-3.0219,-6.888,4.9164,-6.817,-3.8005,4.5897,-9.339,-1.0694,1.1032,-5.5438,-6.7247,5.3502,-0.436299,-1.3526,5.7491,1.7994,-2.843,7.5118,5.0662,-8.2151,7.1129,2.8305,-4.2399,2.8081,2.069,-3.5805,8.0284,-0.446899,-5.0709,9.7911,2.8198,-5.7303,4.5708,5.3358,-2.624,4.3319,5.496,-7.9182,4.3894,3.0496,-7.1466,7.9799,1.4643,-1.8524,7.9223,3.9107,-6.3796,8.3507,9.207,-4.8863,9.0374,3.611,-2.6613,5.7185,3.7975,-4.1546,5.0318,9.3935,-8.0234,7.0348,5.4019,-3.4124,10.2172,7.0228,-1.1874,6.8983,7.2093,-5.7985,3.716,5.5883,-5.63,5.0345,2.7661,-6.7158,4.6277,8.4821,-3.4762,6.843,9.2551,-2.3904,7.2498,3.5391,0.6262,4.4535,2.4359,4.9541,3.9753,6.3163,2.2728,3.6255,9.2638,-2.0552,4.1037,5.3834,2.9012,1.1484,4.1132,2.9142,6.9388,4.8123,0.2329,6.5889,7.7598,0.2199,0.798599,7.0608,3.1353,0.726999,8.1684,-1.175,1.7081,4.3638,-0.9074,5.6355,5.0733,3.4029,4.6545,8.878,-9.5371,4.4349,2.7643,-5.5796,3.038,-1.2858,-3.4017,1.1557,1.4915,-7.3592,2.5526,5.5416,-8.9668,1.0869,0.0480001,-6.091,6.0399,1.1497,-3.9131,4.1576,3.927,-6.7889,-0.7954,2.8253,-5.3995,-0.9009,0.0341999,-9.0913,0.9223,4.1649,-6.89,4.2228,4.6756,-3.1982,2.3996,0.5448,6.4029,-1.8664,-6.9093,8.5012,1.8068,-2.8941,5.2187,4.0655,-3.2452,3.1205,0.392401,-7.2603,6.1438,-1.5699,-2.5783,8.7335,1.5409,-6.7775,5.451,3.7997,-7.1285,2.8613,0.6889,-2.9293,4.866,1.9164,-0.8784,3.0014,-1.4717,-5.2443,4.8961,0.873201,-7.8732,6.7607,4.2613,-3.5073,-7.5224,12.6626,-3.0458,-3.8054,15.4153,0.507202,-3.3065,12.0422,2.5985,-7.0234,9.2896,-0.954499,-3.2241,13.323,-3.0061,-7.6594,14.8231,0.471602,-7.1604,11.4501,2.5629,-2.7252,9.95,-0.914899,-1.0661,12.2935,0.304501,-5.1555,9.6821,-2.9319,-7.9635,10.8716,-0.343499,-3.8742,13.483,2.8929,1.9866,9.7257,0.154901,0.9664,15.2672,1.6605,-2.4616,14.1632,3.4013,-1.4414,8.6216,1.8956,2.9393,12.2012,3.6011,0.1121,13.0476,-1.4295,-3.3159,11.9435,0.311301,-0.4886,11.0971,5.3419,-0.0601,14.1807,5.5408,0.7098,8.734,3.6024,-1.2828,9.6435,0.255401,-2.0527,15.0902,2.1938,-10.4103,11.5067,-0.901499,-8.9839,6.8863,2.3594,-5.3145,6.8954,0.767201,-6.7409,11.5158,-2.4938,-8.6924,10.9472,3.0543,-10.5242,7.388,-1.1875,-6.8548,7.397,-2.7797,-5.023,10.9563,1.4621,-5.372,8.6098,3.4879,-6.9526,12.9024,-0.130298,-8.1188,10.1945,-2.8335,-6.5382,5.9019,0.784701,8.9495,0.701699,6.8674,4.0984,3.6689,8.1631,2.7839,3.1541,4.4205,7.635,0.1869,3.1248,5.0159,-0.351501,8.3939,7.6254,4.6133,6.7944,6.3109,4.0984,3.0518,3.7014,-0.866301,4.6513,1.6866,0.815899,6.3372,6.7467,-1.7073,4.9071,8.2396,1.8621,3.8917,3.1795,4.3853,5.3218,-4.7574,1.4833,0.3021,-0.0665,2.1157,-3.1055,-2.4099,2.0362,-6.3462,-7.1008,1.4038,-2.9386,-2.5899,4.8731,-1.3484,-2.0099,-0.9237,-1.6256,-4.3533,-1.0032,-4.8663,-4.9334,4.7936,-4.5891,-1.9261,5.0634,-5.3733,-6.5486,3.9282,-2.0028,-5.8719,0.00550029,-2.3959,-1.2493,1.1407,-5.7664,-1.9395,3.117,-7.2097,1.7384,-0.377299,-10.0871,2.6492,-2.2368,-6.6647,-1.0287,1.2575,-3.7873,-2.2819,-0.729999,-9.2087,2.0454,3.072,-8.2947,2.9562,1.2126,-4.8723,-1.3711,-2.5895,-5.7863,0.2545,-3.76,-8.1778,-3.0323,0.0524006,-5.2317,0.144,2.4411,-4.7792,3.4308,-1.3713,-7.7253,2.3925,5.4887,4.084,7.0762,8.5764,5.6796,9.2173,6.8203,2.793,4.5336,3.7326,1.1975,4.0565,9.349,2.9698,5.5843,5.1151,6.6787,7.7253,3.359,3.7921,6.1975,7.593,0.0832009,7.9434,9.5789,1.7384,3.4107,6.134,0.472201,4.7344,3.4258,3.1015,9.2671,6.8708,4.3678,-7.0532,7.9639,1.9473,-6.4205,10.1705,7.3089,-4.0469,7.1042,8.2908,-4.6797,4.8976,2.9291,-4.267,10.7229,3.828,-8.9187,7.6967,5.6225,-6.5452,4.6304,6.6044,-1.8934,7.6566,4.8099,-2.3041,9.5884,7.2247,-3.3399,7.1264,2.0399,-6.4802,5.1907,3.5864,-5.4445,7.6528,8.7712,8.503,-0.7799,1.9103,11.7472,2.729,-1.4333,8.503,4.9026,-2.2999,5.2589,1.3936,1.0437,10.7706,2.8706,2.5773,9.714,-0.5441,-2.0314,6.4698,1.6294,-2.898,7.5264,5.0441,1.7107,10.0486,6.1376,0.236001,6.7247,2.3444,3.1652,6.1967,0.2212,-0.1834,9.5206,4.0144,-3.1126,0.4199,9.1774,11.0116,-2.0343,4.273,9.0266,0.2423,4.4627,5.7432,2.6965,9.3671,7.7282,1.2982,4.9337,11.3754,-2.8218,8.078,8.7004,-0.5452,8.2677,5.417,3.5748,5.1234,8.092,1.6595,2.6627,8.0007,3.7453,7.8224,9.745,0.7838,9.6776,7.7987,-1.302,4.5178,6.0544],
+
+ "morphTargets" : [],
+
+ "normals" : [0,1,0,0,0.662984,-0.748589,-0.529344,0.662984,-0.529344,-0.748589,0.662984,0,-0.529344,0.662984,0.529344,0,0.662984,0.748589,0.529344,0.662984,0.529344,0.748589,0.662984,0,0.529344,0.662984,-0.529344,-0.707083,0,-0.707083,0,0,-1,-1,0,0,-0.707083,0,0.707083,0,0,1,0.707083,0,0.707083,1,0,0,0.707083,0,-0.707083,-0.653279,-0.382672,-0.653279,0,-0.382672,-0.923856,-0.923856,-0.382672,0,-0.653279,-0.382672,0.653279,0,-0.382672,0.923856,0.653279,-0.382672,0.653279,0.923856,-0.382672,0,0.653279,-0.382672,-0.653279,-0.099887,-0.544145,-0.833003,-0.187597,-0.811884,0.552843,0.977142,-0.211493,0.020966,-0.721458,0.337779,0.60445,-0.627827,0.049074,-0.776788,-0.292062,-0.939909,0.176672,-0.012024,0.715537,0.698447,-0.400433,0.636586,-0.659047,0.916227,0.287606,-0.278848,0.845454,-0.394116,0.360332,0.323893,-0.158025,-0.932768,0.424574,0.905362,-0.005951,-0.570818,0.624744,-0.532731,-0.292062,-0.760888,-0.579363,0.767327,0.175115,-0.61684,-0.173681,-0.382733,-0.907346,-0.954558,-0.161046,0.250649,0.242103,-0.909665,0.337413,-0.721122,0.287149,-0.630451,-0.054231,-0.930631,-0.361858,-0.690664,-0.226753,0.686666,-0.728935,-0.528306,0.435347,-0.681051,0.495254,-0.539323,-0.069308,0.689627,0.720817,-0.498184,-0.867,0.008179,-0.850856,0.487045,-0.196966,0.166784,-0.105106,-0.980346,-0.660573,0.738792,-0.133335,-0.600452,-0.626545,-0.496841,0.450606,0.248115,-0.857509,0.894986,0.383038,0.228492,0.353191,-0.295724,-0.88757,0.272408,-0.875088,0.399976,-0.408979,-0.903043,0.13126,-0.375164,0.035249,-0.926267,0.831843,-0.428083,-0.353191,-0.502457,0.862575,0.058687,0.570635,0.381878,-0.726981,0.649525,0.331767,0.684103,0.354747,0.012055,0.934874,-0.906186,0.250465,0.340648,-0.230018,-0.968047,0.099796,0.935362,-0.276345,-0.220618,0.350322,0.639027,0.684744,0.048219,0.717795,-0.69454,0.268807,0.73867,0.618122,-0.434004,0.665792,-0.606891,0.859859,0.105106,-0.499557,0.637806,-0.27308,0.720145,0.221076,0.96057,0.168462,-0.737754,0.051759,0.673025,-0.471969,0.360363,0.804559,0.743126,-0.328379,0.582995,-0.474319,-0.873074,0.112796,0.703787,0.707053,-0.068758,-0.616352,0.559648,-0.553941,-0.35316,0.432234,0.829707,0.536088,-0.839473,-0.088504,0.706717,0.389019,0.59093,0.461623,0.379376,-0.801843,-0.604297,0.792993,0.076998,-0.766594,-0.60506,0.214911,-0.217017,-0.070833,-0.973571,0.160985,-0.580462,-0.798212,-0.418958,0.692068,-0.587756,0.893613,0.429029,-0.131748,-0.635456,-0.75689,0.152623,0.050325,-0.237831,-0.97,-0.77047,0.608692,-0.189215,-0.430433,0.902493,-0.014863,-0.366832,-0.159825,0.91644,-0.824702,-0.399915,-0.399853,-0.531571,-0.092654,-0.841914,-0.670583,-0.561174,0.485153,-0.517441,0.822474,0.236152,0.876766,-0.198859,-0.437819,0.44264,0.689413,0.573351,-0.187811,0.696524,-0.692496,-0.111789,0.724418,0.680227,0.046052,-0.679983,0.731742,0.992645,0.113132,0.042634,0.834529,-0.366375,0.41142,-0.44261,-0.001251,0.896695,0.328013,0.930448,0.163213,-0.55858,0.570513,0.602008,-0.712516,-0.701621,0.003784,-0.424543,0.426832,-0.798456,0.508316,0.489731,-0.708335,-0.006989,-0.820154,-0.572039,-0.86111,0.295755,-0.413465,0.174566,0.030244,0.984161,0.084506,-0.996277,0.015625,-0.980987,-0.080447,0.176458,0.112247,-0.519547,0.847011,-0.791467,-0.56212,-0.239906,0.600757,-0.643483,-0.474319,0.287271,-0.812647,-0.507004,0.068239,-0.510605,0.857082,0.955412,0.280801,0.09122,0.310495,-0.281961,-0.907773,0.576556,0.815088,-0.055971,-0.75573,0.505997,-0.415693,0.569292,-0.720603,-0.395672,-0.498703,0.079867,-0.863063,0.653554,0.688681,-0.313883,0.730399,-0.179418,-0.658986,-0.270974,0.809534,-0.520737,-0.626911,-0.558946,-0.54268,0.970824,0.067965,0.229926,-0.053102,-0.874203,0.482589,-0.233833,0.480728,0.845088,-0.788263,-0.158391,-0.594562,-0.529771,0.666219,0.524857,0.312967,0.728721,-0.609088,-0.557573,-0.774834,0.29783,-0.809839,0.428938,-0.400159,-0.182318,0.464309,0.866665,-0.235389,0.958617,0.159917,0.971618,0.228401,0.061007,0.021943,0.169774,-0.985229,0.878811,-0.05005,-0.474502,0.064425,-0.9729,0.222022,0.472762,0.225684,0.851772,-0.347026,0.21424,0.913022,0.568163,-0.726524,0.386425,-0.746147,-0.652852,-0.130406,0.195074,-0.685415,-0.701498,-0.408979,0.593219,-0.693381,0.891415,0.422163,-0.164586,0.266335,-0.250984,-0.930601,0.957427,0.18009,0.225471,-0.110996,0.951079,-0.288278,-0.501938,-0.373119,0.780267,0.258644,-0.925596,-0.276223,0.825312,0.063173,0.561113,-0.992187,-0.062716,0.107639,-0.121982,0.665365,-0.736473,0.025422,0.743858,0.667806,0.577502,0.586413,-0.56798,-0.533403,0.797723,0.281228,-0.618,-0.140538,-0.773492,0.607379,0.791894,-0.062929,0.688162,-0.484939,0.539659,0.396802,-0.371105,-0.839503,0.571764,0.304453,-0.761803,-0.361736,0.927,0.099002,-0.736351,-0.21894,-0.640156,-0.706992,-0.638081,-0.30491,-0.571429,0.261391,0.777886,0.416669,-0.724204,0.549425,0.367656,0.546281,-0.752556,0.268105,-0.837153,-0.476699,-0.890439,-0.026521,-0.454268,-0.72982,-0.485641,0.481094,-0.574297,0.817316,-0.046144,0.3708,0.310007,0.875423,-0.301004,0.057497,0.951872,-0.655293,-0.737632,-0.162633,0.69277,-0.672719,0.259713,0.946684,0.290414,0.139256,0.041993,0.317362,-0.947356,0.319346,-0.902707,-0.288278,0.259987,0.041536,-0.96469,0.659322,-0.737541,0.145909,0.705435,0.674001,0.219153,-0.126621,0.40257,0.906583,-0.907346,-0.416303,0.058138,0.40083,-0.81521,0.418012,-0.608112,0.293649,-0.73751,-0.670034,0.308359,0.675222,-0.425733,-0.904782,-0.009217,-0.69042,-0.606769,0.393841,-0.531175,0.055635,-0.845393,0.491043,-0.792901,-0.360729,-0.960845,-0.136387,0.241066,0.013062,-0.89169,-0.452437,-0.276681,0.431562,-0.858577,-0.754906,-0.197974,-0.625202,-0.639546,0.011261,0.768639,0.145116,-0.980132,0.135136,-0.519608,0.638966,-0.567156,0.415784,0.769036,0.485458,0.746391,0.016419,-0.665273,-0.268777,0.446425,0.853481,-0.479873,0.706229,-0.520524,0.835139,0.549455,-0.024384,0.131687,0.986816,-0.094028,-0.984527,0.14124,0.103641,-0.115543,-0.078921,-0.990143,0.410565,0.552934,0.725028,0.722983,-0.681936,0.11066,0.55562,0.478744,-0.679739,-0.841762,0.493118,0.219672,-0.535234,-0.709433,-0.458449,0.070223,0.503494,-0.86111,-0.276162,-0.954619,-0.111332,0.102176,-0.144353,0.984222,-0.955657,0.260414,0.137394,-0.238624,-0.492508,-0.83694,-0.936674,0.344157,0.064547,-0.256203,-0.799341,0.543443,0.065706,-0.203162,0.976928,0.994842,0.088931,-0.048402,0.077059,-0.975066,-0.207984,0.758812,0.239692,-0.605579,-0.127781,-0.856929,-0.499283,-0.63863,0.456252,-0.619617,0.836818,-0.494522,0.234809,-0.332926,-0.119175,0.935362,0.434584,0.860927,0.264382,-0.635426,-0.635517,0.438551,-0.770989,0.491165,-0.405347,0.042177,-0.595691,-0.802087,0.171636,-0.362316,-0.916105,0.033509,0.931486,-0.362133,-0.984588,-0.031434,-0.172033,-0.213843,0.420911,0.881497,0.099673,-0.888272,0.448347,-0.97174,-0.183752,-0.148015,0.428694,-0.24189,0.870449,0.267891,-0.886105,-0.378155,0.862789,0.395306,-0.315073,0.655232,-0.03177,0.754723,-0.338755,0.880612,0.331217,0.675161,0.472732,-0.566271,-0.039125,-0.884945,-0.463973,0.039338,-0.465346,0.884243,0.998444,-0.016358,-0.053011,-0.728538,0.408094,0.550127,-0.607074,-0.012726,-0.794519,-0.317209,-0.912839,0.257027,0.422285,-0.905972,0.029084,0.25428,0.149205,0.955535,0.870052,0.3961,-0.293405,0.455275,-0.75634,0.46968,0.538987,-0.185736,-0.821558,0.70864,0.627186,0.323099,-0.264718,0.823359,0.501938,-0.658803,-0.534532,0.529344,-0.704154,0.190527,-0.68395,0.409894,-0.015442,0.911985,-0.910672,0.049074,0.410138,0.051088,0.998657,-0.006012,0.870296,-0.377789,-0.315928,0.031495,0.682882,-0.72982,0.491501,0.625202,0.60622,-0.488052,0.473769,0.732994,-0.162755,0.775689,-0.609729,0.857479,0.416883,0.301462,-0.5768,-0.200262,-0.791925,0.816675,-0.160894,-0.554155,-0.016419,-0.96643,0.256355,-0.728111,0.029267,0.684805,-0.533738,0.602588,-0.593249,0.430036,0.797479,0.423139,0.113041,0.895047,-0.431349,-0.921079,-0.068392,-0.383312,0.37257,-0.440657,-0.816675,0.790582,0.54561,0.277902,-0.25602,-0.11771,0.959471,0.55623,-0.829707,0.046602,-0.002228,-0.992767,-0.119846,-0.742058,0.081973,-0.665273,-0.670339,-0.087436,0.736869,0.493057,0.849208,0.188879,-0.678518,0.239509,0.694418,-0.544481,0.470565,-0.694327,0.444014,0.533341,-0.719962,-0.359752,-0.62978,-0.688406,-0.820612,0.564684,-0.087741,-0.76043,0.257179,0.596271,0.637287,0.471938,0.60918,0.124699,-0.843257,0.522813,-0.484725,0.145085,-0.862514,0.174902,-0.950102,-0.258156,-0.85696,-0.276009,0.435163,0.314066,0.610248,0.727256,-0.244545,0.792199,-0.559099,0.917356,0.002258,-0.398022,0.447401,0.851222,-0.274209,0.831751,-0.508744,-0.222144,0.328593,0.128697,0.935636,0.099429,-0.993896,-0.047517,-0.804285,-0.108402,0.584246,-0.585833,-0.019868,-0.810175,0.741935,0.651875,0.156713,0.630604,-0.599109,-0.493332,0.227699,-0.464858,0.855586,0.26191,-0.725913,0.635914,-0.803034,-0.529405,-0.273537,0.535234,-0.439009,-0.72161,0.797571,0.518845,-0.307657,-0.108463,-0.378338,-0.919279,0.593371,-0.766564,0.24546,-0.181158,-0.585437,-0.790185,-0.5562,-0.601611,0.57326,0.811029,-0.543382,0.216651,-0.706381,0.539109,-0.458632,0.420759,0.840877,0.340312,0.56914,0.047395,-0.820826],
+
+ "colors" : [],
+
+ "uvs" : [[0.2601,0.851,0.1635,0.7071,0.3615,0.7082,0.5001,0.793,0.4981,0.9117,0.3568,0.9948,0.1588,0.9937,0.0202,0.9089,0.0222,0.7902,0.5039,0.5283,0.5759,0.7009,0.7497,0.7009,0.7497,0.5283,0.2512,0.5283,0.2512,0.7009,0.425,0.7009,0.4969,0.5283,0.0054,0.5283,0.0774,0.7009,0.7497,0.1787,0.7497,0.3514,0.5759,0.3514,0.5039,0.1787,0.9954,0.1787,0.9235,0.3514,0.2512,0.1787,0.2512,0.3514,0.0774,0.3514,0.0054,0.1787,0.4969,0.1787,0.425,0.3514,0.9235,0.7009,0.9954,0.5283,0.5759,0.3556,0.7497,0.3556,0.2512,0.3556,0.425,0.3556,0.0774,0.3556,0.7497,0.0061,0.5759,0.0061,0.9235,0.0061,0.2512,0.0061,0.0774,0.0061,0.425,0.0061,0.9235,0.3556,0.5776,0.7509,0.5776,0.9957,0.9436,0.9957,0.9436,0.7509]],
+
+ "faces" : [42,0,1,2,0,0,1,2,0,1,2,42,0,2,3,0,0,2,3,0,2,3,42,0,3,4,0,0,3,4,0,3,4,42,0,4,5,0,0,4,5,0,4,5,42,0,5,6,0,0,5,6,0,5,6,42,0,6,7,0,0,6,7,0,6,7,42,0,7,8,0,0,7,8,0,7,8,42,0,8,1,0,0,8,1,0,8,1,43,9,2,1,10,0,9,10,11,12,9,2,1,10,43,11,3,2,9,0,13,14,15,16,11,3,2,9,43,12,4,3,11,0,17,18,14,13,12,4,3,11,43,13,5,4,12,0,19,20,21,22,13,5,4,12,43,14,6,5,13,0,23,24,20,19,14,6,5,13,43,15,7,6,14,0,25,26,27,28,15,7,6,14,43,16,8,7,15,0,29,30,26,25,16,8,7,15,43,10,1,8,16,0,12,11,31,32,10,1,8,16,43,17,9,10,18,0,33,9,12,34,17,9,10,18,43,19,11,9,17,0,35,13,16,36,19,11,9,17,43,20,12,11,19,0,37,17,13,35,20,12,11,19,43,21,13,12,20,0,38,19,22,39,21,13,12,20,43,22,14,13,21,0,40,23,19,38,22,14,13,21,43,23,15,14,22,0,41,25,28,42,23,15,14,22,43,24,16,15,23,0,43,29,25,41,24,16,15,23,43,18,10,16,24,0,34,12,32,44,18,10,16,24,43,27,26,25,28,0,45,46,47,48,25,25,25,25,43,31,30,29,32,0,45,46,47,48,26,26,26,26,43,33,34,35,36,0,47,46,45,48,27,27,27,27,43,39,38,37,40,0,45,46,47,48,28,28,28,28,43,43,42,41,44,0,45,46,47,48,29,29,29,29,43,47,46,45,48,0,45,46,47,48,30,30,30,30,43,51,50,49,52,0,45,46,47,48,31,31,31,31,43,53,54,55,56,0,47,46,45,48,32,32,32,32,43,59,58,57,60,0,45,46,47,48,33,33,33,33,43,63,62,61,64,0,45,46,47,48,34,34,34,34,43,67,66,65,68,0,45,46,47,48,35,35,35,35,43,71,70,69,72,0,45,46,47,48,36,36,36,36,43,73,74,75,76,0,47,46,45,48,37,37,37,37,43,79,78,77,80,0,45,46,47,48,38,38,38,38,43,83,82,81,84,0,45,46,47,48,39,39,39,39,43,87,86,85,88,0,45,46,47,48,40,40,40,40,43,91,90,89,92,0,45,46,47,48,41,41,41,41,43,93,94,95,96,0,47,46,45,48,42,42,42,42,43,99,98,97,100,0,45,46,47,48,43,43,43,43,43,103,102,101,104,0,45,46,47,48,44,44,44,44,43,107,106,105,108,0,45,46,47,48,45,45,45,45,43,111,110,109,112,0,45,46,47,48,46,46,46,46,43,113,114,115,116,0,47,46,45,48,47,47,47,47,43,119,118,117,120,0,45,46,47,48,48,48,48,48,43,123,122,121,124,0,45,46,47,48,49,49,49,49,43,127,126,125,128,0,45,46,47,48,50,50,50,50,43,131,130,129,132,0,45,46,47,48,51,51,51,51,43,133,134,135,136,0,47,46,45,48,52,52,52,52,43,139,138,137,140,0,45,46,47,48,53,53,53,53,43,143,142,141,144,0,45,46,47,48,54,54,54,54,43,147,146,145,148,0,45,46,47,48,55,55,55,55,43,151,150,149,152,0,45,46,47,48,56,56,56,56,43,153,154,155,156,0,47,46,45,48,57,57,57,57,43,159,158,157,160,0,45,46,47,48,58,58,58,58,43,163,162,161,164,0,45,46,47,48,59,59,59,59,43,167,166,165,168,0,45,46,47,48,60,60,60,60,43,171,170,169,172,0,45,46,47,48,61,61,61,61,43,173,174,175,176,0,47,46,45,48,62,62,62,62,43,179,178,177,180,0,45,46,47,48,63,63,63,63,43,183,182,181,184,0,45,46,47,48,64,64,64,64,43,187,186,185,188,0,45,46,47,48,65,65,65,65,43,191,190,189,192,0,45,46,47,48,66,66,66,66,43,193,194,195,196,0,47,46,45,48,67,67,67,67,43,199,198,197,200,0,45,46,47,48,68,68,68,68,43,203,202,201,204,0,45,46,47,48,69,69,69,69,43,207,206,205,208,0,45,46,47,48,70,70,70,70,43,211,210,209,212,0,45,46,47,48,71,71,71,71,43,213,214,215,216,0,47,46,45,48,72,72,72,72,43,219,218,217,220,0,45,46,47,48,73,73,73,73,43,223,222,221,224,0,45,46,47,48,74,74,74,74,43,227,226,225,228,0,45,46,47,48,75,75,75,75,43,231,230,229,232,0,45,46,47,48,76,76,76,76,43,233,234,235,236,0,47,46,45,48,77,77,77,77,43,239,238,237,240,0,45,46,47,48,78,78,78,78,43,243,242,241,244,0,45,46,47,48,79,79,79,79,43,247,246,245,248,0,45,46,47,48,80,80,80,80,43,251,250,249,252,0,45,46,47,48,81,81,81,81,43,253,254,255,256,0,47,46,45,48,82,82,82,82,43,259,258,257,260,0,45,46,47,48,83,83,83,83,43,263,262,261,264,0,45,46,47,48,84,84,84,84,43,267,266,265,268,0,45,46,47,48,85,85,85,85,43,271,270,269,272,0,45,46,47,48,86,86,86,86,43,273,274,275,276,0,47,46,45,48,87,87,87,87,43,279,278,277,280,0,45,46,47,48,88,88,88,88,43,283,282,281,284,0,45,46,47,48,89,89,89,89,43,287,286,285,288,0,45,46,47,48,90,90,90,90,43,289,290,291,292,0,47,46,45,48,91,91,91,91,43,295,294,293,296,0,45,46,47,48,92,92,92,92,43,299,298,297,300,0,45,46,47,48,93,93,93,93,43,303,302,301,304,0,45,46,47,48,94,94,94,94,43,307,306,305,308,0,45,46,47,48,95,95,95,95,43,309,310,311,312,0,47,46,45,48,96,96,96,96,43,315,314,313,316,0,45,46,47,48,97,97,97,97,43,319,318,317,320,0,45,46,47,48,98,98,98,98,43,323,322,321,324,0,45,46,47,48,99,99,99,99,43,327,326,325,328,0,45,46,47,48,100,100,100,100,43,329,330,331,332,0,47,46,45,48,101,101,101,101,43,335,334,333,336,0,45,46,47,48,102,102,102,102,43,339,338,337,340,0,45,46,47,48,103,103,103,103,43,343,342,341,344,0,45,46,47,48,104,104,104,104,43,347,346,345,348,0,45,46,47,48,105,105,105,105,43,349,350,351,352,0,47,46,45,48,106,106,106,106,43,355,354,353,356,0,45,46,47,48,107,107,107,107,43,359,358,357,360,0,45,46,47,48,108,108,108,108,43,363,362,361,364,0,45,46,47,48,109,109,109,109,43,367,366,365,368,0,45,46,47,48,110,110,110,110,43,369,370,371,372,0,47,46,45,48,111,111,111,111,43,375,374,373,376,0,45,46,47,48,112,112,112,112,43,379,378,377,380,0,45,46,47,48,113,113,113,113,43,383,382,381,384,0,45,46,47,48,114,114,114,114,43,387,386,385,388,0,45,46,47,48,115,115,115,115,43,389,390,391,392,0,47,46,45,48,116,116,116,116,43,395,394,393,396,0,45,46,47,48,117,117,117,117,43,399,398,397,400,0,45,46,47,48,118,118,118,118,43,403,402,401,404,0,45,46,47,48,119,119,119,119,43,407,406,405,408,0,45,46,47,48,120,120,120,120,43,409,410,411,412,0,47,46,45,48,121,121,121,121,43,415,414,413,416,0,45,46,47,48,122,122,122,122,43,419,418,417,420,0,45,46,47,48,123,123,123,123,43,423,422,421,424,0,45,46,47,48,124,124,124,124,43,427,426,425,428,0,45,46,47,48,125,125,125,125,43,429,430,431,432,0,47,46,45,48,126,126,126,126,43,435,434,433,436,0,45,46,47,48,127,127,127,127,43,439,438,437,440,0,45,46,47,48,128,128,128,128,43,443,442,441,444,0,45,46,47,48,129,129,129,129,43,445,446,447,448,0,47,46,45,48,130,130,130,130,43,451,450,449,452,0,45,46,47,48,131,131,131,131,43,455,454,453,456,0,45,46,47,48,132,132,132,132,43,459,458,457,460,0,45,46,47,48,133,133,133,133,43,463,462,461,464,0,45,46,47,48,134,134,134,134,43,465,466,467,468,0,47,46,45,48,135,135,135,135,43,471,470,469,472,0,45,46,47,48,136,136,136,136,43,475,474,473,476,0,45,46,47,48,137,137,137,137,43,479,478,477,480,0,45,46,47,48,138,138,138,138,43,483,482,481,484,0,45,46,47,48,139,139,139,139,43,485,486,487,488,0,47,46,45,48,140,140,140,140,43,491,490,489,492,0,45,46,47,48,141,141,141,141,43,495,494,493,496,0,45,46,47,48,142,142,142,142,43,499,498,497,500,0,45,46,47,48,143,143,143,143,43,503,502,501,504,0,45,46,47,48,144,144,144,144,43,505,506,507,508,0,47,46,45,48,145,145,145,145,43,511,510,509,512,0,45,46,47,48,146,146,146,146,43,515,514,513,516,0,45,46,47,48,147,147,147,147,43,519,518,517,520,0,45,46,47,48,148,148,148,148,43,523,522,521,524,0,45,46,47,48,149,149,149,149,43,525,526,527,528,0,47,46,45,48,150,150,150,150,43,531,530,529,532,0,45,46,47,48,151,151,151,151,43,535,534,533,536,0,45,46,47,48,152,152,152,152,43,539,538,537,540,0,45,46,47,48,153,153,153,153,43,543,542,541,544,0,45,46,47,48,154,154,154,154,43,545,546,547,548,0,47,46,45,48,155,155,155,155,43,551,550,549,552,0,45,46,47,48,156,156,156,156,43,555,554,553,556,0,45,46,47,48,157,157,157,157,43,559,558,557,560,0,45,46,47,48,158,158,158,158,43,563,562,561,564,0,45,46,47,48,159,159,159,159,43,565,566,567,568,0,47,46,45,48,160,160,160,160,43,571,570,569,572,0,45,46,47,48,161,161,161,161,43,575,574,573,576,0,45,46,47,48,162,162,162,162,43,579,578,577,580,0,45,46,47,48,163,163,163,163,43,583,582,581,584,0,45,46,47,48,164,164,164,164,43,585,586,587,588,0,47,46,45,48,165,165,165,165,43,591,590,589,592,0,45,46,47,48,166,166,166,166,43,595,594,593,596,0,45,46,47,48,167,167,167,167,43,599,598,597,600,0,45,46,47,48,168,168,168,168,43,601,602,603,604,0,47,46,45,48,169,169,169,169,43,607,606,605,608,0,45,46,47,48,170,170,170,170,43,611,610,609,612,0,45,46,47,48,171,171,171,171,43,615,614,613,616,0,45,46,47,48,172,172,172,172,43,619,618,617,620,0,45,46,47,48,173,173,173,173,43,621,622,623,624,0,47,46,45,48,174,174,174,174,43,627,626,625,628,0,45,46,47,48,175,175,175,175,43,631,630,629,632,0,45,46,47,48,176,176,176,176,43,635,634,633,636,0,45,46,47,48,177,177,177,177,43,639,638,637,640,0,45,46,47,48,178,178,178,178,43,641,642,643,644,0,47,46,45,48,179,179,179,179,43,647,646,645,648,0,45,46,47,48,180,180,180,180,43,651,650,649,652,0,45,46,47,48,181,181,181,181,43,655,654,653,656,0,45,46,47,48,182,182,182,182,43,659,658,657,660,0,45,46,47,48,183,183,183,183,43,661,662,663,664,0,47,46,45,48,184,184,184,184,43,667,666,665,668,0,45,46,47,48,185,185,185,185,43,671,670,669,672,0,45,46,47,48,186,186,186,186,43,675,674,673,676,0,45,46,47,48,187,187,187,187,43,679,678,677,680,0,45,46,47,48,188,188,188,188,43,681,682,683,684,0,47,46,45,48,189,189,189,189,43,687,686,685,688,0,45,46,47,48,190,190,190,190,43,691,690,689,692,0,45,46,47,48,191,191,191,191,43,695,694,693,696,0,45,46,47,48,192,192,192,192,43,699,698,697,700,0,45,46,47,48,193,193,193,193,43,701,702,703,704,0,47,46,45,48,194,194,194,194,43,707,706,705,708,0,45,46,47,48,195,195,195,195,43,711,710,709,712,0,45,46,47,48,196,196,196,196,43,715,714,713,716,0,45,46,47,48,197,197,197,197,43,719,718,717,720,0,45,46,47,48,198,198,198,198,43,721,722,723,724,0,47,46,45,48,199,199,199,199,43,727,726,725,728,0,45,46,47,48,200,200,200,200,43,731,730,729,732,0,45,46,47,48,201,201,201,201,43,735,734,733,736,0,45,46,47,48,202,202,202,202,43,739,738,737,740,0,45,46,47,48,203,203,203,203,43,741,742,743,744,0,47,46,45,48,204,204,204,204,43,747,746,745,748,0,45,46,47,48,205,205,205,205,43,751,750,749,752,0,45,46,47,48,206,206,206,206,43,755,754,753,756,0,45,46,47,48,207,207,207,207,43,757,758,759,760,0,47,46,45,48,208,208,208,208,43,763,762,761,764,0,45,46,47,48,209,209,209,209,43,767,766,765,768,0,45,46,47,48,210,210,210,210,43,771,770,769,772,0,45,46,47,48,211,211,211,211,43,775,774,773,776,0,45,46,47,48,212,212,212,212,43,777,778,779,780,0,47,46,45,48,213,213,213,213,43,783,782,781,784,0,45,46,47,48,214,214,214,214,43,787,786,785,788,0,45,46,47,48,215,215,215,215,43,791,790,789,792,0,45,46,47,48,216,216,216,216,43,795,794,793,796,0,45,46,47,48,217,217,217,217,43,797,798,799,800,0,47,46,45,48,218,218,218,218,43,803,802,801,804,0,45,46,47,48,219,219,219,219,43,807,806,805,808,0,45,46,47,48,220,220,220,220,43,811,810,809,812,0,45,46,47,48,221,221,221,221,43,815,814,813,816,0,45,46,47,48,222,222,222,222,43,817,818,819,820,0,47,46,45,48,223,223,223,223,43,823,822,821,824,0,45,46,47,48,224,224,224,224,43,827,826,825,828,0,45,46,47,48,225,225,225,225,43,831,830,829,832,0,45,46,47,48,226,226,226,226,43,835,834,833,836,0,45,46,47,48,227,227,227,227,43,837,838,839,840,0,47,46,45,48,228,228,228,228,43,843,842,841,844,0,45,46,47,48,229,229,229,229,43,847,846,845,848,0,45,46,47,48,230,230,230,230,43,851,850,849,852,0,45,46,47,48,231,231,231,231,43,855,854,853,856,0,45,46,47,48,232,232,232,232,43,857,858,859,860,0,47,46,45,48,233,233,233,233,43,863,862,861,864,0,45,46,47,48,234,234,234,234,43,867,866,865,868,0,45,46,47,48,235,235,235,235,43,871,870,869,872,0,45,46,47,48,236,236,236,236,43,875,874,873,876,0,45,46,47,48,237,237,237,237,43,877,878,879,880,0,47,46,45,48,238,238,238,238,43,883,882,881,884,0,45,46,47,48,239,239,239,239,43,887,886,885,888,0,45,46,47,48,240,240,240,240,43,891,890,889,892,0,45,46,47,48,241,241,241,241,43,895,894,893,896,0,45,46,47,48,242,242,242,242,43,897,898,899,900,0,47,46,45,48,243,243,243,243,43,903,902,901,904,0,45,46,47,48,244,244,244,244,43,907,906,905,908,0,45,46,47,48,245,245,245,245,43,911,910,909,912,0,45,46,47,48,246,246,246,246,43,913,914,915,916,0,47,46,45,48,247,247,247,247,43,919,918,917,920,0,45,46,47,48,248,248,248,248,43,923,922,921,924,0,45,46,47,48,249,249,249,249,43,927,926,925,928,0,45,46,47,48,250,250,250,250,43,931,930,929,932,0,45,46,47,48,251,251,251,251,43,933,934,935,936,0,47,46,45,48,252,252,252,252,43,939,938,937,940,0,45,46,47,48,253,253,253,253,43,943,942,941,944,0,45,46,47,48,254,254,254,254,43,947,946,945,948,0,45,46,47,48,255,255,255,255,43,951,950,949,952,0,45,46,47,48,256,256,256,256,43,953,954,955,956,0,47,46,45,48,257,257,257,257,43,959,958,957,960,0,45,46,47,48,258,258,258,258,43,963,962,961,964,0,45,46,47,48,259,259,259,259,43,967,966,965,968,0,45,46,47,48,260,260,260,260,43,971,970,969,972,0,45,46,47,48,261,261,261,261,43,973,974,975,976,0,47,46,45,48,262,262,262,262,43,979,978,977,980,0,45,46,47,48,263,263,263,263,43,983,982,981,984,0,45,46,47,48,264,264,264,264,43,987,986,985,988,0,45,46,47,48,265,265,265,265,43,991,990,989,992,0,45,46,47,48,266,266,266,266,43,993,994,995,996,0,47,46,45,48,267,267,267,267,43,999,998,997,1000,0,45,46,47,48,268,268,268,268,43,1003,1002,1001,1004,0,45,46,47,48,269,269,269,269,43,1007,1006,1005,1008,0,45,46,47,48,270,270,270,270,43,1011,1010,1009,1012,0,45,46,47,48,271,271,271,271,43,1013,1014,1015,1016,0,47,46,45,48,272,272,272,272,43,1019,1018,1017,1020,0,45,46,47,48,273,273,273,273,43,1023,1022,1021,1024,0,45,46,47,48,274,274,274,274,43,1027,1026,1025,1028,0,45,46,47,48,275,275,275,275,43,1031,1030,1029,1032,0,45,46,47,48,276,276,276,276,43,1033,1034,1035,1036,0,47,46,45,48,277,277,277,277,43,1039,1038,1037,1040,0,45,46,47,48,278,278,278,278,43,1043,1042,1041,1044,0,45,46,47,48,279,279,279,279,43,1047,1046,1045,1048,0,45,46,47,48,280,280,280,280,43,1051,1050,1049,1052,0,45,46,47,48,281,281,281,281,43,1053,1054,1055,1056,0,47,46,45,48,282,282,282,282,43,1059,1058,1057,1060,0,45,46,47,48,283,283,283,283,43,1063,1062,1061,1064,0,45,46,47,48,284,284,284,284,43,1067,1066,1065,1068,0,45,46,47,48,285,285,285,285,43,1069,1070,1071,1072,0,47,46,45,48,286,286,286,286,43,1075,1074,1073,1076,0,45,46,47,48,287,287,287,287,43,1079,1078,1077,1080,0,45,46,47,48,288,288,288,288,43,1083,1082,1081,1084,0,45,46,47,48,289,289,289,289,43,1087,1086,1085,1088,0,45,46,47,48,290,290,290,290,43,1089,1090,1091,1092,0,47,46,45,48,291,291,291,291,43,1095,1094,1093,1096,0,45,46,47,48,292,292,292,292,43,1099,1098,1097,1100,0,45,46,47,48,293,293,293,293,43,1103,1102,1101,1104,0,45,46,47,48,294,294,294,294,43,1107,1106,1105,1108,0,45,46,47,48,295,295,295,295,43,1109,1110,1111,1112,0,47,46,45,48,296,296,296,296,43,1115,1114,1113,1116,0,45,46,47,48,297,297,297,297,43,1119,1118,1117,1120,0,45,46,47,48,298,298,298,298,43,1123,1122,1121,1124,0,45,46,47,48,299,299,299,299,43,1127,1126,1125,1128,0,45,46,47,48,300,300,300,300,43,1129,1130,1131,1132,0,47,46,45,48,301,301,301,301,43,1135,1134,1133,1136,0,45,46,47,48,302,302,302,302,43,1139,1138,1137,1140,0,45,46,47,48,303,303,303,303,43,1143,1142,1141,1144,0,45,46,47,48,304,304,304,304,43,1147,1146,1145,1148,0,45,46,47,48,305,305,305,305,43,1149,1150,1151,1152,0,47,46,45,48,306,306,306,306,43,1155,1154,1153,1156,0,45,46,47,48,307,307,307,307,43,1159,1158,1157,1160,0,45,46,47,48,308,308,308,308,43,1163,1162,1161,1164,0,45,46,47,48,309,309,309,309,43,1167,1166,1165,1168,0,45,46,47,48,310,310,310,310,43,1169,1170,1171,1172,0,47,46,45,48,311,311,311,311,43,1175,1174,1173,1176,0,45,46,47,48,312,312,312,312,43,1179,1178,1177,1180,0,45,46,47,48,313,313,313,313,43,1183,1182,1181,1184,0,45,46,47,48,314,314,314,314,43,1187,1186,1185,1188,0,45,46,47,48,315,315,315,315,43,1189,1190,1191,1192,0,47,46,45,48,316,316,316,316,43,1195,1194,1193,1196,0,45,46,47,48,317,317,317,317,43,1199,1198,1197,1200,0,45,46,47,48,318,318,318,318,43,1203,1202,1201,1204,0,45,46,47,48,319,319,319,319,43,1207,1206,1205,1208,0,45,46,47,48,320,320,320,320,43,1209,1210,1211,1212,0,47,46,45,48,321,321,321,321,43,1215,1214,1213,1216,0,45,46,47,48,322,322,322,322,43,1219,1218,1217,1220,0,45,46,47,48,323,323,323,323,43,1223,1222,1221,1224,0,45,46,47,48,324,324,324,324],
+
+ "bones" : [],
+
+ "skinIndices" : [],
+
+ "skinWeights" : [],
+
+ "animations" : []
+
+
+}
diff --git a/examples/canvas3d/jsonmodels/bush.png b/examples/canvas3d/jsonmodels/bush.png
new file mode 100644
index 0000000..9980cf0
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/bush.png
Binary files differ
diff --git a/examples/canvas3d/jsonmodels/deployment.pri b/examples/canvas3d/jsonmodels/deployment.pri
new file mode 100644
index 0000000..5441b63
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/deployment.pri
@@ -0,0 +1,27 @@
+android-no-sdk {
+ target.path = /data/user/qt
+ export(target.path)
+ INSTALLS += target
+} else:android {
+ x86 {
+ target.path = /libs/x86
+ } else: armeabi-v7a {
+ target.path = /libs/armeabi-v7a
+ } else {
+ target.path = /libs/armeabi
+ }
+ export(target.path)
+ INSTALLS += target
+} else:unix {
+ isEmpty(target.path) {
+ qnx {
+ target.path = /tmp/$${TARGET}/bin
+ } else {
+ target.path = /opt/$${TARGET}/bin
+ }
+ export(target.path)
+ }
+ INSTALLS += target
+}
+
+export(INSTALLS)
diff --git a/examples/canvas3d/jsonmodels/doc/images/jsonmodels-example.png b/examples/canvas3d/jsonmodels/doc/images/jsonmodels-example.png
new file mode 100644
index 0000000..64e77a4
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/doc/images/jsonmodels-example.png
Binary files differ
diff --git a/examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc b/examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc
new file mode 100644
index 0000000..0e19a7d
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/doc/src/jsonmodels.qdoc
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example jsonmodels
+ \since QtCanvas3D 1.0
+ \title JSON Models Example
+ \ingroup qtcanvas3d-examples
+ \brief Load and display several JSON models
+
+ The JSON Models Example simply demonstrates loading and displaying more than one JSON model
+ and more than one texture. A simple mouse input handling has also been added, to allow rotating
+ the scene and zooming into it.
+
+ The example incorporates some Qt Quick Enterprise Controls by default, but you can switch to
+ Qt Quick Controls instead by defining \c{#define NO_ENTERPRISE} in \c{main.cpp}. The controls
+ are used to toggle some optional animations and draw options, as well as displaying camera
+ rotations and distance.
+
+ \image jsonmodels-example.png
+
+ \section1 JSON Model Loader
+
+ First we'll include a JSON model parser, which handles parsing the json models into our internal
+ models:
+
+ \snippet jsonmodels/jsonmodels.js 0
+
+ The \c{ThreeJSLoader.js} includes a reimplementation of the json parser in \c{three.js}, but
+ we will not go into the implementation details on that.
+
+ \section1 Loading the Models
+
+ First we need to initialize all array buffers for the models:
+
+ \snippet jsonmodels/jsonmodels.js 1
+ \dots
+
+ Then we request the models to be loaded:
+
+ \snippet jsonmodels/jsonmodels.js 2
+ \dots
+
+ Then, when the load requests return, we handle the models:
+
+ \snippet jsonmodels/jsonmodels.js 3
+ \dots
+
+ Each buffer is bound and filled with the data parsed from the json models:
+
+ \snippet jsonmodels/jsonmodels.js 4
+
+ \section1 Loading the Textures
+
+ First we ask the TextureImageLoader to load the texture images one by one:
+
+ \snippet jsonmodels/jsonmodels.js 5
+ \dots
+
+ Then, after being successfully loaded, we create the textures:
+
+ \snippet jsonmodels/jsonmodels.js 6
+ \dots
+
+ \section1 Input Handling
+
+ First we add a MouseArea to fill the Canvas3D:
+
+ \snippet jsonmodels/jsonmodels.qml 0
+ \dots
+
+ Then we'll add some functionality on it. But first we need to add properties to the canvas
+ with initial values set:
+
+ \snippet jsonmodels/jsonmodels.qml 1
+
+ After that, let's do rotation on mouse movement when the left button is pressed:
+
+ \snippet jsonmodels/jsonmodels.qml 2
+
+ We need to keep the previous x and y to avoid rotation jumping when the mouse button is released
+ and repressed. These are the properties for them:
+
+ \snippet jsonmodels/jsonmodels.qml 3
+
+ Then we'll add zooming by mouse wheel:
+
+ \snippet jsonmodels/jsonmodels.qml 4
+
+ These are then used in the JavaScript side for eye/camera movement calculations:
+
+ \snippet jsonmodels/jsonmodels.js 7
+
+ We want to convert the rotation values into movement, and we do it like this:
+
+ \snippet jsonmodels/jsonmodels.js 8
+
+ */
diff --git a/examples/canvas3d/jsonmodels/glMatrix-0.9.5.min.js b/examples/canvas3d/jsonmodels/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/jsonmodels/gold.jpg b/examples/canvas3d/jsonmodels/gold.jpg
new file mode 100644
index 0000000..ca316d5
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/gold.jpg
Binary files differ
diff --git a/examples/canvas3d/jsonmodels/gold.json b/examples/canvas3d/jsonmodels/gold.json
new file mode 100644
index 0000000..0e586be
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/gold.json
@@ -0,0 +1,47 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "generatedBy" : "Blender 2.7 Exporter",
+ "vertices" : 104,
+ "faces" : 126,
+ "normals" : 84,
+ "colors" : 0,
+ "uvs" : [23],
+ "materials" : 1,
+ "morphTargets" : 0,
+ "bones" : 0
+ },
+
+ "scale" : 1.00000,
+
+ "materials" : [ {
+ "DbgColor" : 15658734,
+ "DbgIndex" : 0,
+ "DbgName" : "default",
+ "vertexColors" : false
+ }],
+
+ "vertices" : [-0.0737,0.0675,-0.0399,-0.0123,0.0675,-0.0829,0.0307,0.0696,-0.0215,-0.0307,0.0675,0.0215,-0.0555,0.105,-0.03,-0.0231,0.105,0.0162,0.0555,0.1047,0.03,-0.0044,0.105,-0.0555,-0.0161,0.105,-0.0576,-0.0099,0.0977,-0.0664,0.0099,0.0978,0.0662,0.0665,0.0716,0.045,0.0696,0.0791,0.0377,0.0123,0.0714,0.0829,0.0687,0.0712,0.0327,-0.0756,0.0675,0.0829,-0.1186,0.0675,0.0215,-0.0572,0.0696,-0.0215,-0.0141,0.0675,0.0399,-0.0971,0.1047,-0.0624,-0.111,0.105,0.0162,-0.0786,0.105,0.0624,-0.0372,0.105,0.0232,-0.0393,0.105,0.0349,-0.0288,0.0977,0.032,-0.0995,0.0791,-0.0783,-0.1074,0.0716,-0.0779,-0.1467,0.0978,-0.0319,-0.1616,0.0714,-0.0399,-0.0951,0.0712,-0.0757,0.1019,0.0675,0.0829,0.0589,0.0675,0.0215,0.1204,0.0696,-0.0215,0.1634,0.0675,0.0399,0.0804,0.1047,-0.0624,0.0665,0.105,0.0162,0.0989,0.105,0.0624,0.1403,0.105,0.0232,0.1383,0.105,0.0349,0.1487,0.0977,0.032,0.078,0.0791,-0.0783,0.0701,0.0716,-0.0779,0.0308,0.0978,-0.0319,0.0159,0.0714,-0.0399,0.0824,0.0712,-0.0757,0.15,0.03,-0.075,0.15,0.03,3.57628e-09,0.075,0.0321,3.82662e-09,0.075,0.03,-0.075,0.0843,0.0672,0.0564,0.1407,0.0675,8.04663e-09,0.1407,0.0675,-0.0564,0.0843,0.0675,-0.0481,0.0927,0.0675,-0.0564,0.0825,0.0602,-0.0601,0.0771,0.0416,0.0708,0.0838,0.0341,0.075,0.1424,0.0603,0.0599,0.15,0.0339,0.075,0.075,0.0337,0.0662,0,0.03,0.075,0,0.03,3.57628e-09,0.075,0.03,0.075,0.0657,0.0672,-0.0564,0.0093,0.0675,8.04663e-09,0.0093,0.0675,0.0564,0.0657,0.0675,0.048,0.0573,0.0675,0.0564,0.0675,0.0602,0.0601,0.0729,0.0416,-0.0708,0.0662,0.0341,-0.075,0.0076,0.0603,-0.0599,0,0.0339,-0.075,0.075,0.0337,-0.0662,-0.075,0.03,-0.075,0,0.03,-0.075,0,0.0321,3.82662e-09,-0.075,0.03,3.57628e-09,-0.0657,0.0675,-0.0564,-0.0657,0.0675,8.04663e-09,-0.0093,0.0672,0.0564,-0.0093,0.0675,-0.0481,-0.0177,0.0675,-0.0564,-0.0075,0.0602,-0.0601,-0.0674,0.0603,0.0599,-0.0088,0.0341,0.075,-0.0021,0.0416,0.0708,-0.075,0.0339,0.075,0,0.0337,0.0662,-0.15,0.03,0.075,-0.15,0.03,3.57628e-09,-0.075,0.0321,3.82662e-09,-0.075,0.03,0.075,-0.0843,0.0672,-0.0564,-0.1407,0.0675,8.04663e-09,-0.1407,0.0675,0.0564,-0.0843,0.0675,0.048,-0.0927,0.0675,0.0564,-0.0825,0.0602,0.0601,-0.0771,0.0416,-0.0708,-0.0838,0.0341,-0.075,-0.1424,0.0603,-0.0599,-0.15,0.0339,-0.075,-0.075,0.0337,-0.0662],
+
+ "morphTargets" : [],
+
+ "normals" : [-0.892087,-0.40141,-0.207373,0.11478,-0.399579,-0.909452,0.663259,-0.604724,-0.44084,-0.621601,-0.629475,0.46617,-0.662191,0.747703,-0.048799,-0.489212,0.791986,0.365215,0.632282,0.773278,0.047182,0.445204,0.790368,-0.42082,-0.218421,0.847438,-0.48381,0.187628,0.533952,-0.824396,-0.194525,0.710196,0.676565,0.641713,-0.47911,0.598834,0.936674,0.316294,0.150182,-0.104282,-0.36494,0.925138,0.766137,-0.581805,-0.272896,-0.110691,-0.401593,0.909085,-0.650624,-0.629261,0.425031,0.640858,-0.604633,-0.472945,0.894009,-0.399365,0.202979,0.171667,0.77337,-0.610218,-0.51033,0.792016,0.334971,-0.179632,0.747917,0.638997,0.547197,0.791162,-0.27311,0.378613,0.847377,0.372204,0.838679,0.53444,0.104617,0.180609,0.315836,-0.931425,-0.342143,-0.478927,-0.808405,-0.702109,0.71041,-0.048036,-0.905118,-0.364574,-0.218635,0.520035,-0.582446,-0.624714,-0.110599,-0.401898,0.908963,0.641438,-0.603748,-0.473281,0.893918,-0.399396,0.203345,0.17127,0.773461,-0.610218,-0.179632,0.747795,0.639149,0.546281,0.791589,-0.27369,0.380444,0.846736,0.371807,0.838832,0.534227,0.104526,0.519669,-0.582507,-0.624958,0.61214,-0.4008,-0.6816,0.776849,-0.62917,0.025025,0,-1,0,-0.615711,-0.399518,-0.679128,-0.490219,0.773644,0.40141,0.609882,0.79223,0.018311,0.51381,0.748405,-0.419324,-0.604724,0.791223,-0.09064,-0.09653,0.84814,-0.52089,-0.626301,0.534593,-0.56737,-0.682943,0.317026,0.65804,-0.183172,-0.479019,0.858455,0.547563,0.71044,0.44203,0.615833,-0.36433,0.698538,-0.784204,-0.582171,0.214667,-0.61214,-0.4008,0.6816,-0.776849,-0.62917,-0.025025,0.615711,-0.399518,0.679128,0.490219,0.773644,-0.40141,-0.609882,0.79223,-0.018311,-0.51381,0.748405,0.419324,0.604907,0.791253,0.089297,0.097354,0.84817,0.520676,0.626179,0.535051,0.567064,0.682943,0.317026,-0.65804,0.183172,-0.479019,-0.858455,-0.547563,0.71044,-0.44203,-0.615833,-0.36433,-0.698538,0.784204,-0.582171,-0.214667,-0.61214,-0.4008,-0.6816,0.615711,-0.399518,-0.679159,0.796686,-0.604022,0.019684,-0.776849,-0.62917,0.025025,-0.51381,0.748405,-0.419324,-0.609882,0.79223,0.018311,0.490219,0.773644,0.40141,0.604724,0.791223,-0.09064,0.09653,0.84814,-0.52089,0.626301,0.534593,-0.56737,-0.547563,0.71044,0.44203,0.183172,-0.479019,0.858455,0.682943,0.317026,0.65804,-0.615833,-0.36433,0.698538,0.784204,-0.582171,0.214667,0.796686,-0.604022,-0.019684],
+
+ "colors" : [],
+
+ "uvs" : [[0.994,0.1384,0.6342,0.1353,0.6333,0.4944,0.9917,0.4982,0.197,0.2357,0.2,0.504,0.469,0.7727,0.4616,0.2729,0.4268,0.2365,0.4842,0.2086,0.1878,0.7906,0.4578,0.9539,0.4929,0.9153,0.0167,0.5126,0.0609,0.8718,0.1631,0.0351,0.9862,0.8596,0.6345,0.8082,0.0088,0.1513,0.6644,0.8554,0.6056,0.8374,0.1417,0.9331,0.5234,0.0476]],
+
+ "faces" : [43,0,1,2,3,0,0,1,2,3,0,1,2,3,43,4,5,6,7,0,4,5,6,7,4,5,6,7,42,8,4,7,0,8,4,7,8,4,7,42,1,9,2,0,1,9,2,1,9,2,43,6,10,11,12,0,6,10,11,12,6,10,11,12,43,3,13,10,5,0,13,14,10,5,3,13,10,5,43,9,0,4,8,0,9,15,4,8,9,0,4,8,42,3,2,13,0,3,2,16,3,2,13,42,6,5,10,0,6,5,10,6,5,10,42,2,6,14,0,2,6,17,2,6,14,43,4,0,3,5,0,4,18,13,5,4,0,3,5,42,11,14,12,0,19,17,20,11,14,12,42,11,10,13,0,11,10,21,11,10,13,42,14,6,12,0,17,6,20,14,6,12,43,11,13,2,14,0,19,16,2,17,11,13,2,14,42,9,8,7,0,9,8,7,9,8,7,43,6,2,9,7,0,6,2,9,7,6,2,9,7,42,0,9,1,0,15,9,22,0,9,1,43,15,16,17,18,0,0,3,2,1,15,16,17,18,43,19,20,21,22,0,6,5,4,7,19,20,21,22,42,23,22,21,0,8,7,4,23,22,21,42,18,17,24,0,1,2,9,18,17,24,43,19,25,26,27,0,6,12,11,10,19,25,26,27,43,16,20,27,28,0,13,5,10,14,16,20,27,28,43,24,23,21,15,0,9,8,4,15,24,23,21,15,42,16,28,17,0,3,16,2,16,28,17,42,19,27,20,0,6,10,5,19,27,20,42,17,29,19,0,2,17,6,17,29,19,43,16,15,21,20,0,13,18,4,5,16,15,21,20,42,26,25,29,0,19,20,17,26,25,29,42,26,28,27,0,11,21,10,26,28,27,42,29,25,19,0,17,20,6,29,25,19,43,26,29,17,28,0,19,17,2,16,26,29,17,28,42,24,22,23,0,9,7,8,24,22,23,43,19,22,24,17,0,6,7,9,2,19,22,24,17,42,15,18,24,0,15,22,9,15,18,24,43,30,31,32,33,0,0,3,2,1,30,16,31,32,43,34,35,36,37,0,6,5,4,7,33,20,34,35,42,38,37,36,0,8,7,4,36,35,34,42,33,32,39,0,1,2,9,32,31,37,43,34,40,41,42,0,6,12,11,10,33,25,26,27,43,31,35,42,43,0,13,5,10,14,16,20,27,28,43,39,38,36,30,0,9,8,4,15,37,36,34,30,42,31,43,32,0,3,16,2,16,28,31,42,34,42,35,0,6,10,5,33,27,20,42,32,44,34,0,2,17,6,31,38,33,43,31,30,36,35,0,13,18,4,5,16,30,34,20,42,41,40,44,0,19,20,17,26,25,38,42,41,43,42,0,11,21,10,26,28,27,42,44,40,34,0,17,20,6,38,25,33,43,41,44,32,43,0,19,17,2,16,26,38,31,28,42,39,37,38,0,9,7,8,37,35,36,43,34,37,39,32,0,6,7,9,2,33,35,37,31,42,30,33,39,0,15,22,9,30,32,37,43,45,46,47,48,0,0,3,2,1,39,40,41,42,43,49,50,51,52,0,6,5,4,7,43,44,45,46,42,53,52,51,0,8,7,4,47,46,45,42,48,47,54,0,1,2,9,42,41,48,43,49,55,56,57,0,6,12,11,10,43,49,50,51,43,46,50,57,58,0,13,5,10,14,40,44,51,52,43,54,53,51,45,0,9,8,4,15,48,47,45,39,42,46,58,47,0,3,16,2,40,52,41,42,49,57,50,0,6,10,5,43,51,44,42,47,59,49,0,2,17,6,41,53,43,43,46,45,51,50,0,13,18,4,5,40,39,45,44,42,56,55,59,0,19,20,17,50,49,53,42,56,58,57,0,11,21,10,50,52,51,42,59,55,49,0,17,20,6,53,49,43,43,56,59,47,58,0,19,17,2,16,50,53,41,52,42,54,52,53,0,9,7,8,48,46,47,43,49,52,54,47,0,6,7,9,2,43,46,48,41,42,45,48,54,0,15,22,9,39,42,48,43,60,61,47,62,0,0,3,2,1,54,55,41,56,43,63,64,65,66,0,6,5,4,7,57,58,59,60,42,67,66,65,0,8,7,4,61,60,59,42,62,47,68,0,1,2,9,56,41,62,43,63,69,70,71,0,6,12,11,10,57,63,64,65,43,61,64,71,72,0,13,5,10,14,55,58,65,66,43,68,67,65,60,0,9,8,4,15,62,61,59,54,42,61,72,47,0,3,16,2,55,66,41,42,63,71,64,0,6,10,5,57,65,58,42,47,73,63,0,2,17,6,41,67,57,43,61,60,65,64,0,13,18,4,5,55,54,59,58,42,70,69,73,0,19,20,17,64,63,67,42,70,72,71,0,11,21,10,64,66,65,42,73,69,63,0,17,20,6,67,63,57,43,70,73,47,72,0,19,17,2,16,64,67,41,66,42,68,66,67,0,9,7,8,62,60,61,43,63,66,68,47,0,6,7,9,2,57,60,62,41,42,60,62,68,0,15,22,9,54,56,62,43,74,75,76,77,0,0,1,2,3,68,69,70,71,43,78,79,80,81,0,4,5,6,7,72,73,74,75,42,82,78,81,0,8,4,7,76,72,75,42,75,83,76,0,1,9,2,69,77,70,43,80,84,85,86,0,6,10,11,12,74,78,79,80,43,77,87,84,79,0,13,14,10,5,71,81,78,73,43,83,74,78,82,0,9,15,4,8,77,68,72,76,42,77,76,87,0,3,2,16,71,70,81,42,80,79,84,0,6,5,10,74,73,78,42,76,80,88,0,2,6,17,70,74,82,43,77,79,78,74,0,13,5,4,18,71,73,72,68,42,85,88,86,0,19,17,20,79,82,80,42,85,84,87,0,11,10,21,79,78,81,42,88,80,86,0,17,6,20,82,74,80,43,85,87,76,88,0,19,16,2,17,79,81,70,82,42,83,82,81,0,9,8,7,77,76,75,43,80,76,83,81,0,6,2,9,7,74,70,77,75,42,74,83,75,0,15,9,22,68,77,69,43,89,90,91,92,0,0,3,2,1,54,55,83,56,43,93,94,95,96,0,6,5,4,7,57,58,59,60,42,97,96,95,0,8,7,4,61,60,59,42,92,91,98,0,1,2,9,56,83,62,43,93,99,100,101,0,6,12,11,10,57,63,64,65,43,90,94,101,102,0,13,5,10,14,55,58,65,66,43,98,97,95,89,0,9,8,4,15,62,61,59,54,42,90,102,91,0,3,16,2,55,66,83,42,93,101,94,0,6,10,5,57,65,58,42,91,103,93,0,2,17,6,83,67,57,43,90,89,95,94,0,13,18,4,5,55,54,59,58,42,100,99,103,0,19,20,17,64,63,67,42,100,102,101,0,11,21,10,64,66,65,42,103,99,93,0,17,20,6,67,63,57,43,100,103,91,102,0,19,17,2,16,64,67,83,66,42,98,96,97,0,9,7,8,62,60,61,43,93,96,98,91,0,6,7,9,2,57,60,62,83,42,89,92,98,0,15,22,9,54,56,62],
+
+ "bones" : [],
+
+ "skinIndices" : [],
+
+ "skinWeights" : [],
+
+ "animations" : []
+
+
+}
diff --git a/examples/canvas3d/jsonmodels/jsonmodels.js b/examples/canvas3d/jsonmodels/jsonmodels.js
new file mode 100644
index 0000000..1d2cd8b
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/jsonmodels.js
@@ -0,0 +1,839 @@
+Qt.include("glMatrix-0.9.5.min.js")
+//! [0]
+Qt.include("ThreeJSLoader.js")
+//! [0]
+
+var gl;
+
+var texturedShaderProgram = 0;
+var vertexShader = 0;
+var fragmentShader = 0;
+
+var vertexPositionAttribute;
+var textureCoordAttribute;
+var vertexNormalAttribute;
+
+var pMatrixUniform;
+var mvMatrixUniform;
+var nMatrixUniform;
+var textureSamplerUniform;
+var eyeUniform;
+
+var modelOneTexture = 0;
+var modelTwoTexture = 0;
+var modelThreeTexture = 0;
+var modelFourTexture = 0;
+var modelFiveTexture = 0;
+
+var vMatrix = mat4.create();
+var mMatrix = mat4.create();
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+var nMatrix = mat4.create();
+
+var fov = degToRad(45);
+var eye = [0, 1, 1];
+var light = [0, 1, 1];
+
+var posOne = [0, 0, 0];
+var posTwo = [0.3, 0, 0];
+var posThree = [-0.1, 0, 0.25];
+var posFour = [0.1, 0, -0.45];
+var posFive = [0, -0.14, 0];
+var posSix = [-1.2, -0.28, 0.0];
+var posSeven = [0.5, -0.28, 0.9];
+var posEight = [0.5, -0.28, -0.9];
+var posNine = [0.55, 0.09, -1.0];
+var posTen = [1.0, 0.09, -0.7];
+
+var rotOne = degToRad(90);
+var rotTwo = degToRad(-80);
+var rotThree = degToRad(15);
+var rotFour = degToRad(40);
+var rotFive = degToRad(60);
+
+var drawMode = 0;
+
+var canvas3d;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+function Model() {
+ this.verticesVBO = 0;
+ this.normalsVBO = 0;
+ this.texCoordVBO = 0;
+ this.indexVBO = 0;
+ this.count = 0;
+}
+
+var modelOne = new Model();
+var modelTwo = new Model();
+var modelThree = new Model();
+var modelFour = new Model();
+var modelFive = new Model();
+
+function initGL(canvas, textureLoader) {
+ canvas3d = canvas
+ log("initGL...")
+ try {
+ gl = canvas.getContext("canvas3d", {depth:true, antialias:true});
+ log(" Received context: "+gl);
+
+ var contextConfig = gl.getContextAttributes();
+ log(" Depth: "+contextConfig.alpha);
+ log(" Stencil: "+contextConfig.stencil);
+ log(" Antialiasing: "+contextConfig.antialias);
+ log(" Premultiplied alpha: "+contextConfig.premultipliedAlpha);
+ log(" Preserve drawingbuffer: "+contextConfig.preserveDrawingBuffer);
+ log(" Prefer Low Power To High Performance: "+contextConfig.preferLowPowerToHighPerformance);
+ log(" Fail If Major Performance Caveat: "+contextConfig.failIfMajorPerformanceCaveat);
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.disable(gl.CULL_FACE);
+ gl.enable(gl.BLEND);
+ gl.enable(gl.DEPTH_WRITE);
+ gl.depthMask(true);
+ gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
+
+ gl.clearColor(0.9, 0.9, 0.9, 1.0);
+ gl.clearDepth(1.0);
+
+ // Set viewport
+ gl.viewport(0, 0,
+ canvas.width * canvas.devicePixelRatio,
+ canvas.height * canvas.devicePixelRatio);
+
+ // Initialize the shader program
+ initShaders();
+
+ // Initialize buffers
+ initBuffers();
+
+ // Load textures
+ loadTextures(textureLoader);
+
+ // Load JSON models
+ loadJSONModels();
+
+ log("...initGL");
+ } catch(e) {
+ console.log("...initGL FAILURE!");
+ console.log(""+e);
+ console.log(""+e.message);
+ }
+}
+
+function renderGL(canvas) {
+ // draw only when we have the meshes and textures
+ if (modelOne.count <= 0 || modelTwo.count <= 0 || modelThree.count <= 0 || modelFour.count <= 0
+ || modelFive.count <= 0 || modelOneTexture == 0 || modelTwoTexture == 0
+ || modelThreeTexture == 0 || modelFourTexture == 0 || modelFiveTexture == 0)
+ return;
+
+ // draw
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ gl.useProgram(texturedShaderProgram);
+
+ // Calculate the perspective projection
+ mat4.perspective(pMatrix, fov, canvas.width / canvas.height, 0.1, 100.0);
+ gl.uniformMatrix4fva(pMatrixUniform, false, pMatrix);
+
+ //! [7]
+ // Get the view matrix
+ mat4.identity(vMatrix);
+ eye = moveEye(canvas.xRot, canvas.yRot, canvas.distance);
+ mat4.lookAt(vMatrix, eye, [0, 0, 0], [0, 1, 0]);
+ //! [7]
+
+ // Apply light position
+ if (canvas3d.animatingLight === true)
+ light = moveEye(canvas.lightX, canvas.lightY, canvas.lightDistance);
+ else
+ light = eye;
+ gl.uniform3fva(eyeUniform, light);
+
+ if (canvas3d.drawWireframe)
+ drawMode = gl.LINES;
+ else
+ drawMode = gl.TRIANGLES;
+
+ // Draw model one
+ // Bind the correct buffers
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelOne.verticesVBO);
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelOne.normalsVBO);
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelOne.texCoordVBO);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, modelOneTexture);
+ gl.uniform1i(textureSamplerUniform, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posOne);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, modelOne.indexVBO);
+ gl.drawElements(drawMode, modelOne.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posTwo);
+ mat4.rotateY(mMatrix, mMatrix, rotTwo);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelOne.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posThree);
+ mat4.rotateY(mMatrix, mMatrix, rotThree);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelOne.count, gl.UNSIGNED_SHORT, 0);
+
+ // Draw model two
+ // Bind the correct buffers
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelTwo.verticesVBO);
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelTwo.normalsVBO);
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelTwo.texCoordVBO);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, modelTwoTexture);
+ gl.uniform1i(textureSamplerUniform, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posOne);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, modelTwo.indexVBO);
+ gl.drawElements(drawMode, modelTwo.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posTwo);
+ mat4.rotateY(mMatrix, mMatrix, rotTwo);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelTwo.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posThree);
+ mat4.rotateY(mMatrix, mMatrix, rotThree);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelTwo.count, gl.UNSIGNED_SHORT, 0);
+
+ // Draw model four
+ // Bind the correct buffers
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelFour.verticesVBO);
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelFour.normalsVBO);
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelFour.texCoordVBO);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, modelFourTexture);
+ gl.uniform1i(textureSamplerUniform, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posFive);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, modelFour.indexVBO);
+ gl.drawElements(drawMode, modelFour.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posSix);
+ mat4.rotateY(mMatrix, mMatrix, rotFour);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelFour.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posSeven);
+ mat4.rotateY(mMatrix, mMatrix, rotOne);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelFour.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posEight);
+ mat4.rotateY(mMatrix, mMatrix, rotFive);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelFour.count, gl.UNSIGNED_SHORT, 0);
+
+ // Draw model five
+ // Bind the correct buffers
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelFive.verticesVBO);
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelFive.normalsVBO);
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelFive.texCoordVBO);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, modelFiveTexture);
+ gl.uniform1i(textureSamplerUniform, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posNine);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, modelFive.indexVBO);
+ gl.drawElements(drawMode, modelFive.count, gl.UNSIGNED_SHORT, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posTen);
+ mat4.rotateX(mMatrix, mMatrix, rotFour);
+ mat4.rotateY(mMatrix, mMatrix, rotFive);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.drawElements(drawMode, modelFive.count, gl.UNSIGNED_SHORT, 0);
+
+ // Draw model three (Includes transparency, must be drawn last)
+ // Bind the correct buffers
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelThree.verticesVBO);
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelThree.normalsVBO);
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, modelThree.texCoordVBO);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, modelThreeTexture);
+ gl.uniform1i(textureSamplerUniform, 0);
+
+ // Calculate the modelview matrix
+ mat4.identity(mMatrix);
+ mat4.translate(mMatrix, mMatrix, posFour);
+ // Calculate normal matrix before scaling, to keep lighting in order
+ // Scale normal matrix with distance instead
+ mat4.copy(nMatrix, mMatrix);
+ mat4.scale(nMatrix, nMatrix, [canvas.distance, canvas.distance, canvas.distance]);
+ mat4.invert(nMatrix, nMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nMatrixUniform, false, nMatrix);
+ // Scale the modelview matrix, and apply the matrix
+ mat4.scale(mMatrix, mMatrix, [canvas.itemSize, canvas.itemSize, canvas.itemSize]);
+ mat4.multiply(mvMatrix, vMatrix, mMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the model
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, modelThree.indexVBO);
+ gl.drawElements(drawMode, modelThree.count, gl.UNSIGNED_SHORT, 0);
+}
+
+//! [8]
+function moveEye(xRot, yRot, distance) {
+ var xAngle = degToRad(xRot);
+ var yAngle = degToRad(yRot);
+
+ var zPos = distance * Math.cos(xAngle) * Math.cos(yAngle);
+ var xPos = distance * Math.sin(xAngle) * Math.cos(yAngle);
+ var yPos = distance * Math.sin(yAngle);
+
+ return [-xPos, yPos, zPos];
+}
+//! [8]
+
+//! [3]
+function handleLoadedModel(jsonObj) {
+ log("handleLoadedModel...");
+ var modelData = parseJSON3DModel(jsonObj, "");
+
+ if (modelOne.count === 0)
+ fillModel(modelData, modelOne);
+ else if (modelTwo.count === 0)
+ fillModel(modelData, modelTwo);
+ //! [3]
+ else if (modelThree.count === 0)
+ fillModel(modelData, modelThree);
+ else if (modelFour.count === 0)
+ fillModel(modelData, modelFour);
+ else if (modelFive.count === 0)
+ fillModel(modelData, modelFive);
+
+ log("...handleLoadedModel");
+}
+
+//! [4]
+function fillModel(modelData, model) {
+ log(" fillModel...");
+ log(" "+model.verticesVBO);
+ gl.bindBuffer(gl.ARRAY_BUFFER, model.verticesVBO);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array(modelData.vertices),
+ gl.STATIC_DRAW);
+
+ log(" "+model.normalsVBO);
+ gl.bindBuffer(gl.ARRAY_BUFFER, model.normalsVBO);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array(modelData.normals),
+ gl.STATIC_DRAW);
+
+ log(" "+model.texCoordVBO);
+ gl.bindBuffer(gl.ARRAY_BUFFER, model.texCoordVBO);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array(modelData.texCoords[0]),
+ gl.STATIC_DRAW);
+
+ log(" "+model.indexVBO);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, model.indexVBO);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ Arrays.newUint16Array(modelData.indices),
+ gl.STATIC_DRAW);
+
+ model.count = modelData.indices.length;
+ log(" ...fillModel");
+}
+//! [4]
+
+//! [6]
+function textureLoaded(textureImage) {
+ log("textureLoaded...")
+ if (textureImage.imageState === TextureImage.LOADING_FINISHED) {
+ log(" processing "+textureImage.source);
+ if (modelOneTexture == 0 && textureImage.source == "qrc:///gold.jpg") {
+ log(" creating model one texture");
+ modelOneTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, modelOneTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ } else if (modelTwoTexture == 0 && textureImage.source == "qrc:///woodbox.jpg") {
+ log(" creating model two texture");
+ modelTwoTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, modelTwoTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ //! [6]
+ } else if (modelThreeTexture == 0 && textureImage.source == "qrc:///bush.png") {
+ log(" creating model three texture");
+ modelThreeTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, modelThreeTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ } else if (modelFourTexture == 0 && textureImage.source == "qrc:///pallet.jpg") {
+ log(" creating model four texture");
+ modelFourTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, modelFourTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ } else if (modelFiveTexture == 0 && textureImage.source == "qrc:///rock.jpg") {
+ log(" creating model five texture");
+ modelFiveTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, modelFiveTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ }
+ }
+
+ gl.bindTexture(gl.TEXTURE_2D, null);
+ log("...textureLoaded");
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function initShaders()
+{
+ log(" initShaders...")
+
+ 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;
+ uniform vec3 eyePos;
+
+ varying highp vec2 vTextureCoord;
+ varying highp vec4 vLighting;
+
+ void main(void) {
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vTextureCoord = aTextureCoord;
+ highp vec4 ambientLight = vec4(0.5, 0.5, 0.5, 1.0);
+ highp vec4 directionalLightColor = vec4(1.0, 1.0, 1.0, 1.0);
+ highp vec3 directionalVector = eyePos;
+ 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);
+
+ fragmentShader = getShader(gl,
+ "varying highp vec2 vTextureCoord;
+ varying highp vec4 vLighting;
+
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ mediump vec4 texelColor = texture2D(uSampler, vTextureCoord);
+ gl_FragColor = vec4(texelColor * vLighting);
+ }", gl.FRAGMENT_SHADER);
+
+ texturedShaderProgram = gl.createProgram();
+ gl.attachShader(texturedShaderProgram, vertexShader);
+ gl.attachShader(texturedShaderProgram, fragmentShader);
+ gl.linkProgram(texturedShaderProgram);
+
+ if (!gl.getProgramParameter(texturedShaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialize shaders");
+ console.log(gl.getProgramInfoLog(texturedShaderProgram));
+ }
+
+ gl.useProgram(texturedShaderProgram);
+
+ // look up where the vertex data needs to go.
+ vertexPositionAttribute = gl.getAttribLocation(texturedShaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ vertexNormalAttribute = gl.getAttribLocation(texturedShaderProgram, "aVertexNormal");
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+ textureCoordAttribute = gl.getAttribLocation(texturedShaderProgram, "aTextureCoord");
+ gl.enableVertexAttribArray(textureCoordAttribute);
+
+ pMatrixUniform = gl.getUniformLocation(texturedShaderProgram, "uPMatrix");
+ mvMatrixUniform = gl.getUniformLocation(texturedShaderProgram, "uMVMatrix");
+ textureSamplerUniform = gl.getUniformLocation(texturedShaderProgram, "uSampler")
+ nMatrixUniform = gl.getUniformLocation(texturedShaderProgram, "uNormalMatrix");
+ eyeUniform = gl.getUniformLocation(texturedShaderProgram, "eyePos");
+ log(" ...initShaders");
+}
+
+//! [1]
+function initBuffers() {
+ modelOne.verticesVBO = gl.createBuffer();
+ modelOne.normalsVBO = gl.createBuffer();
+ modelOne.texCoordVBO = gl.createBuffer();
+ modelOne.indexVBO = gl.createBuffer();
+ modelTwo.verticesVBO = gl.createBuffer();
+ modelTwo.normalsVBO = gl.createBuffer();
+ modelTwo.texCoordVBO = gl.createBuffer();
+ modelTwo.indexVBO = gl.createBuffer();
+ //! [1]
+ modelThree.verticesVBO = gl.createBuffer();
+ modelThree.normalsVBO = gl.createBuffer();
+ modelThree.texCoordVBO = gl.createBuffer();
+ modelThree.indexVBO = gl.createBuffer();
+ modelFour.verticesVBO = gl.createBuffer();
+ modelFour.normalsVBO = gl.createBuffer();
+ modelFour.texCoordVBO = gl.createBuffer();
+ modelFour.indexVBO = gl.createBuffer();
+ modelFive.verticesVBO = gl.createBuffer();
+ modelFive.normalsVBO = gl.createBuffer();
+ modelFive.texCoordVBO = gl.createBuffer();
+ modelFive.indexVBO = gl.createBuffer();
+}
+
+//! [5]
+function loadTextures(textureLoader) {
+ // Load the first texture
+ textureLoader.loadTexture("gold.jpg");
+ log(" loadTexture sent for texture one")
+
+ // Load the second texture
+ textureLoader.loadTexture("woodbox.jpg");
+ log(" loadTexture sent for texture two")
+ //! [5]
+
+ // Load the third texture
+ textureLoader.loadTexture("bush.png");
+ log(" loadTexture sent for texture three")
+
+ // Load the fourth texture
+ textureLoader.loadTexture("pallet.jpg");
+ log(" loadTexture sent for texture four")
+
+ // Load the fifth texture
+ textureLoader.loadTexture("rock.jpg");
+ log(" loadTexture sent for texture five")
+}
+
+//! [2]
+function loadJSONModels() {
+ // Load the first model
+ var request = new XMLHttpRequest();
+ request.open("GET", "gold.json");
+ request.onreadystatechange = function () {
+ if (request.readyState === XMLHttpRequest.DONE) {
+ handleLoadedModel(JSON.parse(request.responseText));
+ }
+ }
+ request.send();
+ log(" XMLHttpRequest sent for model one")
+
+ // Load the second model
+ var request2 = new XMLHttpRequest();
+ request2.open("GET", "woodbox.json");
+ request2.onreadystatechange = function () {
+ if (request2.readyState === XMLHttpRequest.DONE) {
+ handleLoadedModel(JSON.parse(request2.responseText));
+ }
+ }
+ request2.send();
+ log(" XMLHttpRequest sent for model two")
+ //! [2]
+
+ // Load the third model
+ var request3 = new XMLHttpRequest();
+ request3.open("GET", "bush.json");
+ request3.onreadystatechange = function () {
+ if (request3.readyState === XMLHttpRequest.DONE) {
+ handleLoadedModel(JSON.parse(request3.responseText));
+ }
+ }
+ request3.send();
+ log(" XMLHttpRequest sent for model three")
+
+ // Load the fourth model
+ var request4 = new XMLHttpRequest();
+ request4.open("GET", "pallet.json");
+ request4.onreadystatechange = function () {
+ if (request4.readyState === XMLHttpRequest.DONE) {
+ handleLoadedModel(JSON.parse(request4.responseText));
+ }
+ }
+ request4.send();
+ log(" XMLHttpRequest sent for model four")
+
+ // Load the fifth model
+ var request5 = new XMLHttpRequest();
+ request5.open("GET", "rock.json");
+ request5.onreadystatechange = function () {
+ if (request5.readyState === XMLHttpRequest.DONE) {
+ handleLoadedModel(JSON.parse(request5.responseText));
+ }
+ }
+ request5.send();
+ log(" XMLHttpRequest sent for model five")
+}
+
+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;
+}
diff --git a/examples/canvas3d/jsonmodels/jsonmodels.pro b/examples/canvas3d/jsonmodels/jsonmodels.pro
new file mode 100644
index 0000000..df8e925
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/jsonmodels.pro
@@ -0,0 +1,16 @@
+TEMPLATE = app
+
+QT += qml quick
+
+SOURCES += main.cpp
+
+RESOURCES += qml.qrc
+
+OTHER_FILES += doc/src/* \
+ doc/images/*
+
+# Additional import path used to resolve QML modules in Qt Creator's code model
+QML_IMPORT_PATH =
+
+# Default rules for deployment.
+include(deployment.pri)
diff --git a/examples/canvas3d/jsonmodels/jsonmodels.qml b/examples/canvas3d/jsonmodels/jsonmodels.qml
new file mode 100644
index 0000000..ec0d15e
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/jsonmodels.qml
@@ -0,0 +1,335 @@
+import QtQuick 2.2
+import QtQuick.Window 2.1
+import QtCanvas3D 1.0
+import QtQuick.Enterprise.Controls 1.1
+import QtQuick.Enterprise.Controls.Styles 1.1
+import QtQuick.Layouts 1.1
+
+import "jsonmodels.js" as GLCode
+
+Window {
+ visible: true
+ width: 1200
+ height: 900
+
+ //! [3]
+ property int previousY: 0
+ property int previousX: 0
+ //! [3]
+
+ ColumnLayout {
+ anchors.fill: parent
+ RowLayout {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ Canvas3D {
+ id: canvas3d
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ imageLoader: textureImageLoader
+ //! [1]
+ property double xRot: 0.0
+ property double yRot: 45.0
+ property double distance: 2.0
+ //! [1]
+ property double itemSize: 1.0
+ property double lightX: 0.0
+ property double lightY: 45.0
+ property double lightDistance: 2.0
+ property bool animatingLight: false
+ property bool animatingCamera: false
+ property bool drawWireframe: false
+
+ function initGL() {
+ GLCode.initGL(canvas3d, textureImageLoader);
+ }
+
+ function renderGL() {
+ GLCode.renderGL(canvas3d);
+ }
+
+ //! [0]
+ MouseArea {
+ anchors.fill: parent
+ //! [0]
+ //! [2]
+ onMouseXChanged: {
+ // Do not rotate if we don't have previous value
+ if (previousY !== 0)
+ canvas3d.yRot += mouseY - previousY
+ previousY = mouseY
+ // Limit the rotation to -90...90 degrees
+ if (canvas3d.yRot > 90)
+ canvas3d.yRot = 90
+ if (canvas3d.yRot < -90)
+ canvas3d.yRot = -90
+ }
+ onMouseYChanged: {
+ // Do not rotate if we don't have previous value
+ if (previousX !== 0)
+ canvas3d.xRot += mouseX - previousX
+ previousX = mouseX
+ // Wrap the rotation around
+ if (canvas3d.xRot > 180)
+ canvas3d.xRot -= 360
+ if (canvas3d.xRot < -180)
+ canvas3d.xRot += 360
+ }
+ onReleased: {
+ // Reset previous mouse positions to avoid rotation jumping
+ previousX = 0
+ previousY = 0
+ }
+ //! [2]
+ //! [4]
+ onWheel: {
+ canvas3d.distance -= wheel.angleDelta.y / 1000.0
+ // Limit the distance to 0.5...10
+ if (canvas3d.distance < 0.5)
+ canvas3d.distance = 0.5
+ if (canvas3d.distance > 10)
+ canvas3d.distance = 10
+ }
+ //! [4]
+ }
+ }
+
+ ColumnLayout {
+ CircularGauge {
+ minimumValue: -180
+ maximumValue: 180
+ value: canvas3d.xRot
+ style: CircularGaugeStyle {
+ labelStepSize: 30
+ tickmarkStepSize: 15
+ background: Canvas {
+ Text {
+ font.pixelSize: 20
+ text: "x angle: " + angle
+ color: "lightgray"
+ horizontalAlignment: Text.AlignHCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.verticalCenter
+ anchors.topMargin: parent.height / 8
+ readonly property int angle: canvas3d.xRot
+ }
+ }
+ }
+ }
+ CircularGauge {
+ minimumValue: -90
+ maximumValue: 90
+ value: canvas3d.yRot
+ style: CircularGaugeStyle {
+ labelStepSize: 30
+ tickmarkStepSize: 15
+ background: Canvas {
+ Text {
+ font.pixelSize: 20
+ text: "y angle: " + angle
+ color: "lightgray"
+ horizontalAlignment: Text.AlignHCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.verticalCenter
+ anchors.topMargin: parent.height / 8
+ readonly property int angle: canvas3d.yRot
+ }
+ }
+ }
+ }
+ CircularGauge {
+ minimumValue: 0
+ maximumValue: 100
+ value: canvas3d.distance * 10
+ style: CircularGaugeStyle {
+ labelStepSize: 20
+ tickmarkStepSize: 10
+ background: Canvas {
+ Text {
+ font.pixelSize: 20
+ text: "distance: " + distance
+ color: "lightgray"
+ horizontalAlignment: Text.AlignHCenter
+ anchors.horizontalCenter: parent.horizontalCenter
+ anchors.top: parent.verticalCenter
+ anchors.topMargin: parent.height / 8
+ readonly property int distance: canvas3d.distance * 10
+ }
+ }
+ }
+ }
+ }
+ }
+ RowLayout {
+ Layout.fillWidth: true
+ ToggleButton {
+ id: lightButton
+ text: "Animate Light"
+ onCheckedChanged: canvas3d.animatingLight = checked
+ }
+ ToggleButton {
+ id: cameraButton
+ text: "Animate Camera"
+ onCheckedChanged: canvas3d.animatingCamera = checked
+ }
+ ToggleButton {
+ id: drawButton
+ text: "Wireframe"
+ onCheckedChanged: canvas3d.drawWireframe = checked
+ }
+ DelayButton {
+ text: "Reset"
+ delay: 1000
+ onCheckedChanged: {
+ canvas3d.xRot = 0.0
+ canvas3d.yRot = 45.0
+ canvas3d.distance = 2.0
+ canvas3d.itemSize = 1.0
+ canvas3d.lightX = 0.0
+ canvas3d.lightY = 45.0
+ canvas3d.lightDistance = 2.0
+ lightButton.checked = false
+ cameraButton.checked = false
+ drawButton.checked = false
+ checked = false
+ }
+ }
+ DelayButton {
+ text: "Quit"
+ delay: 1000
+ onCheckedChanged: Qt.quit()
+ }
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingLight
+ NumberAnimation {
+ target: canvas3d
+ property: "lightX"
+ from: 0.0
+ to: 360.0
+ duration: 5000
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingLight
+ NumberAnimation {
+ target: canvas3d
+ property: "lightY"
+ from: 0.0
+ to: 90.0
+ duration: 10000
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "lightY"
+ from: 90.0
+ to: 0.0
+ duration: 10000
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingLight
+ NumberAnimation {
+ target: canvas3d
+ property: "lightDistance"
+ from: 10.0
+ to: 0.5
+ duration: 30000
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "lightDistance"
+ from: 0.5
+ to: 10.0
+ duration: 30000
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingCamera
+ NumberAnimation {
+ target: canvas3d
+ property: "xRot"
+ from: -180.0
+ to: 180.0
+ duration: 5000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRot"
+ from: 180.0
+ to: -180.0
+ duration: 5000
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingCamera
+ NumberAnimation {
+ target: canvas3d
+ property: "yRot"
+ from: 0.0
+ to: 90.0
+ duration: 10000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRot"
+ from: 90.0
+ to: 0.0
+ duration: 10000
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingCamera
+ NumberAnimation {
+ target: canvas3d
+ property: "distance"
+ from: 10.0
+ to: 0.5
+ duration: 30000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "distance"
+ from: 0.5
+ to: 10.0
+ duration: 30000
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ TextureImageLoader {
+ id: textureImageLoader
+
+ function loadTexture(file) {
+ return textureImageLoader.loadImage("qrc:///"+file);
+ }
+
+ function imageLoaded(textureImage) {
+ GLCode.textureLoaded(textureImage);
+ }
+
+ function imageLoadingError(textureImage) {
+ if (GLCode.textureLoadError !== undefined) {
+ GLCode.textureLoadError(textureImage);
+ }
+ }
+ }
+}
diff --git a/examples/canvas3d/jsonmodels/jsonmodelsbasic.qml b/examples/canvas3d/jsonmodels/jsonmodelsbasic.qml
new file mode 100644
index 0000000..caab7a8
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/jsonmodelsbasic.qml
@@ -0,0 +1,279 @@
+import QtQuick 2.2
+import QtQuick.Window 2.1
+import QtCanvas3D 1.0
+import QtQuick.Controls 1.1
+import QtQuick.Layouts 1.1
+
+import "jsonmodels.js" as GLCode
+
+Window {
+ visible: true
+ width: 1200
+ height: 900
+
+ property int previousY: 0
+ property int previousX: 0
+
+ ColumnLayout {
+ anchors.fill: parent
+ RowLayout {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ Canvas3D {
+ id: canvas3d
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ imageLoader: textureImageLoader
+ property double xRot: 0.0
+ property double yRot: 45.0
+ property double distance: 2.0
+ property double itemSize: 1.0
+ property double lightX: 0.0
+ property double lightY: 45.0
+ property double lightDistance: 2.0
+ property bool animatingLight: false
+ property bool animatingCamera: false
+ property bool drawWireframe: false
+
+ function initGL() {
+ GLCode.initGL(canvas3d, textureImageLoader);
+ }
+
+ function renderGL() {
+ GLCode.renderGL(canvas3d);
+ }
+
+ MouseArea {
+ anchors.fill: parent
+ onMouseXChanged: {
+ if (previousY !== 0)
+ canvas3d.yRot += mouseY - previousY
+ previousY = mouseY
+ if (canvas3d.yRot > 90)
+ canvas3d.yRot = 90
+ if (canvas3d.yRot < -90)
+ canvas3d.yRot = -90
+ }
+ onMouseYChanged: {
+ if (previousX !== 0)
+ canvas3d.xRot += mouseX - previousX
+ previousX = mouseX
+ if (canvas3d.xRot > 180)
+ canvas3d.xRot -= 360
+ if (canvas3d.xRot < -180)
+ canvas3d.xRot += 360
+ }
+ onReleased: {
+ previousX = 0
+ previousY = 0
+ }
+ onWheel: {
+ canvas3d.distance -= wheel.angleDelta.y / 1000.0
+ if (canvas3d.distance < 0.5)
+ canvas3d.distance = 0.5
+ if (canvas3d.distance > 10)
+ canvas3d.distance = 10
+ }
+ }
+ }
+
+ ColumnLayout {
+ Label {
+ width: 150
+ Text {
+ font.pixelSize: 20
+ text: "x angle: " + angle
+ readonly property int angle: canvas3d.xRot
+ }
+ }
+ Label {
+ width: 150
+ Text {
+ font.pixelSize: 20
+ text: "y angle: " + angle
+ readonly property int angle: canvas3d.yRot
+ }
+ }
+ Label {
+ width: 150
+ Text {
+ font.pixelSize: 20
+ text: "distance: " + distance
+ readonly property int distance: canvas3d.distance * 10
+ }
+ }
+ }
+ }
+ RowLayout {
+ Layout.fillWidth: true
+ Button {
+ id: lightButton
+ text: "Animate Light"
+ checkable: true
+ onCheckedChanged: canvas3d.animatingLight = checked
+ }
+ Button {
+ id: cameraButton
+ text: "Animate Camera"
+ checkable: true
+ onCheckedChanged: canvas3d.animatingCamera = checked
+ }
+ Button {
+ id: drawButton
+ text: "Wireframe"
+ checkable: true
+ onCheckedChanged: canvas3d.drawWireframe = checked
+ }
+ Button {
+ text: "Reset"
+ onClicked: {
+ canvas3d.xRot = 0.0
+ canvas3d.yRot = 45.0
+ canvas3d.distance = 2.0
+ canvas3d.itemSize = 1.0
+ canvas3d.lightX = 0.0
+ canvas3d.lightY = 45.0
+ canvas3d.lightDistance = 2.0
+ lightButton.checked = false
+ cameraButton.checked = false
+ drawButton.checked = false
+ }
+ }
+ Button {
+ text: "Quit"
+ onClicked: Qt.quit()
+ }
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingLight
+ NumberAnimation {
+ target: canvas3d
+ property: "lightX"
+ from: 0.0
+ to: 360.0
+ duration: 5000
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingLight
+ NumberAnimation {
+ target: canvas3d
+ property: "lightY"
+ from: 0.0
+ to: 90.0
+ duration: 10000
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "lightY"
+ from: 90.0
+ to: 0.0
+ duration: 10000
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingLight
+ NumberAnimation {
+ target: canvas3d
+ property: "lightDistance"
+ from: 10.0
+ to: 0.5
+ duration: 30000
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "lightDistance"
+ from: 0.5
+ to: 10.0
+ duration: 30000
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingCamera
+ NumberAnimation {
+ target: canvas3d
+ property: "xRot"
+ from: -180.0
+ to: 180.0
+ duration: 5000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRot"
+ from: 180.0
+ to: -180.0
+ duration: 5000
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingCamera
+ NumberAnimation {
+ target: canvas3d
+ property: "yRot"
+ from: 0.0
+ to: 90.0
+ duration: 10000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRot"
+ from: 90.0
+ to: 0.0
+ duration: 10000
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ SequentialAnimation {
+ loops: Animation.Infinite
+ running: canvas3d.animatingCamera
+ NumberAnimation {
+ target: canvas3d
+ property: "distance"
+ from: 10.0
+ to: 0.5
+ duration: 30000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "distance"
+ from: 0.5
+ to: 10.0
+ duration: 30000
+ easing.type: Easing.InOutSine
+ }
+ }
+
+ TextureImageLoader {
+ id: textureImageLoader
+
+ function loadTexture(file) {
+ return textureImageLoader.loadImage("qrc:///"+file);
+ }
+
+ function imageLoaded(textureImage) {
+ GLCode.textureLoaded(textureImage);
+ }
+
+ function imageLoadingError(textureImage) {
+ if (GLCode.textureLoadError !== undefined) {
+ GLCode.textureLoadError(textureImage);
+ }
+ }
+ }
+}
diff --git a/examples/canvas3d/jsonmodels/main.cpp b/examples/canvas3d/jsonmodels/main.cpp
new file mode 100644
index 0000000..e93862e
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/main.cpp
@@ -0,0 +1,18 @@
+//#define NO_ENTERPRISE
+
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+#ifdef NO_ENTERPRISE
+ engine.load(QUrl(QStringLiteral("qrc:///jsonmodelsbasic.qml")));
+#else
+ engine.load(QUrl(QStringLiteral("qrc:///jsonmodels.qml")));
+#endif
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/jsonmodels/pallet.jpg b/examples/canvas3d/jsonmodels/pallet.jpg
new file mode 100644
index 0000000..ea0c01a
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/pallet.jpg
Binary files differ
diff --git a/examples/canvas3d/jsonmodels/pallet.json b/examples/canvas3d/jsonmodels/pallet.json
new file mode 100644
index 0000000..8bd7fef
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/pallet.json
@@ -0,0 +1,47 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "generatedBy" : "Blender 2.7 Exporter",
+ "vertices" : 360,
+ "faces" : 220,
+ "normals" : 12,
+ "colors" : 0,
+ "uvs" : [530],
+ "materials" : 1,
+ "morphTargets" : 0,
+ "bones" : 0
+ },
+
+ "scale" : 100.000000,
+
+ "materials" : [ {
+ "DbgColor" : 15658734,
+ "DbgIndex" : 0,
+ "DbgName" : "default",
+ "vertexColors" : false
+ }],
+
+ "vertices" : [-5.7509,-0.024009,75.1078,-5.7509,-0.0239911,-74.8922,5.7509,-0.0239911,-74.8922,5.7509,-0.024009,75.1078,-5.7509,1.97599,75.1078,5.7509,1.97599,75.1078,5.7509,1.97601,-74.8922,-5.7509,1.97601,-74.8922,-74.5272,12.1,74.8922,-74.5272,12.1,-75.1078,-64.2475,12.1,-75.1078,-64.2475,12.1,74.8922,-74.5272,14.1,74.8922,-64.2475,14.1,74.8922,-64.2475,14.1,-75.1078,-74.5272,14.1,-75.1078,-59.1077,12.1,74.8922,-59.1077,12.1,-75.1078,-48.8281,12.1,-75.1078,-48.8281,12.1,74.8922,-59.1077,14.1,74.8922,-48.8281,14.1,74.8922,-48.8281,14.1,-75.1078,-59.1077,14.1,-75.1078,-43.6883,12.1,74.8922,-43.6883,12.1,-75.1078,-33.4087,12.1,-75.1078,-33.4087,12.1,74.8922,-43.6883,14.1,74.8922,-33.4087,14.1,74.8922,-33.4087,14.1,-75.1078,-43.6883,14.1,-75.1078,-28.2689,12.1,74.8922,-28.2689,12.1,-75.1078,-17.9893,12.1,-75.1078,-17.9893,12.1,74.8922,-28.2689,14.1,74.8922,-17.9893,14.1,74.8922,-17.9893,14.1,-75.1078,-28.2689,14.1,-75.1078,-12.8495,12.1,74.8922,-12.8495,12.1,-75.1078,-2.5699,12.1,-75.1078,-2.5699,12.1,74.8922,-12.8495,14.1,74.8922,-2.5699,14.1,74.8922,-2.5699,14.1,-75.1078,-12.8495,14.1,-75.1078,2.5699,12.1,74.8922,2.5699,12.1,-75.1078,12.8495,12.1,-75.1078,12.8495,12.1,74.8922,2.5699,14.1,74.8922,12.8495,14.1,74.8922,12.8495,14.1,-75.1078,2.5699,14.1,-75.1078,17.9893,12.1,74.8922,17.9893,12.1,-75.1078,28.2689,12.1,-75.1078,28.2689,12.1,74.8922,17.9893,14.1,74.8922,28.2689,14.1,74.8922,28.2689,14.1,-75.1078,17.9893,14.1,-75.1078,33.4087,12.1,74.8922,33.4087,12.1,-75.1078,43.6883,12.1,-75.1078,43.6883,12.1,74.8922,33.4087,14.1,74.8922,43.6883,14.1,74.8922,43.6883,14.1,-75.1078,33.4087,14.1,-75.1078,48.8281,12.1,74.8922,48.8281,12.1,-75.1078,59.1077,12.1,-75.1078,59.1077,12.1,74.8922,48.8281,14.1,74.8922,59.1077,14.1,74.8922,59.1077,14.1,-75.1078,48.8281,14.1,-75.1078,64.2475,12.1,74.8922,64.2475,12.1,-75.1078,74.5271,12.1,-75.1078,74.5271,12.1,74.8922,64.2475,14.1,74.8922,74.5271,14.1,74.8922,74.5271,14.1,-75.1078,64.2475,14.1,-75.1078,75,10.1123,68.4901,-75,10.1123,68.4901,-75,10.1123,58.1158,75,10.1123,58.1158,75,12.1123,68.4901,75,12.1123,58.1158,-75,12.1123,58.1158,-75,12.1123,68.4901,75,10.1123,37.3673,-75,10.1123,37.3673,-75,10.1123,26.993,75,10.1123,26.993,75,12.1123,37.3673,75,12.1123,26.993,-75,12.1123,26.993,-75,12.1123,37.3673,75,10.1123,6.2445,-75,10.1123,6.2445,-75,10.1123,-4.1297,75,10.1123,-4.1298,75,12.1123,6.2445,75,12.1123,-4.1298,-75,12.1123,-4.1297,-75,12.1123,6.2445,75,10.1123,-24.8783,-75,10.1123,-24.8783,-75,10.1123,-35.2525,75,10.1123,-35.2525,75,12.1123,-24.8783,75,12.1123,-35.2525,-75,12.1123,-35.2525,-75,12.1123,-24.8783,75,10.1123,-56.0011,-75,10.1123,-56.0011,-75,10.1123,-66.3753,75,10.1123,-66.3753,75,12.1123,-56.0011,75,12.1123,-66.3753,-75,12.1123,-66.3753,-75,12.1123,-56.0011,-40.2565,-0.024009,75.1078,-40.2565,-0.0239911,-74.8922,-28.7547,-0.0239911,-74.8922,-28.7547,-0.024009,75.1078,-40.2565,1.97599,75.1078,-28.7547,1.97599,75.1078,-28.7547,1.97601,-74.8922,-40.2565,1.97601,-74.8922,28.7546,-0.024009,75.1078,28.7546,-0.0239911,-74.8922,40.2565,-0.0239911,-74.8922,40.2565,-0.024009,75.1078,28.7546,1.97599,75.1078,40.2565,1.97599,75.1078,40.2565,1.97601,-74.8922,28.7546,1.97601,-74.8922,63.2602,-0.024009,75.1078,63.2602,-0.0239911,-74.8922,74.762,-0.0239911,-74.8922,74.762,-0.024009,75.1078,63.2602,1.97599,75.1078,74.762,1.97599,75.1078,74.762,1.97601,-74.8922,63.2602,1.97601,-74.8922,-74.7621,-0.024009,75.1078,-74.7621,-0.0239911,-74.8922,-63.2602,-0.0239911,-74.8922,-63.2602,-0.024009,75.1078,-74.7621,1.97599,75.1078,-63.2602,1.97599,75.1078,-63.2602,1.97601,-74.8922,-74.7621,1.97601,-74.8922,73.6621,10.3676,-56.1854,64.2601,10.3676,-56.1854,64.2601,1.70111,-56.1854,73.6621,1.70111,-56.1854,73.6621,10.3676,-66.1572,73.6621,1.70111,-66.1572,64.2601,10.3676,-66.1572,64.2601,1.70111,-66.1572,73.6621,10.3676,-25.0654,64.2601,10.3676,-25.0654,64.2601,1.7011,-25.0654,73.6621,1.7011,-25.0654,73.6621,10.3676,-35.0372,73.6621,1.7011,-35.0372,64.2601,10.3676,-35.0372,64.2601,1.7011,-35.0372,73.6621,10.3676,6.0546,64.2601,10.3676,6.0546,64.2601,1.7011,6.0546,73.6621,1.7011,6.0546,73.6621,10.3676,-3.9172,73.6621,1.7011,-3.9172,64.2601,10.3676,-3.9172,64.2601,1.7011,-3.9172,73.6621,10.3676,37.1746,64.2601,10.3676,37.1746,64.2601,1.7011,37.1746,73.6621,1.7011,37.1746,73.6621,10.3676,27.2028,73.6621,1.7011,27.2028,64.2601,10.3676,27.2028,64.2601,1.7011,27.2028,73.6621,10.3676,68.2946,64.2601,10.3676,68.2946,64.2601,1.70109,68.2946,73.6621,1.70109,68.2946,73.6621,10.3676,58.3228,73.6621,1.70109,58.3228,64.2601,10.3676,58.3228,64.2601,1.70109,58.3228,39.1621,10.3676,68.2946,29.7601,10.3676,68.2946,29.7601,1.70109,68.2946,39.1621,1.70109,68.2946,39.1621,10.3676,58.3228,39.1621,1.70109,58.3228,29.7601,10.3676,58.3228,29.7601,1.70109,58.3228,39.1621,10.3676,37.1746,29.7601,10.3676,37.1746,29.7601,1.7011,37.1746,39.1621,1.7011,37.1746,39.1621,10.3676,27.2028,39.1621,1.7011,27.2028,29.7601,10.3676,27.2028,29.7601,1.7011,27.2028,39.1621,10.3676,6.0546,29.7601,10.3676,6.0546,29.7601,1.7011,6.0546,39.1621,1.7011,6.0546,39.1621,10.3676,-3.9172,39.1621,1.7011,-3.9172,29.7601,10.3676,-3.9172,29.7601,1.7011,-3.9172,39.1621,10.3676,-25.0654,29.7601,10.3676,-25.0654,29.7601,1.7011,-25.0654,39.1621,1.7011,-25.0654,39.1621,10.3676,-35.0372,39.1621,1.7011,-35.0372,29.7601,10.3676,-35.0372,29.7601,1.7011,-35.0372,39.1621,10.3676,-56.1854,29.7601,10.3676,-56.1854,29.7601,1.70111,-56.1854,39.1621,1.70111,-56.1854,39.1621,10.3676,-66.1572,39.1621,1.70111,-66.1572,29.7601,10.3676,-66.1572,29.7601,1.70111,-66.1572,4.6621,10.3676,68.2946,-4.7399,10.3676,68.2946,-4.7399,1.70109,68.2946,4.6621,1.70109,68.2946,4.6621,10.3676,58.3228,4.6621,1.70109,58.3228,-4.7399,10.3676,58.3228,-4.7399,1.70109,58.3228,4.6621,10.3676,37.1746,-4.7399,10.3676,37.1746,-4.7399,1.7011,37.1746,4.6621,1.7011,37.1746,4.6621,10.3676,27.2028,4.6621,1.7011,27.2028,-4.7399,10.3676,27.2028,-4.7399,1.7011,27.2028,4.6621,10.3676,6.0546,-4.7399,10.3676,6.0546,-4.7399,1.7011,6.0546,4.6621,1.7011,6.0546,4.6621,10.3676,-3.9172,4.6621,1.7011,-3.9172,-4.7399,10.3676,-3.9172,-4.7399,1.7011,-3.9172,4.6621,10.3676,-25.0654,-4.7399,10.3676,-25.0654,-4.7399,1.7011,-25.0654,4.6621,1.7011,-25.0654,4.6621,10.3676,-35.0372,4.6621,1.7011,-35.0372,-4.7399,10.3676,-35.0372,-4.7399,1.7011,-35.0372,4.6621,10.3676,-56.1854,-4.7399,10.3676,-56.1854,-4.7399,1.70111,-56.1854,4.6621,1.70111,-56.1854,4.6621,10.3676,-66.1572,4.6621,1.70111,-66.1572,-4.7399,10.3676,-66.1572,-4.7399,1.70111,-66.1572,-29.8379,10.3676,68.2946,-39.2399,10.3676,68.2946,-39.2399,1.70109,68.2946,-29.8379,1.70109,68.2946,-29.8379,10.3676,58.3228,-29.8379,1.70109,58.3228,-39.2399,10.3676,58.3228,-39.2399,1.70109,58.3228,-29.8379,10.3676,37.1746,-39.2399,10.3676,37.1746,-39.2399,1.7011,37.1746,-29.8379,1.7011,37.1746,-29.8379,10.3676,27.2028,-29.8379,1.7011,27.2028,-39.2399,10.3676,27.2028,-39.2399,1.7011,27.2028,-29.8379,10.3676,6.0546,-39.2399,10.3676,6.0546,-39.2399,1.7011,6.0546,-29.8379,1.7011,6.0546,-29.8379,10.3676,-3.9172,-29.8379,1.7011,-3.9172,-39.2399,10.3676,-3.9172,-39.2399,1.7011,-3.9172,-29.8379,10.3676,-25.0654,-39.2399,10.3676,-25.0654,-39.2399,1.7011,-25.0654,-29.8379,1.7011,-25.0654,-29.8379,10.3676,-35.0372,-29.8379,1.7011,-35.0372,-39.2399,10.3676,-35.0372,-39.2399,1.7011,-35.0372,-29.8379,10.3676,-56.1854,-39.2399,10.3676,-56.1854,-39.2399,1.70111,-56.1854,-29.8379,1.70111,-56.1854,-29.8379,10.3676,-66.1572,-29.8379,1.70111,-66.1572,-39.2399,10.3676,-66.1572,-39.2399,1.70111,-66.1572,-64.3379,10.3676,68.2946,-73.7399,10.3676,68.2946,-73.7399,1.70109,68.2946,-64.3379,1.70109,68.2946,-64.3379,10.3676,58.3228,-64.3379,1.70109,58.3228,-73.7399,10.3676,58.3228,-73.7399,1.70109,58.3228,-64.3379,10.3676,37.1746,-73.7399,10.3676,37.1746,-73.7399,1.7011,37.1746,-64.3379,1.7011,37.1746,-64.3379,10.3676,27.2028,-64.3379,1.7011,27.2028,-73.7399,10.3676,27.2028,-73.7399,1.7011,27.2028,-64.3379,10.3676,6.0546,-73.7399,10.3676,6.0546,-73.7399,1.7011,6.0546,-64.3379,1.7011,6.0546,-64.3379,10.3676,-3.9172,-64.3379,1.7011,-3.9172,-73.7399,10.3676,-3.9172,-73.7399,1.7011,-3.9172,-64.3379,10.3676,-25.0654,-73.7399,10.3676,-25.0654,-73.7399,1.7011,-25.0654,-64.3379,1.7011,-25.0654,-64.3379,10.3676,-35.0372,-64.3379,1.7011,-35.0372,-73.7399,10.3676,-35.0372,-73.7399,1.7011,-35.0372,-64.3379,10.3676,-56.1854,-73.7399,10.3676,-56.1854,-73.7399,1.70111,-56.1854,-64.3379,1.70111,-56.1854,-64.3379,10.3676,-66.1572,-64.3379,1.70111,-66.1572,-73.7399,10.3676,-66.1572,-73.7399,1.70111,-66.1572],
+
+ "morphTargets" : [],
+
+ "normals" : [-0.577349,-0.577349,0.577349,-0.577349,-0.577349,-0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,0.577349,-0.577349,0.577349,0.577349,0.577349,0.577349,0.577349,0.577349,0.577349,-0.577349,-0.577349,0.577349,-0.577349,0.707083,0,0.707083,-0.707083,0,0.707083,0.707083,0,-0.707083,-0.707083,0,-0.707083],
+
+ "colors" : [],
+
+ "uvs" : [[0.0243,0.6047,0.4936,0.6047,0.4936,0.6407,0.0243,0.6407,0.0243,0.5984,0.0243,0.5625,0.4936,0.5625,0.4936,0.5984,0.018,0.5984,0.018,0.5625,0.0243,0.5562,0.4936,0.5562,0.4999,0.5625,0.4999,0.5984,0.5166,0.2164,0.9859,0.2164,0.9859,0.2486,0.5166,0.2486,0.5166,0.2102,0.5166,0.178,0.9859,0.178,0.9859,0.2102,0.5103,0.2102,0.5103,0.178,0.5166,0.1717,0.9859,0.1717,0.9922,0.178,0.9922,0.2102,0.5166,0.5542,0.9859,0.5542,0.9859,0.5864,0.5166,0.5864,0.5166,0.548,0.5166,0.5158,0.9859,0.5158,0.9859,0.548,0.5103,0.548,0.5103,0.5158,0.5166,0.5096,0.9859,0.5096,0.9922,0.5158,0.9922,0.548,0.5166,0.3881,0.9859,0.3881,0.9859,0.4202,0.5166,0.4202,0.5166,0.3818,0.5166,0.3496,0.9859,0.3496,0.9859,0.3818,0.5103,0.3818,0.5103,0.3496,0.5166,0.3434,0.9859,0.3434,0.9922,0.3496,0.9922,0.3818,0.5166,0.6346,0.9859,0.6346,0.9859,0.6668,0.5166,0.6668,0.5166,0.6284,0.5166,0.5962,0.9859,0.5962,0.9859,0.6284,0.5103,0.6284,0.5103,0.5962,0.5166,0.5899,0.9859,0.5899,0.9922,0.5962,0.9922,0.6284,0.5166,0.8745,0.9859,0.8745,0.9859,0.9067,0.5166,0.9067,0.5166,0.8683,0.5166,0.8361,0.9859,0.8361,0.9859,0.8683,0.5103,0.8683,0.5103,0.8361,0.5166,0.8298,0.9859,0.8298,0.9922,0.8361,0.9922,0.8683,0.5166,0.7137,0.9859,0.7137,0.9859,0.7459,0.5166,0.7459,0.5166,0.7075,0.5166,0.6753,0.9859,0.6753,0.9859,0.7075,0.5103,0.7075,0.5103,0.6753,0.5166,0.669,0.9859,0.669,0.9922,0.6753,0.9922,0.7075,0.5166,0.7945,0.9859,0.7945,0.9859,0.8267,0.5166,0.8267,0.5166,0.7882,0.5166,0.7561,0.9859,0.7561,0.9859,0.7882,0.5103,0.7882,0.5103,0.7561,0.5166,0.7498,0.9859,0.7498,0.9922,0.7561,0.9922,0.7882,0.5166,0.3014,0.9859,0.3014,0.9859,0.3336,0.5166,0.3336,0.5166,0.2951,0.5166,0.263,0.9859,0.263,0.9859,0.2951,0.5103,0.2951,0.5103,0.263,0.5166,0.2567,0.9859,0.2567,0.9922,0.263,0.9922,0.2951,0.5166,0.4738,0.9859,0.4738,0.9859,0.506,0.5166,0.506,0.5166,0.4675,0.5166,0.4354,0.9859,0.4354,0.9859,0.4675,0.5103,0.4675,0.5103,0.4354,0.5166,0.4291,0.9859,0.4291,0.9922,0.4354,0.9922,0.4675,0.5166,0.9553,0.9859,0.9553,0.9859,0.9875,0.5166,0.9875,0.5166,0.9491,0.5166,0.9169,0.9859,0.9169,0.9859,0.9491,0.5103,0.9491,0.5103,0.9169,0.5166,0.9106,0.9859,0.9106,0.9922,0.9169,0.9922,0.9491,0.0258,0.5073,0.4951,0.5073,0.4951,0.5398,0.0258,0.5398,0.0258,0.5011,0.0258,0.4686,0.4951,0.4686,0.4951,0.5011,0.0196,0.5011,0.0196,0.4686,0.0258,0.4624,0.4951,0.4624,0.5014,0.4686,0.5014,0.5011,0.0258,0.2527,0.4951,0.2527,0.4951,0.2852,0.0258,0.2852,0.0258,0.2464,0.0258,0.214,0.4951,0.214,0.4951,0.2464,0.0196,0.2464,0.0196,0.214,0.0258,0.2077,0.4951,0.2077,0.5014,0.214,0.5014,0.2464,0.0258,0.169,0.4951,0.169,0.4951,0.2015,0.0258,0.2015,0.0258,0.1628,0.0258,0.1303,0.4951,0.1303,0.4951,0.1628,0.0196,0.1628,0.0196,0.1303,0.0258,0.124,0.4951,0.124,0.5014,0.1303,0.5014,0.1628,0.0258,0.3376,0.4951,0.3376,0.4951,0.37,0.0258,0.37,0.0258,0.3313,0.0258,0.2989,0.4951,0.2989,0.4951,0.3313,0.0196,0.3313,0.0196,0.2989,0.0258,0.2926,0.4951,0.2926,0.5014,0.2989,0.5014,0.3313,0.0258,0.4225,0.4951,0.4225,0.4951,0.4549,0.0258,0.4549,0.0258,0.4162,0.0258,0.3838,0.4951,0.3838,0.4951,0.4162,0.0196,0.4162,0.0196,0.3838,0.0258,0.3775,0.4951,0.3775,0.5014,0.3838,0.5014,0.4162,0.0243,0.6918,0.4936,0.6918,0.4936,0.7278,0.0243,0.7278,0.0243,0.6856,0.0243,0.6496,0.4936,0.6496,0.4936,0.6856,0.018,0.6856,0.018,0.6496,0.0243,0.6433,0.4936,0.6433,0.4999,0.6496,0.4999,0.6856,0.0243,0.9495,0.4936,0.9495,0.4936,0.9855,0.0243,0.9855,0.0243,0.9432,0.0243,0.9072,0.4936,0.9072,0.4936,0.9432,0.018,0.9432,0.018,0.9072,0.0243,0.901,0.4936,0.901,0.4999,0.9072,0.4999,0.9432,0.0243,0.7773,0.4936,0.7773,0.4936,0.8133,0.0243,0.8133,0.0243,0.771,0.0243,0.735,0.4936,0.735,0.4936,0.771,0.018,0.771,0.018,0.735,0.0243,0.7288,0.4936,0.7288,0.4999,0.735,0.4999,0.771,0.0243,0.8627,0.4936,0.8627,0.4936,0.8987,0.0243,0.8987,0.0243,0.8565,0.0243,0.8205,0.4936,0.8205,0.4936,0.8565,0.018,0.8565,0.018,0.8205,0.0243,0.8142,0.4936,0.8142,0.4999,0.8205,0.4999,0.8565,0.2683,0.0099,0.2977,0.0099,0.2977,0.037,0.2683,0.037,0.2371,0.0099,0.2371,0.037,0.3289,0.0099,0.3584,0.0099,0.3584,0.037,0.3289,0.037,0.6446,0.0422,0.674,0.0422,0.674,0.0694,0.6446,0.0694,0.6134,0.0422,0.6134,0.0694,0.7052,0.0422,0.7346,0.0422,0.7346,0.0694,0.7052,0.0694,0.3964,0.0713,0.4258,0.0713,0.4258,0.0984,0.3964,0.0984,0.3652,0.0713,0.3652,0.0984,0.457,0.0713,0.4864,0.0713,0.4864,0.0984,0.457,0.0984,0.7689,0.013,0.7983,0.013,0.7983,0.0401,0.7689,0.0401,0.7377,0.013,0.7377,0.0401,0.8295,0.013,0.8589,0.013,0.8589,0.0401,0.8295,0.0401,0.3958,0.0133,0.4252,0.0133,0.4252,0.0404,0.3958,0.0404,0.3646,0.0133,0.3646,0.0404,0.4564,0.0133,0.4858,0.0133,0.4858,0.0404,0.4564,0.0404,0.5201,0.0147,0.5495,0.0147,0.5495,0.0418,0.5201,0.0418,0.4889,0.0147,0.4889,0.0418,0.5807,0.0147,0.6101,0.0147,0.6101,0.0418,0.5807,0.0418,0.8971,0.1344,0.9265,0.1344,0.9265,0.1615,0.8971,0.1615,0.8659,0.1344,0.8659,0.1615,0.9577,0.1344,0.9871,0.1344,0.9871,0.1615,0.9577,0.1615,0.897,0.1038,0.9265,0.1038,0.9265,0.1309,0.897,0.1309,0.8658,0.1038,0.8658,0.1309,0.9577,0.1038,0.9871,0.1038,0.9871,0.1309,0.9577,0.1309,0.5209,0.0431,0.5503,0.0431,0.5503,0.0702,0.5209,0.0702,0.4897,0.0431,0.4897,0.0702,0.5815,0.0431,0.6109,0.0431,0.6109,0.0702,0.5815,0.0702,0.8973,0.0724,0.9267,0.0724,0.9267,0.0996,0.8973,0.0996,0.8661,0.0724,0.8661,0.0996,0.9579,0.0724,0.9873,0.0724,0.9873,0.0996,0.9579,0.0996,0.7692,0.0415,0.7987,0.0415,0.7987,0.0686,0.7692,0.0686,0.7381,0.0415,0.7381,0.0686,0.8299,0.0415,0.8593,0.0415,0.8593,0.0686,0.8299,0.0686,0.5214,0.0716,0.5508,0.0716,0.5508,0.0987,0.5214,0.0987,0.4902,0.0716,0.4902,0.0987,0.582,0.0716,0.6114,0.0716,0.6114,0.0987,0.582,0.0987,0.7697,0.0702,0.7991,0.0702,0.7991,0.0973,0.7697,0.0973,0.7385,0.0702,0.7385,0.0973,0.8303,0.0702,0.8597,0.0702,0.8597,0.0973,0.8303,0.0973,0.1401,0.0106,0.1695,0.0106,0.1695,0.0377,0.1401,0.0377,0.1089,0.0106,0.1089,0.0377,0.2007,0.0106,0.2301,0.0106,0.2301,0.0377,0.2007,0.0377,0.7699,0.0991,0.7993,0.0991,0.7993,0.1262,0.7699,0.1262,0.7387,0.0991,0.7387,0.1262,0.8305,0.0991,0.8599,0.0991,0.8599,0.1262,0.8305,0.1262,0.7701,0.1285,0.7995,0.1285,0.7995,0.1556,0.7701,0.1556,0.7389,0.1285,0.7389,0.1556,0.8307,0.1285,0.8601,0.1285,0.8601,0.1556,0.8307,0.1556,0.2674,0.0708,0.2968,0.0708,0.2968,0.0979,0.2674,0.0979,0.2362,0.0708,0.2362,0.0979,0.328,0.0708,0.3574,0.0708,0.3574,0.0979,0.328,0.0979,0.6461,0.13,0.6755,0.13,0.6755,0.1571,0.6461,0.1571,0.6149,0.13,0.6149,0.1571,0.7067,0.13,0.7361,0.13,0.7361,0.1571,0.7067,0.1571,0.2679,0.0405,0.2973,0.0405,0.2973,0.0676,0.2679,0.0676,0.2367,0.0405,0.2367,0.0676,0.3285,0.0405,0.358,0.0405,0.358,0.0676,0.3285,0.0676,0.6452,0.0709,0.6747,0.0709,0.6747,0.098,0.6452,0.098,0.614,0.0709,0.614,0.098,0.7058,0.0709,0.7353,0.0709,0.7353,0.098,0.7058,0.098,0.646,0.1001,0.6755,0.1001,0.6755,0.1273,0.646,0.1273,0.6148,0.1001,0.6148,0.1273,0.7066,0.1001,0.7361,0.1001,0.7361,0.1273,0.7066,0.1273,0.6442,0.0133,0.6736,0.0133,0.6736,0.0404,0.6442,0.0404,0.613,0.0133,0.613,0.0404,0.7048,0.0133,0.7342,0.0133,0.7342,0.0404,0.7048,0.0404,0.8987,0.012,0.9281,0.012,0.9281,0.0391,0.8987,0.0391,0.8675,0.012,0.8675,0.0391,0.9593,0.012,0.9887,0.012,0.9887,0.0391,0.9593,0.0391,0.899,0.0407,0.9285,0.0407,0.9285,0.0678,0.899,0.0678,0.8678,0.0407,0.8678,0.0678,0.9597,0.0407,0.9891,0.0407,0.9891,0.0678,0.9597,0.0678,0.3964,0.0424,0.4258,0.0424,0.4258,0.0695,0.3964,0.0695,0.3652,0.0424,0.3652,0.0695,0.457,0.0424,0.4864,0.0424,0.4864,0.0695,0.457,0.0695]],
+
+ "faces" : [43,0,1,2,3,0,0,1,2,3,0,1,2,3,43,4,5,6,7,0,4,5,6,7,4,5,6,7,43,0,3,5,4,0,8,9,5,4,0,3,5,4,43,3,2,6,5,0,10,11,6,5,3,2,6,5,43,2,1,7,6,0,12,13,7,6,2,1,7,6,43,1,0,4,7,0,1,0,4,7,1,0,4,7,43,8,9,10,11,0,14,15,16,17,0,1,2,3,43,12,13,14,15,0,18,19,20,21,4,5,6,7,43,8,11,13,12,0,22,23,19,18,0,3,5,4,43,11,10,14,13,0,24,25,20,19,3,2,6,5,43,10,9,15,14,0,26,27,21,20,2,1,7,6,43,9,8,12,15,0,15,14,18,21,1,0,4,7,43,16,17,18,19,0,28,29,30,31,0,1,2,3,43,20,21,22,23,0,32,33,34,35,4,5,6,7,43,16,19,21,20,0,36,37,33,32,0,3,5,4,43,19,18,22,21,0,38,39,34,33,3,2,6,5,43,18,17,23,22,0,40,41,35,34,2,1,7,6,43,17,16,20,23,0,29,28,32,35,1,0,4,7,43,24,25,26,27,0,42,43,44,45,0,1,2,3,43,28,29,30,31,0,46,47,48,49,4,5,6,7,43,24,27,29,28,0,50,51,47,46,0,3,5,4,43,27,26,30,29,0,52,53,48,47,3,2,6,5,43,26,25,31,30,0,54,55,49,48,2,1,7,6,43,25,24,28,31,0,43,42,46,49,1,0,4,7,43,32,33,34,35,0,56,57,58,59,0,1,2,3,43,36,37,38,39,0,60,61,62,63,4,5,6,7,43,32,35,37,36,0,64,65,61,60,0,3,5,4,43,35,34,38,37,0,66,67,62,61,3,2,6,5,43,34,33,39,38,0,68,69,63,62,2,1,7,6,43,33,32,36,39,0,57,56,60,63,1,0,4,7,43,40,41,42,43,0,70,71,72,73,0,1,2,3,43,44,45,46,47,0,74,75,76,77,4,5,6,7,43,40,43,45,44,0,78,79,75,74,0,3,5,4,43,43,42,46,45,0,80,81,76,75,3,2,6,5,43,42,41,47,46,0,82,83,77,76,2,1,7,6,43,41,40,44,47,0,71,70,74,77,1,0,4,7,43,48,49,50,51,0,84,85,86,87,0,1,2,3,43,52,53,54,55,0,88,89,90,91,4,5,6,7,43,48,51,53,52,0,92,93,89,88,0,3,5,4,43,51,50,54,53,0,94,95,90,89,3,2,6,5,43,50,49,55,54,0,96,97,91,90,2,1,7,6,43,49,48,52,55,0,85,84,88,91,1,0,4,7,43,56,57,58,59,0,98,99,100,101,0,1,2,3,43,60,61,62,63,0,102,103,104,105,4,5,6,7,43,56,59,61,60,0,106,107,103,102,0,3,5,4,43,59,58,62,61,0,108,109,104,103,3,2,6,5,43,58,57,63,62,0,110,111,105,104,2,1,7,6,43,57,56,60,63,0,99,98,102,105,1,0,4,7,43,64,65,66,67,0,112,113,114,115,0,1,2,3,43,68,69,70,71,0,116,117,118,119,4,5,6,7,43,64,67,69,68,0,120,121,117,116,0,3,5,4,43,67,66,70,69,0,122,123,118,117,3,2,6,5,43,66,65,71,70,0,124,125,119,118,2,1,7,6,43,65,64,68,71,0,113,112,116,119,1,0,4,7,43,72,73,74,75,0,126,127,128,129,0,1,2,3,43,76,77,78,79,0,130,131,132,133,4,5,6,7,43,72,75,77,76,0,134,135,131,130,0,3,5,4,43,75,74,78,77,0,136,137,132,131,3,2,6,5,43,74,73,79,78,0,138,139,133,132,2,1,7,6,43,73,72,76,79,0,127,126,130,133,1,0,4,7,43,80,81,82,83,0,140,141,142,143,0,1,2,3,43,84,85,86,87,0,144,145,146,147,4,5,6,7,43,80,83,85,84,0,148,149,145,144,0,3,5,4,43,83,82,86,85,0,150,151,146,145,3,2,6,5,43,82,81,87,86,0,152,153,147,146,2,1,7,6,43,81,80,84,87,0,141,140,144,147,1,0,4,7,43,88,89,90,91,0,154,155,156,157,3,0,1,2,43,92,93,94,95,0,158,159,160,161,5,6,7,4,43,88,91,93,92,0,162,163,159,158,3,2,6,5,43,91,90,94,93,0,164,165,160,159,2,1,7,6,43,90,89,95,94,0,166,167,161,160,1,0,4,7,43,89,88,92,95,0,155,154,158,161,0,3,5,4,43,96,97,98,99,0,168,169,170,171,3,0,1,2,43,100,101,102,103,0,172,173,174,175,5,6,7,4,43,96,99,101,100,0,176,177,173,172,3,2,6,5,43,99,98,102,101,0,178,179,174,173,2,1,7,6,43,98,97,103,102,0,180,181,175,174,1,0,4,7,43,97,96,100,103,0,169,168,172,175,0,3,5,4,43,104,105,106,107,0,182,183,184,185,3,0,1,2,43,108,109,110,111,0,186,187,188,189,5,6,7,4,43,104,107,109,108,0,190,191,187,186,3,2,6,5,43,107,106,110,109,0,192,193,188,187,2,1,7,6,43,106,105,111,110,0,194,195,189,188,1,0,4,7,43,105,104,108,111,0,183,182,186,189,0,3,5,4,43,112,113,114,115,0,196,197,198,199,3,0,1,2,43,116,117,118,119,0,200,201,202,203,5,6,7,4,43,112,115,117,116,0,204,205,201,200,3,2,6,5,43,115,114,118,117,0,206,207,202,201,2,1,7,6,43,114,113,119,118,0,208,209,203,202,1,0,4,7,43,113,112,116,119,0,197,196,200,203,0,3,5,4,43,120,121,122,123,0,210,211,212,213,3,0,1,2,43,124,125,126,127,0,214,215,216,217,5,6,7,4,43,120,123,125,124,0,218,219,215,214,3,2,6,5,43,123,122,126,125,0,220,221,216,215,2,1,7,6,43,122,121,127,126,0,222,223,217,216,1,0,4,7,43,121,120,124,127,0,211,210,214,217,0,3,5,4,43,128,129,130,131,0,224,225,226,227,0,1,2,3,43,132,133,134,135,0,228,229,230,231,4,5,6,7,43,128,131,133,132,0,232,233,229,228,0,3,5,4,43,131,130,134,133,0,234,235,230,229,3,2,6,5,43,130,129,135,134,0,236,237,231,230,2,1,7,6,43,129,128,132,135,0,225,224,228,231,1,0,4,7,43,136,137,138,139,0,238,239,240,241,0,1,2,3,43,140,141,142,143,0,242,243,244,245,4,5,6,7,43,136,139,141,140,0,246,247,243,242,0,3,5,4,43,139,138,142,141,0,248,249,244,243,3,2,6,5,43,138,137,143,142,0,250,251,245,244,2,1,7,6,43,137,136,140,143,0,239,238,242,245,1,0,4,7,43,144,145,146,147,0,252,253,254,255,0,1,2,3,43,148,149,150,151,0,256,257,258,259,4,5,6,7,43,144,147,149,148,0,260,261,257,256,0,3,5,4,43,147,146,150,149,0,262,263,258,257,3,2,6,5,43,146,145,151,150,0,264,265,259,258,2,1,7,6,43,145,144,148,151,0,253,252,256,259,1,0,4,7,43,152,153,154,155,0,266,267,268,269,0,1,2,3,43,156,157,158,159,0,270,271,272,273,4,5,6,7,43,152,155,157,156,0,274,275,271,270,0,3,5,4,43,155,154,158,157,0,276,277,272,271,3,2,6,5,43,154,153,159,158,0,278,279,273,272,2,1,7,6,43,153,152,156,159,0,267,266,270,273,1,0,4,7,43,160,161,162,163,0,280,281,282,283,8,9,9,8,43,164,160,163,165,0,284,280,283,285,10,8,8,10,43,166,164,165,167,0,286,287,288,289,11,10,10,11,43,161,166,167,162,0,281,286,289,282,9,11,11,9,43,168,169,170,171,0,290,291,292,293,8,9,9,8,43,172,168,171,173,0,294,290,293,295,10,8,8,10,43,174,172,173,175,0,296,297,298,299,11,10,10,11,43,169,174,175,170,0,291,296,299,292,9,11,11,9,43,176,177,178,179,0,300,301,302,303,8,9,9,8,43,180,176,179,181,0,304,300,303,305,10,8,8,10,43,182,180,181,183,0,306,307,308,309,11,10,10,11,43,177,182,183,178,0,301,306,309,302,9,11,11,9,43,184,185,186,187,0,310,311,312,313,8,9,9,8,43,188,184,187,189,0,314,310,313,315,10,8,8,10,43,190,188,189,191,0,316,317,318,319,11,10,10,11,43,185,190,191,186,0,311,316,319,312,9,11,11,9,43,192,193,194,195,0,320,321,322,323,8,9,9,8,43,196,192,195,197,0,324,320,323,325,10,8,8,10,43,198,196,197,199,0,326,327,328,329,11,10,10,11,43,193,198,199,194,0,321,326,329,322,9,11,11,9,43,200,201,202,203,0,330,331,332,333,8,9,9,8,43,204,200,203,205,0,334,330,333,335,10,8,8,10,43,206,204,205,207,0,336,337,338,339,11,10,10,11,43,201,206,207,202,0,331,336,339,332,9,11,11,9,43,208,209,210,211,0,340,341,342,343,8,9,9,8,43,212,208,211,213,0,344,340,343,345,10,8,8,10,43,214,212,213,215,0,346,347,348,349,11,10,10,11,43,209,214,215,210,0,341,346,349,342,9,11,11,9,43,216,217,218,219,0,350,351,352,353,8,9,9,8,43,220,216,219,221,0,354,350,353,355,10,8,8,10,43,222,220,221,223,0,356,357,358,359,11,10,10,11,43,217,222,223,218,0,351,356,359,352,9,11,11,9,43,224,225,226,227,0,360,361,362,363,8,9,9,8,43,228,224,227,229,0,364,360,363,365,10,8,8,10,43,230,228,229,231,0,366,367,368,369,11,10,10,11,43,225,230,231,226,0,361,366,369,362,9,11,11,9,43,232,233,234,235,0,370,371,372,373,8,9,9,8,43,236,232,235,237,0,374,370,373,375,10,8,8,10,43,238,236,237,239,0,376,377,378,379,11,10,10,11,43,233,238,239,234,0,371,376,379,372,9,11,11,9,43,240,241,242,243,0,380,381,382,383,8,9,9,8,43,244,240,243,245,0,384,380,383,385,10,8,8,10,43,246,244,245,247,0,386,387,388,389,11,10,10,11,43,241,246,247,242,0,381,386,389,382,9,11,11,9,43,248,249,250,251,0,390,391,392,393,8,9,9,8,43,252,248,251,253,0,394,390,393,395,10,8,8,10,43,254,252,253,255,0,396,397,398,399,11,10,10,11,43,249,254,255,250,0,391,396,399,392,9,11,11,9,43,256,257,258,259,0,400,401,402,403,8,9,9,8,43,260,256,259,261,0,404,400,403,405,10,8,8,10,43,262,260,261,263,0,406,407,408,409,11,10,10,11,43,257,262,263,258,0,401,406,409,402,9,11,11,9,43,264,265,266,267,0,410,411,412,413,8,9,9,8,43,268,264,267,269,0,414,410,413,415,10,8,8,10,43,270,268,269,271,0,416,417,418,419,11,10,10,11,43,265,270,271,266,0,411,416,419,412,9,11,11,9,43,272,273,274,275,0,420,421,422,423,8,9,9,8,43,276,272,275,277,0,424,420,423,425,10,8,8,10,43,278,276,277,279,0,426,427,428,429,11,10,10,11,43,273,278,279,274,0,421,426,429,422,9,11,11,9,43,280,281,282,283,0,430,431,432,433,8,9,9,8,43,284,280,283,285,0,434,430,433,435,10,8,8,10,43,286,284,285,287,0,436,437,438,439,11,10,10,11,43,281,286,287,282,0,431,436,439,432,9,11,11,9,43,288,289,290,291,0,440,441,442,443,8,9,9,8,43,292,288,291,293,0,444,440,443,445,10,8,8,10,43,294,292,293,295,0,446,447,448,449,11,10,10,11,43,289,294,295,290,0,441,446,449,442,9,11,11,9,43,296,297,298,299,0,450,451,452,453,8,9,9,8,43,300,296,299,301,0,454,450,453,455,10,8,8,10,43,302,300,301,303,0,456,457,458,459,11,10,10,11,43,297,302,303,298,0,451,456,459,452,9,11,11,9,43,304,305,306,307,0,460,461,462,463,8,9,9,8,43,308,304,307,309,0,464,460,463,465,10,8,8,10,43,310,308,309,311,0,466,467,468,469,11,10,10,11,43,305,310,311,306,0,461,466,469,462,9,11,11,9,43,312,313,314,315,0,470,471,472,473,8,9,9,8,43,316,312,315,317,0,474,470,473,475,10,8,8,10,43,318,316,317,319,0,476,477,478,479,11,10,10,11,43,313,318,319,314,0,471,476,479,472,9,11,11,9,43,320,321,322,323,0,480,481,482,483,8,9,9,8,43,324,320,323,325,0,484,480,483,485,10,8,8,10,43,326,324,325,327,0,486,487,488,489,11,10,10,11,43,321,326,327,322,0,481,486,489,482,9,11,11,9,43,328,329,330,331,0,490,491,492,493,8,9,9,8,43,332,328,331,333,0,494,490,493,495,10,8,8,10,43,334,332,333,335,0,496,497,498,499,11,10,10,11,43,329,334,335,330,0,491,496,499,492,9,11,11,9,43,336,337,338,339,0,500,501,502,503,8,9,9,8,43,340,336,339,341,0,504,500,503,505,10,8,8,10,43,342,340,341,343,0,506,507,508,509,11,10,10,11,43,337,342,343,338,0,501,506,509,502,9,11,11,9,43,344,345,346,347,0,510,511,512,513,8,9,9,8,43,348,344,347,349,0,514,510,513,515,10,8,8,10,43,350,348,349,351,0,516,517,518,519,11,10,10,11,43,345,350,351,346,0,511,516,519,512,9,11,11,9,43,352,353,354,355,0,520,521,522,523,8,9,9,8,43,356,352,355,357,0,524,520,523,525,10,8,8,10,43,358,356,357,359,0,526,527,528,529,11,10,10,11,43,353,358,359,354,0,521,526,529,522,9,11,11,9],
+
+ "bones" : [],
+
+ "skinIndices" : [],
+
+ "skinWeights" : [],
+
+ "animations" : []
+
+
+}
diff --git a/examples/canvas3d/jsonmodels/qml.qrc b/examples/canvas3d/jsonmodels/qml.qrc
new file mode 100644
index 0000000..9a3a957
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/qml.qrc
@@ -0,0 +1,19 @@
+<RCC>
+ <qresource prefix="/">
+ <file>glMatrix-0.9.5.min.js</file>
+ <file>gold.json</file>
+ <file>ThreeJSLoader.js</file>
+ <file>woodbox.json</file>
+ <file>bush.json</file>
+ <file>pallet.json</file>
+ <file>rock.json</file>
+ <file>pallet.jpg</file>
+ <file>rock.jpg</file>
+ <file>gold.jpg</file>
+ <file>woodbox.jpg</file>
+ <file>bush.png</file>
+ <file>jsonmodels.js</file>
+ <file>jsonmodels.qml</file>
+ <file>jsonmodelsbasic.qml</file>
+ </qresource>
+</RCC>
diff --git a/examples/canvas3d/jsonmodels/readme.txt b/examples/canvas3d/jsonmodels/readme.txt
new file mode 100644
index 0000000..0996800
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/readme.txt
@@ -0,0 +1,3 @@
+3D Models and textures used in the example courtesy of http://nobiax.deviantart.com/
+
+See 3dmodels.txt for more information about the models. \ No newline at end of file
diff --git a/examples/canvas3d/jsonmodels/rock.jpg b/examples/canvas3d/jsonmodels/rock.jpg
new file mode 100644
index 0000000..023035d
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/rock.jpg
Binary files differ
diff --git a/examples/canvas3d/jsonmodels/rock.json b/examples/canvas3d/jsonmodels/rock.json
new file mode 100644
index 0000000..72127b6
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/rock.json
@@ -0,0 +1,42 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "generatedBy" : "Blender 2.7 Exporter",
+ "vertices" : 102,
+ "faces" : 200,
+ "normals" : 102,
+ "colors" : 0,
+ "uvs" : [148],
+ "materials" : 0,
+ "morphTargets" : 0,
+ "bones" : 0
+ },
+
+ "scale" : 30.000000,
+
+ "materials" : [],
+
+ "vertices" : [-3.48797,-2.95468,7.08177,-5.32847,-2.5644,4.49579,-3.78357,-5.33534,4.84091,0.36732,-3.19927,7.41514,-0.06208,-5.21103,5.7029,-4.41892,-0.645211,6.95992,-1.20424,-0.777831,7.15025,-5.81985,-0.576321,4.45764,3.88,-2.61767,5.77622,3.31687,-1.11737,7.45119,2.07679,-3.79156,5.86468,5.19294,-0.251021,6.63316,1.11213,-0.477711,7.2304,2.2281,1.10384,7.20116,1.48249,2.85095,6.8374,5.58399,2.71664,4.82859,2.4293,4.51119,5.07261,0.75634,4.26501,6.2493,-1.11515,2.57498,6.74687,6.39477,-0.519301,5.38904,-1.8777,3.59732,6.01294,-3.96561,3.65329,3.08605,-4.62071,2.41627,4.45055,-5.51179,0.907309,5.45365,-3.79723,1.55253,6.77793,-0.43277,4.81693,5.72144,-2.4531,4.93726,2.83048,-5.11515,3.87374,1.6376,0.70264,5.83825,4.93236,-1.1089,6.21538,2.86321,1.16732,7.00829,1.74753,-0.45004,7.19237,-0.447879,-1.95972,6.72344,0.531461,-3.59747,5.6844,0.667031,-3.52789,5.28623,-1.20333,5.73456,4.7813,2.97697,3.41474,6.82853,2.69681,4.42947,5.76217,-0.402799,2.32469,7.43503,0.467801,1.77164,7.23564,-2.29136,3.86719,4.41436,-5.47892,1.07968,5.60551,-5.51487,2.81572,6.88968,-1.65168,4.92747,4.91081,-2.12767,-0.82117,6.44981,-2.78694,-2.05597,5.52614,-3.84299,-1.31983,4.97489,-5.53985,-4.31561,2.0466,-4.00447,-0.07734,3.36308,-6.4996,-1.63382,-0.894099,-6.34447,1.20103,-0.539079,-7.50713,-2.98044,-0.279719,-5.29083,-4.48793,-0.82402,-4.15656,5.80354,1.31693,-4.69672,4.96973,-1.40687,-5.91637,3.41875,0.994711,-6.58949,1.74384,2.65546,-6.4395,2.19821,-2.75553,-7.09694,3.95713,-3.63892,-4.94121,0.1998,-6.20937,-5.3833,-0.13698,-2.50222,-7.12123,2.46833,-5.6957,-4.30768,-4.97238,-4.40987,-2.47592,-2.85709,-2.84807,-5.21821,-2.32443,-5.2165,-5.00417,-5.45276,-5.10059,2.93825,-4.33031,-6.23095,2.55232,-5.00667,-5.41863,-0.113021,-3.98829,-6.39516,0.824669,-0.75027,-6.65522,0.641849,0.47847,-6.28575,2.69625,-2.07119,-6.26115,2.83183,-3.66459,-6.38201,-1.26747,-2.79305,-6.52591,-3.47798,-0.08125,-6.33792,-3.49339,-1.30827,-6.44351,-2.47057,4.42157,-4.79764,-3.14348,5.45501,-4.97326,-0.449501,1.77874,-6.64072,1.01024,2.98886,-6.05347,-1.63411,1.16124,-6.73581,-0.902031,3.11539,-5.6883,2.50764,5.97839,-4.3528,1.79094,6.53337,2.21848,3.46916,7.32447,-0.3297,1.99527,7.02727,1.50936,-0.27971,7.14184,2.91039,0.81278,6.59089,3.71753,-1.21035,7.37303,-2.17679,3.7072,6.56855,-3.03723,-1.53606,6.99887,-2.81482,1.64137,5.62592,-2.95998,-3.82508,6.63669,-0.83669,-1.88168,6.37868,2.96381,-3.11829,-5.65432,-0.36744,-2.32105,-6.10154,1.19555,-0.23874,-5.37234,2.77649,-0.11497,-6.45554,-0.36563,-0.67517,-6.68683,-0.0393902,1.80538,-5.99887,-4.10642,-0.19584,-6.37839,-2.32142,2.27487,-6.45336,1.50944,2.79992],
+
+ "morphTargets" : [],
+
+ "normals" : [-0.401715,-0.345683,0.847987,-0.839259,-0.264779,0.474868,-0.406995,-0.711234,0.573077,0.094577,-0.384533,0.918241,0.110416,-0.792352,0.599933,-0.542405,-0.031159,0.839503,-0.055666,0.084719,0.994842,-0.911466,-0.123386,0.392407,0.472976,-0.616688,0.629261,0.302988,-0.19248,0.933317,0.431715,-0.661977,0.61269,0.572375,-0.031587,0.819361,-0.069765,0.088809,0.993591,0.114139,0.20716,0.971618,0.174505,0.381756,0.90762,0.623188,0.438581,0.647481,0.395947,0.571734,0.718528,0.128056,0.529923,0.838282,-0.115116,0.305155,0.945311,0.788995,-0.064913,0.61095,-0.400311,0.63448,0.661184,-0.505295,0.731468,0.457808,-0.596881,0.679128,0.427168,-0.813685,0.281442,0.508591,-0.398541,0.412091,0.81933,-0.313303,0.660482,0.682333,-0.564623,0.675161,0.474685,-0.754845,0.637745,0.153172,0.007172,0.796808,0.604144,-0.39906,0.825068,0.399945,-0.120853,0.954894,0.271126,-0.260659,0.963836,-0.055147,-0.409986,0.910154,0.059145,-0.65862,0.744072,0.111942,-0.696829,0.670675,-0.254067,0.699576,0.61623,0.361644,0.385998,0.854518,0.347484,0.645527,0.756951,-0.101199,0.225684,0.973174,0.043977,0.135563,0.9429,-0.304117,0.493149,0.525193,-0.693472,0.05591,0.704276,-0.707663,0.529435,0.821741,-0.210669,0.647786,0.715629,-0.261208,-0.332133,0.893368,-0.302499,-0.56386,0.730949,-0.38435,-0.431166,0.557756,-0.709189,-0.761925,0.281686,-0.583148,-0.172582,0.268502,-0.947661,-0.521622,0.026643,-0.852748,0.002564,0.066103,-0.997803,-0.594256,0.051698,-0.802576,-0.741386,-0.043519,-0.669637,0.818964,0.090243,-0.566668,0.689352,-0.179571,-0.701804,0.400891,0.171941,-0.899808,0.167302,0.298898,-0.939482,0.29603,-0.342692,-0.891568,0.565813,-0.564287,-0.601123,0.058107,-0.812708,-0.57973,-0.283639,-0.20661,-0.936369,0.427717,-0.806604,-0.40791,-0.805322,-0.378979,-0.455824,-0.630909,-0.163793,-0.758324,-0.519608,-0.424879,-0.741234,-0.81106,-0.511765,0.283273,-0.403119,-0.895657,0.18778,-0.727897,-0.66924,-0.149174,-0.371014,-0.928556,-0.00885,-0.044496,-0.996765,0.06653,0.096133,-0.950072,0.296762,-0.037141,-0.965026,0.259438,-0.430555,-0.892331,-0.13538,-0.390545,-0.859401,-0.329875,0.112003,-0.988556,-0.100955,-0.0065,-0.999115,-0.040864,0.609027,-0.702506,-0.368145,0.648366,-0.756493,-0.085177,0.225898,-0.96353,0.143315,0.378246,-0.913327,-0.150822,0.130985,-0.986602,-0.097201,0.405713,-0.837062,0.366955,0.646474,-0.731193,0.217658,0.898984,0.255959,0.355327,0.998474,0.042024,0.035646,0.983703,0.020142,-0.178564,0.955931,0.292459,0.025483,0.85165,0.492538,-0.179022,0.871578,-0.323191,0.368572,0.905606,-0.343883,-0.248085,0.930509,-0.358196,-0.076205,0.801447,-0.397504,-0.44676,0.961303,-0.063875,-0.267953,0.872982,0.324229,-0.36433,-0.889523,0.042573,-0.454848,-0.911924,0.332499,-0.240333,-0.856441,0.463088,-0.228065,-0.95706,0.05942,-0.283608,-0.998535,0.026246,0.047212,-0.914212,-0.363689,-0.178655,-0.968139,-0.179968,0.174047,-0.921384,0.333628,0.199286],
+
+ "colors" : [],
+
+ "uvs" : [[0.6195,0.0857,0.5513,0.1162,0.5466,0.0354,0.7008,0.0209,0.043,0.7169,0.1279,0.7852,0.1094,0.8581,0.6131,0.1497,0.6823,0.1189,0.555,0.1849,0.2231,0.8795,0.184,0.9351,0.1761,0.8383,0.2455,0.9595,0.7597,0.0804,0.8097,0.0326,0.8103,0.1082,0.1063,0.376,0.1693,0.2623,0.1803,0.3616,0.8062,0.2209,0.7356,0.1875,0.8116,0.1675,0.1459,0.4109,0.0728,0.2378,0.1021,0.1916,0.0673,0.3351,0.0216,0.2785,0.7226,0.2289,0.6599,0.2836,0.6336,0.2464,0.605,0.2035,0.6654,0.1891,0.7754,0.2553,0.693,0.3332,0.5906,0.326,0.1684,0.4504,0.2048,0.4169,0.2624,0.4695,0.2472,0.5223,0.2971,0.4036,0.3638,0.4455,0.333,0.4937,0.6346,0.4001,0.3191,0.5512,0.7957,0.9453,0.8761,0.9432,0.8379,0.984,0.2455,0.2672,0.2658,0.351,0.3369,0.289,0.3302,0.3679,0.7718,0.8085,0.8265,0.6916,0.862,0.7614,0.7402,0.7844,0.7306,0.6985,0.8391,0.8528,0.4106,0.3725,0.3871,0.338,0.3783,0.2464,0.8936,0.8558,0.7795,0.893,0.917,0.8034,0.5561,0.805,0.5907,0.9285,0.4998,0.9127,0.4503,0.8801,0.9335,0.7374,0.4693,0.7101,0.4097,0.8261,0.3808,0.7047,0.5127,0.7606,0.5676,0.7246,0.8111,0.5949,0.8647,0.5363,0.8907,0.6222,0.9731,0.615,0.9038,0.6875,0.9708,0.5401,0.9086,0.4787,0.4625,0.5584,0.4318,0.6601,0.3722,0.6323,0.9571,0.4153,0.4048,0.522,0.6209,0.6278,0.5202,0.6833,0.5191,0.6168,0.4816,0.0769,0.4634,0.029,0.384,0.0871,0.401,0.0289,0.1816,0.6472,0.1825,0.7121,0.1169,0.6833,0.062,0.645,0.0963,0.6047,0.1357,0.556,0.5601,0.5545,0.6333,0.5501,0.4867,0.5141,0.2142,0.5616,0.1916,0.5131,0.2618,0.5552,0.697,0.5354,0.6843,0.5864,0.8813,0.4196,0.3554,0.7261,0.2373,0.6922,0.3111,0.6513,0.9028,0.3467,0.8106,0.3648,0.2512,0.6387,0.4082,0.4407,0.2487,0.7526,0.3331,0.7927,0.1912,0.21,0.1924,0.1355,0.2781,0.1528,0.247,0.1936,0.3278,0.2025,0.3426,0.8863,0.1358,0.0087,0.2538,0.0087,0.1657,0.0616,0.1181,0.1132,0.295,0.9441,0.8467,0.4779,0.7603,0.5039,0.784,0.4386,0.2949,0.0671,0.7431,0.3319,0.7504,0.6233,0.376,0.1633,0.6281,0.7463,0.6812,0.8061,0.6644,0.8587,0.4386,0.26,0.5107,0.2285,0.4816,0.3003,0.6826,0.7525,0.6385,0.9644,0.6947,0.637,0.3998,0.1421,0.4921,0.1642,0.5579,0.2475,0.5247,0.3437]],
+
+ "faces" : [40,0,1,2,0,1,2,0,1,2,40,3,0,2,3,0,2,3,0,2,40,2,4,3,4,5,6,2,4,3,40,5,0,6,7,0,8,5,0,6,40,0,3,6,0,3,8,0,3,6,40,7,1,5,9,1,7,7,1,5,40,1,0,5,1,0,7,1,0,5,40,8,9,10,10,11,12,8,9,10,40,8,11,9,10,13,11,8,11,9,40,12,6,3,14,8,3,12,6,3,40,3,9,12,3,15,14,3,9,12,40,9,13,12,15,16,14,9,13,12,40,3,4,10,6,5,12,3,4,10,40,10,9,3,12,11,6,10,9,3,40,14,15,16,17,18,19,14,15,16,40,17,18,14,20,21,22,17,18,14,40,14,16,17,17,19,23,14,16,17,40,18,12,13,21,14,16,18,12,13,40,13,14,18,16,22,21,13,14,18,40,11,19,15,24,25,18,11,19,15,40,15,14,11,18,17,24,15,14,11,40,11,14,13,24,17,26,11,14,13,40,13,9,11,26,27,24,13,9,11,40,20,21,22,28,29,30,20,21,22,40,23,24,22,31,32,30,23,24,22,40,24,20,22,32,28,30,24,20,22,40,7,5,23,9,7,31,7,5,23,40,24,23,5,32,31,7,24,23,5,40,6,12,18,8,14,21,6,12,18,40,24,6,18,32,8,21,24,6,18,40,24,5,6,32,7,8,24,5,6,40,18,17,25,21,20,33,18,17,25,40,18,25,20,21,33,28,18,25,20,40,20,24,18,28,32,21,20,24,18,40,21,20,26,29,28,34,21,20,26,40,20,25,26,28,33,34,20,25,26,40,26,27,21,34,35,29,26,27,21,40,25,17,28,36,23,37,25,17,28,40,25,28,29,36,37,38,25,28,29,40,29,26,25,38,39,36,29,26,25,40,30,31,32,40,41,42,30,31,32,40,29,30,32,38,40,42,29,30,32,40,33,27,26,43,35,34,33,27,26,40,26,29,33,39,38,44,26,29,33,40,29,32,33,38,42,44,29,32,33,40,32,34,33,45,46,47,32,34,33,40,16,15,35,19,18,48,16,15,35,40,36,16,35,49,19,48,36,16,35,40,36,35,37,49,48,50,36,35,37,40,38,36,37,51,49,50,38,36,37,40,38,31,30,51,41,40,38,31,30,40,28,17,16,37,23,19,28,17,16,40,36,38,30,49,51,40,36,38,30,40,16,36,28,19,49,37,16,36,28,40,28,36,30,37,49,40,28,36,30,40,30,29,28,40,38,37,30,29,28,40,39,40,41,52,53,54,39,40,41,40,39,42,40,52,55,53,39,42,40,40,40,42,43,53,55,56,40,42,43,40,44,39,41,57,52,54,44,39,41,40,31,38,39,41,51,58,31,38,39,40,42,39,38,59,58,51,42,39,38,40,37,43,42,50,60,59,37,43,42,40,42,38,37,59,51,50,42,38,37,40,44,45,34,57,61,46,44,45,34,40,39,44,31,52,57,62,39,44,31,40,34,32,31,46,45,62,34,32,31,40,34,31,44,46,62,57,34,31,44,40,44,41,46,57,54,63,44,41,46,40,46,45,44,63,61,57,46,45,44,40,47,34,45,64,65,66,47,34,45,40,47,45,46,64,66,67,47,45,46,40,46,41,48,63,54,68,46,41,48,40,49,46,48,69,67,70,49,46,48,40,49,48,50,69,70,71,49,48,50,40,51,52,47,72,73,64,51,52,47,40,47,46,51,64,67,72,47,46,51,40,46,49,51,67,69,72,46,49,51,40,53,54,55,74,75,76,53,54,55,40,40,53,55,53,74,76,40,53,55,40,55,50,56,76,77,78,55,50,56,40,50,48,56,77,68,78,50,48,56,40,56,48,41,78,68,54,56,48,41,40,40,56,41,53,78,54,40,56,41,40,40,55,56,53,76,78,40,55,56,40,57,54,58,79,75,80,57,54,58,40,59,60,57,81,82,83,59,60,57,40,58,61,57,80,84,79,58,61,57,40,57,61,59,83,85,81,57,61,59,40,50,55,57,77,76,79,50,55,57,40,57,60,50,83,82,71,57,60,50,40,57,55,54,79,76,75,57,55,54,40,62,63,64,86,87,88,62,63,64,40,52,51,63,73,72,87,52,51,63,40,63,51,49,87,72,69,63,51,49,40,50,60,49,71,82,69,50,60,49,40,63,49,60,87,69,82,63,49,60,40,60,59,64,82,81,88,60,59,64,40,64,63,60,88,87,82,64,63,60,40,65,66,2,89,90,2,65,66,2,40,66,67,68,90,91,92,66,67,68,40,69,70,71,93,94,95,69,70,71,40,71,66,68,95,96,97,71,66,68,40,71,68,69,95,97,93,71,68,69,40,72,69,68,98,93,97,72,69,68,40,2,71,4,4,95,5,2,71,4,40,66,71,2,96,95,4,66,71,2,40,71,70,4,95,94,5,71,70,4,40,73,72,62,99,100,86,73,72,62,40,73,62,64,99,86,88,73,62,64,40,73,64,59,99,88,81,73,64,59,40,59,74,73,81,101,99,59,74,73,40,69,72,75,93,98,102,69,72,75,40,72,73,75,98,103,102,72,73,75,40,73,74,75,103,104,102,73,74,75,40,68,67,72,105,106,100,68,67,72,40,58,76,61,80,107,84,58,76,61,40,77,78,79,108,109,110,77,78,79,40,79,61,76,111,84,107,79,61,76,40,79,76,77,111,107,112,79,76,77,40,69,75,80,93,102,113,69,75,80,40,75,74,80,102,104,113,75,74,80,40,80,74,79,113,104,110,80,74,79,40,79,74,61,114,101,85,79,74,61,40,74,59,61,101,81,85,74,59,61,40,10,81,8,12,115,10,10,81,8,40,81,82,8,115,116,10,81,82,8,40,4,70,81,5,94,115,4,70,81,40,81,10,4,115,12,5,81,10,4,40,78,69,80,109,93,113,78,69,80,40,79,78,80,110,109,113,79,78,80,40,78,81,70,109,115,94,78,81,70,40,70,69,78,94,93,109,70,69,78,40,81,78,77,115,109,108,81,78,77,40,81,77,82,115,108,116,81,77,82,40,15,83,35,18,117,48,15,83,35,40,83,15,19,117,18,25,83,15,19,40,84,85,86,118,119,120,84,85,86,40,19,84,83,25,118,117,19,84,83,40,83,84,86,117,118,120,83,84,86,40,35,83,86,48,117,120,35,83,86,40,86,87,35,120,121,48,86,87,35,40,8,82,88,10,116,122,8,82,88,40,82,89,90,123,124,125,82,89,90,40,90,88,82,125,126,123,90,88,82,40,88,90,84,126,125,118,88,90,84,40,89,84,90,124,118,125,89,84,90,40,11,8,19,13,10,127,11,8,19,40,19,8,88,127,10,122,19,8,88,40,84,19,88,118,25,126,84,19,88,40,76,58,91,107,80,128,76,58,91,40,58,54,91,80,75,128,58,54,91,40,91,92,89,128,129,130,91,92,89,40,89,76,91,130,107,128,89,76,91,40,54,53,92,75,74,129,54,53,92,40,91,54,92,128,75,129,91,54,92,40,85,84,92,119,118,131,85,84,92,40,92,84,89,131,118,124,92,84,89,40,77,76,89,112,107,130,77,76,89,40,89,82,77,130,132,112,89,82,77,40,40,43,93,53,56,133,40,43,93,40,93,53,40,133,74,53,93,53,40,40,37,35,87,50,48,121,37,35,87,40,93,43,87,134,60,121,93,43,87,40,43,37,87,60,50,121,43,37,87,40,92,93,85,131,134,119,92,93,85,40,92,53,93,129,74,133,92,53,93,40,93,87,85,134,121,119,93,87,85,40,86,85,87,120,119,121,86,85,87,40,47,52,94,64,73,135,47,52,94,40,94,95,47,135,136,64,94,95,47,40,95,96,47,136,137,64,95,96,47,40,97,98,95,138,139,140,97,98,95,40,95,94,97,136,135,141,95,94,97,40,96,33,34,137,142,65,96,33,34,40,47,96,34,64,137,65,47,96,34,40,63,62,52,87,86,73,63,62,52,40,94,52,62,135,73,86,94,52,62,40,94,62,99,135,86,143,94,62,99,40,62,67,99,86,106,143,62,67,99,40,62,72,67,86,100,106,62,72,67,40,97,94,99,141,135,143,97,94,99,40,97,99,100,138,144,145,97,99,100,40,1,65,2,1,89,2,1,65,2,40,100,65,1,145,89,1,100,65,1,40,100,1,7,145,1,9,100,1,7,40,98,97,100,139,138,145,98,97,100,40,100,7,98,145,9,139,100,7,98,40,67,66,65,91,90,89,67,66,65,40,65,100,99,89,145,144,65,100,99,40,65,99,67,89,144,91,65,99,67,40,21,27,22,29,35,30,21,27,22,40,27,101,22,35,146,30,27,101,22,40,33,96,27,43,147,35,33,96,27,40,96,101,27,147,146,35,96,101,27,40,7,101,98,9,146,139,7,101,98,40,98,101,95,139,146,140,98,101,95,40,96,95,101,147,140,146,96,95,101,40,23,22,101,31,30,146,23,22,101,40,101,7,23,146,9,31,101,7,23],
+
+ "bones" : [],
+
+ "skinIndices" : [],
+
+ "skinWeights" : [],
+
+ "animations" : []
+
+
+}
diff --git a/examples/canvas3d/jsonmodels/woodbox.jpg b/examples/canvas3d/jsonmodels/woodbox.jpg
new file mode 100644
index 0000000..fd9c10d
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/woodbox.jpg
Binary files differ
diff --git a/examples/canvas3d/jsonmodels/woodbox.json b/examples/canvas3d/jsonmodels/woodbox.json
new file mode 100644
index 0000000..141ad57
--- /dev/null
+++ b/examples/canvas3d/jsonmodels/woodbox.json
@@ -0,0 +1,47 @@
+{
+
+ "metadata" :
+ {
+ "formatVersion" : 3.1,
+ "generatedBy" : "Blender 2.7 Exporter",
+ "vertices" : 112,
+ "faces" : 130,
+ "normals" : 88,
+ "colors" : 0,
+ "uvs" : [208],
+ "materials" : 1,
+ "morphTargets" : 0,
+ "bones" : 0
+ },
+
+ "scale" : 1.000000,
+
+ "materials" : [ {
+ "DbgColor" : 15658734,
+ "DbgIndex" : 0,
+ "DbgName" : "default",
+ "vertexColors" : false
+ }],
+
+ "vertices" : [-0.1575,0.105,-0.09,-0.1725,0.105,-0.09,-0.1725,0.105,0.09,-0.1575,0.105,0.09,-0.1575,0.03,-0.09,-0.1575,0.03,0.09,-0.1725,0.03,0.09,-0.1725,0.03,-0.09,-0.1875,0.105,0.09,-0.1777,0.105,0.105,-0.1875,0.03,0.09,-0.1777,0.03,0.105,0.1777,0.105,0.105,0.1777,0.03,0.105,0.1875,0.03,0.09,0.1875,0.105,0.09,0.1725,0.03,0.09,0.1725,0.105,0.09,0.1875,0.105,-0.09,0.1875,0.03,-0.09,0.1777,0.03,-0.105,0.1777,0.105,-0.105,-0.1777,0.105,-0.105,-0.1777,0.03,-0.105,-0.1875,0.03,-0.09,-0.1875,0.105,-0.09,0.1575,0.105,0.09,0.1725,0.105,-0.09,0.1575,0.105,-0.09,0.1575,0.03,0.09,0.1575,0.03,-0.09,0.1725,0.03,-0.09,0,0.03,0.1075,0,0.03,-0.1075,-0.1835,0.03,-0.1075,-0.1835,0.03,0.1075,-0.1348,0.015,-0.109,-0.1348,0.015,0.109,-0.1778,0.015,0.1093,-0.1778,0.015,-0.1093,-0.1875,0.03,-0.1121,-0.1835,0.03,-0.1121,0.1875,0.03,-0.1121,0.1875,0.03,-0.1075,0.1778,0.015,-0.1093,0.1875,0.03,0.1121,0.1835,0.03,0.1121,0.1778,0.015,0.1093,-0.1875,0.03,0.1121,-0.1875,0.03,0.1075,-0.1333,1.23382e-08,-0.1035,-0.0617,1.23382e-08,-0.1035,-0.0617,-1.23382e-08,0.1035,-0.1333,-1.23382e-08,0.1035,-0.0602,0.015,-0.109,-0.0602,0.015,0.109,0.0617,1.23382e-08,-0.1035,0.1333,1.23382e-08,-0.1035,0.1333,-1.23382e-08,0.1035,0.0617,-1.23382e-08,0.1035,0.0602,0.015,-0.109,0.1348,0.015,-0.109,0.1348,0.015,0.109,0.0602,0.015,0.109,0.1835,0.03,0.1075,0.1835,0.03,-0.1075,0,0.03,-0.1121,0,0.03,0.1121,0.1835,0.03,-0.1121,-0.1835,0.03,0.1121,0.1875,0.03,0.1075,-0.1875,0.03,-0.1075,-0.2394,0.0802,-0.1075,-0.2394,0.0802,0.1075,-0.4057,0.00259999,0.1075,-0.4057,0.00260001,-0.1075,-0.3679,0.0368,0.109,-0.3679,0.0368,-0.109,-0.4068,0.0186,-0.1093,-0.4068,0.0186,0.1093,-0.4093,0.000899987,0.1121,-0.4057,0.00259999,0.1121,-0.0694,0.1594,0.1121,-0.0694,0.1594,0.1075,-0.0846,0.1689,0.1093,-0.0694,0.1594,-0.1121,-0.0731,0.1577,-0.1121,-0.0846,0.1689,-0.1093,-0.4093,0.000900013,-0.1121,-0.4093,0.000900013,-0.1075,-0.3729,0.051,0.1035,-0.308,0.0813,0.1035,-0.308,0.0813,-0.1035,-0.3729,0.051,-0.1035,-0.3003,0.0683,0.109,-0.3003,0.0683,-0.109,-0.1961,0.1334,0.1035,-0.1312,0.1637,0.1035,-0.1312,0.1637,-0.1035,-0.1961,0.1334,-0.1035,-0.1912,0.1192,0.109,-0.1235,0.1507,0.109,-0.1235,0.1507,-0.109,-0.1912,0.1192,-0.109,-0.0731,0.1577,-0.1075,-0.0731,0.1577,0.1075,-0.2394,0.0802,0.1121,-0.2394,0.0802,-0.1121,-0.0731,0.1577,0.1121,-0.4057,0.00260001,-0.1121,-0.0694,0.1594,-0.1075,-0.4093,0.000899987,0.1075],
+
+ "morphTargets" : [],
+
+ "normals" : [0.301492,0.904508,0.301492,-0.301492,0.904508,0.301492,-0.301492,0.904508,-0.301492,0.301492,0.904508,-0.301492,0.301492,-0.904508,0.301492,0.301492,-0.904508,-0.301492,-0.301492,-0.904508,-0.301492,-0.301492,-0.904508,0.301492,-0.73281,0.552843,-0.396588,-0.375652,0.614032,0.694143,-0.73281,-0.552843,-0.396588,-0.375652,-0.614032,0.694143,0.375652,0.614032,0.694143,0.375652,-0.614032,0.694143,0.73281,-0.552843,-0.396588,0.73281,0.552843,-0.396588,0.73281,0.552843,0.396588,0.73281,-0.552843,0.396588,0.375652,-0.614032,-0.694143,0.375652,0.614032,-0.694143,-0.375652,0.614032,-0.694143,-0.375652,-0.614032,-0.694143,-0.73281,-0.552843,0.396588,-0.73281,0.552843,0.396588,0,1,0,-0.223518,-0.522813,-0.822596,-0.223518,-0.522813,0.822596,-0.372967,-0.750114,0.546037,-0.372967,-0.750114,-0.546037,-0.714133,0.371288,-0.593371,0.001526,0.638508,-0.769585,0.714133,0.371288,-0.593371,0.878353,0.477981,0,0.372967,-0.750114,-0.546037,0.714133,0.371288,0.593371,-0.001526,0.638508,0.769585,0.372967,-0.750114,0.546037,-0.714133,0.371288,0.593371,-0.878353,0.477981,0,-0.562426,-0.687124,-0.459883,0.562426,-0.687124,-0.459883,0.562426,-0.687124,0.459883,-0.562426,-0.687124,0.459883,0.223884,-0.522752,-0.822535,0.223884,-0.522752,0.822535,-0.223884,-0.522752,-0.822535,0.223518,-0.522813,-0.822596,0.223518,-0.522813,0.822596,-0.223884,-0.522752,0.822535,0,0.631489,-0.775353,0,0.631489,0.775353,-0.001526,0.638508,-0.769585,0.001526,0.638508,0.769585,0.42262,-0.906278,0,0.424909,-0.905209,0,-0.42375,0.378948,0.822687,-0.42375,0.378948,-0.822687,-0.654622,0.52266,-0.546129,-0.654622,0.52266,0.546129,-0.489639,-0.639149,0.593036,0.272225,-0.576556,0.770348,0.804407,-0.036409,0.592944,0.997955,-0.063906,0,0.019745,0.837428,0.546159,0.804407,-0.036409,-0.592944,0.266396,-0.579363,-0.770287,0.019745,0.837428,-0.546159,-0.489639,-0.639149,-0.593036,-0.593127,-0.805078,0,-0.800623,0.384014,0.459883,0.219642,0.860317,0.459975,0.219642,0.860317,-0.459975,-0.800623,0.384014,-0.459883,-0.017853,0.568224,0.822657,-0.017853,0.568224,-0.822657,-0.799402,0.386639,0.459792,0.21955,0.860408,0.459822,0.21955,0.860408,-0.459822,-0.799402,0.386639,-0.459792,-0.424055,0.380291,0.821894,-0.018555,0.568133,0.822687,-0.018555,0.568133,-0.822687,-0.424055,0.380291,-0.821894,0.419935,-0.907529,0,0.266762,-0.5721,0.775567,0.266762,-0.5721,-0.775567,0.266396,-0.579363,0.770287,0.272225,-0.576556,-0.770348],
+
+ "colors" : [],
+
+ "uvs" : [[0.971,0.4805,0.9874,0.4805,0.9874,0.6776,0.971,0.6776,0.8889,0.4805,0.8889,0.6776,0.8725,0.6776,0.8725,0.4805,0.7904,0.4805,0.7904,0.6776,0.6953,0.9163,0.6789,0.9057,0.6953,0.8999,0.5804,0.9163,0.5804,0.8999,0.5968,0.9057,0.6789,0.9252,0.5968,0.9252,0.6789,0.5165,0.5968,0.5165,0.5968,0.4969,0.6789,0.4969,0.5968,0.4805,0.6789,0.4805,0.6789,0.0229,0.761,0.0229,0.761,0.0424,0.6789,0.0424,0.6789,0.4316,0.761,0.4316,0.761,0.4512,0.6789,0.4512,0.9874,0.2035,0.971,0.2035,0.971,0.0064,0.9874,0.0064,0.8725,0.2035,0.8725,0.0064,0.8889,0.0064,0.8889,0.2035,0.7904,0.0064,0.7904,0.2035,0.6789,0.9417,0.5968,0.9417,0.761,0.4676,0.6789,0.4676,0.6625,0.4423,0.6625,0.4258,0.7774,0.4258,0.7774,0.4423,0.6625,0.0482,0.6625,0.0318,0.7774,0.0318,0.7774,0.0482,0.6789,0.0064,0.761,0.0064,0.6953,0.5058,0.6953,0.5223,0.5804,0.5223,0.5804,0.5058,0.7774,0.5387,0.7774,0.8835,0.6953,0.8835,0.6953,0.5387,0.6625,0.0646,0.6625,0.4094,0.5804,0.4094,0.5804,0.0646,0.5804,0.8835,0.5804,0.5387,0.7774,0.0646,0.7774,0.4094,0.3103,0.2117,0.5457,0.2117,0.5457,0.4126,0.3103,0.4126,0.0254,0.4276,0.2641,0.4276,0.2644,0.4746,0.0251,0.4746,0.5507,0.4169,0.5507,0.4126,0.5674,0.4063,0.022,0.0064,0.0271,0.0064,0.0251,0.026,0.3052,0.0064,0.3052,0.0108,0.2886,0.0171,0.2675,0.4942,0.2625,0.4942,0.0315,0.4111,0.0315,0.3327,0.258,0.3327,0.258,0.4111,0.014,0.4127,0.014,0.3311,0.0254,0.3162,0.2641,0.3162,0.2756,0.3311,0.2756,0.4127,0.0315,0.1679,0.0315,0.0895,0.258,0.0895,0.258,0.1679,0.014,0.1696,0.014,0.0879,0.0254,0.073,0.2641,0.073,0.2756,0.0879,0.2756,0.1696,0.2641,0.1844,0.0254,0.1844,0.3103,0.0108,0.5457,0.0108,0.2644,0.026,0.5507,0.2117,0.5675,0.1458,0.5675,0.2776,0.3052,0.2117,0.2885,0.2776,0.2885,0.1458,0.5507,0.0108,0.5675,0.0641,0.3052,0.4126,0.2885,0.3593,0.2625,0.0064,0.2675,0.0064,0.0271,0.4942,0.022,0.4942,0.5457,0.4169,0.3103,0.4169,0.3103,0.0064,0.5457,0.0064,0.3052,0.4169,0.5507,0.0064,0.5674,0.0171,0.5675,0.3593,0.2886,0.4063,0.2885,0.0641,0.545,0.6346,0.3103,0.6346,0.3102,0.4342,0.545,0.4342,0.0254,0.9272,0.2635,0.9272,0.2638,0.974,0.0251,0.974,0.3052,0.4299,0.3052,0.4342,0.2886,0.4405,0.022,0.5071,0.0271,0.5071,0.0251,0.5266,0.55,0.8393,0.55,0.8349,0.5667,0.8286,0.2668,0.9936,0.2618,0.9936,0.0315,0.9107,0.0315,0.8325,0.2574,0.8325,0.2574,0.9107,0.014,0.9123,0.014,0.8309,0.0254,0.816,0.2635,0.816,0.2749,0.8309,0.2749,0.9123,0.0315,0.6682,0.0315,0.59,0.2574,0.59,0.2574,0.6682,0.014,0.6698,0.014,0.5883,0.0254,0.5735,0.2635,0.5735,0.2749,0.5883,0.2749,0.6698,0.2635,0.6846,0.0254,0.6846,0.545,0.8349,0.3103,0.8349,0.2638,0.5266,0.3052,0.6346,0.2885,0.7003,0.2885,0.5689,0.55,0.6346,0.5667,0.5689,0.5667,0.7003,0.3052,0.8349,0.2885,0.7817,0.55,0.4342,0.5667,0.4874,0.2618,0.5071,0.2669,0.5071,0.0271,0.9936,0.022,0.9936,0.3102,0.4299,0.545,0.4299,0.545,0.8393,0.3103,0.8393,0.55,0.4299,0.3052,0.8393,0.2886,0.8286,0.2885,0.4874,0.5667,0.4405,0.5667,0.7817]],
+
+ "faces" : [43,0,1,2,3,0,0,1,2,3,0,1,2,3,43,4,5,6,7,0,4,5,6,7,4,5,6,7,43,1,7,6,2,0,8,7,6,9,1,7,6,2,43,4,0,3,5,0,4,0,3,5,4,0,3,5,42,8,9,2,0,10,11,12,8,9,2,42,10,6,11,0,13,14,15,10,6,11,43,8,10,11,9,0,16,17,15,11,8,10,11,9,43,12,13,14,15,0,18,19,20,21,12,13,14,15,43,16,17,15,14,0,22,23,21,20,5,3,15,14,43,18,19,20,21,0,24,25,26,27,16,17,18,19,43,22,23,24,25,0,28,29,30,31,20,21,22,23,43,26,17,27,28,0,32,33,34,35,2,3,0,1,43,29,30,31,16,0,36,37,38,39,6,7,4,5,43,17,16,31,27,0,33,39,38,34,3,5,4,0,43,28,30,29,26,0,40,37,36,41,1,7,6,2,43,10,8,2,6,0,17,16,42,43,10,8,2,6,43,25,24,7,1,0,31,30,44,45,23,22,7,1,42,22,25,1,0,28,46,47,20,23,1,42,7,24,23,0,48,49,29,7,22,21,42,21,27,18,0,27,50,51,19,0,16,42,19,31,20,0,52,53,26,17,4,18,43,19,18,27,31,0,25,24,54,55,17,16,0,4,42,12,15,17,0,18,56,57,12,15,3,42,16,14,13,0,58,59,19,5,14,13,43,11,13,12,9,0,15,19,18,11,11,13,12,9,43,29,5,3,26,0,60,61,62,63,6,5,3,2,43,20,23,22,21,0,26,29,28,27,18,21,20,19,43,28,0,4,30,0,64,65,66,67,1,0,4,7,43,9,12,26,3,0,11,18,63,62,9,12,2,3,43,5,29,13,11,0,68,69,19,15,5,6,13,11,43,0,28,21,22,0,65,64,27,28,0,1,19,20,43,30,4,23,20,0,70,71,29,26,7,4,21,18,42,9,3,2,0,11,62,12,9,3,2,42,6,5,11,0,14,68,15,6,5,11,42,21,28,27,0,27,64,50,19,1,0,42,31,30,20,0,53,70,26,4,7,18,42,12,17,26,0,18,57,63,12,3,2,42,29,16,13,0,69,58,19,6,5,13,42,1,0,22,0,47,65,28,1,0,20,42,4,7,23,0,71,48,29,4,7,21,43,32,33,34,35,0,72,73,74,75,24,24,24,24,43,36,37,38,39,0,76,77,78,79,25,26,27,28,42,40,41,39,0,80,81,82,29,30,28,42,42,43,44,0,83,84,85,31,32,33,42,45,46,47,0,86,87,88,34,35,36,42,48,49,38,0,89,90,78,37,38,27,43,50,51,52,53,0,91,92,93,94,39,40,41,42,43,36,54,51,50,0,95,96,92,91,25,43,40,39,43,54,55,52,51,0,97,98,93,92,43,44,41,40,43,55,37,53,52,0,99,100,94,93,44,26,42,41,43,37,36,50,53,0,77,76,91,94,26,25,39,42,43,56,57,58,59,0,101,102,103,104,39,40,41,42,43,60,61,57,56,0,105,106,102,101,45,46,40,39,43,61,62,58,57,0,107,108,103,102,46,47,41,40,43,62,63,59,58,0,109,110,104,103,47,48,42,41,43,63,60,56,59,0,111,112,101,104,48,45,39,42,43,33,32,64,65,0,73,72,113,114,24,24,24,24,43,44,47,62,61,0,85,115,108,107,33,36,47,46,43,54,60,63,55,0,97,112,111,98,43,45,48,44,42,66,60,54,0,116,117,118,49,45,43,42,67,55,63,0,119,120,121,50,44,48,43,68,61,60,66,0,122,123,117,116,51,46,45,49,43,67,69,37,55,0,119,124,125,120,50,52,26,44,43,67,32,35,69,0,119,72,75,124,50,24,24,52,43,41,34,33,66,0,81,74,73,116,30,24,24,49,43,66,33,65,68,0,116,73,114,122,49,24,24,51,43,46,64,32,67,0,87,113,72,119,35,24,24,50,42,70,45,47,0,126,127,115,32,34,36,43,70,47,44,43,0,126,115,85,84,32,36,33,32,43,49,71,39,38,0,90,128,79,78,38,38,28,27,42,71,40,39,0,128,129,79,38,29,28,43,71,49,35,34,0,130,131,75,74,38,38,24,24,43,70,43,65,64,0,132,133,114,113,32,32,24,24,43,49,48,69,35,0,131,134,124,75,38,37,52,24,43,40,71,34,41,0,80,130,74,81,29,38,24,30,43,43,42,68,65,0,133,135,122,114,32,31,51,24,43,45,70,64,46,0,86,132,113,87,34,32,24,35,42,68,42,44,0,122,135,136,51,31,33,42,41,36,39,0,81,137,82,30,25,28,42,69,48,38,0,124,134,138,52,37,27,42,46,62,47,0,87,139,88,35,47,36,42,68,44,61,0,122,136,123,51,33,46,43,41,66,54,36,0,81,116,118,137,30,49,43,25,42,69,38,37,0,124,138,125,52,27,26,43,67,63,62,46,0,119,121,139,87,50,48,47,35,43,72,73,74,75,0,140,141,142,143,53,53,54,54,43,76,77,78,79,0,144,145,146,147,55,56,57,58,42,80,81,79,0,148,149,150,59,60,58,42,82,83,84,0,151,152,153,61,62,63,42,85,86,87,0,154,155,156,64,65,66,42,88,89,78,0,157,158,146,67,68,57,43,90,91,92,93,0,159,160,161,162,69,70,71,72,43,76,94,91,90,0,163,164,160,159,55,73,70,69,43,94,95,92,91,0,165,166,161,160,73,74,71,70,43,95,77,93,92,0,167,168,162,161,74,56,72,71,43,77,76,90,93,0,145,144,159,162,56,55,69,72,43,96,97,98,99,0,169,170,171,172,75,76,77,78,43,100,101,97,96,0,173,174,170,169,79,80,76,75,43,101,102,98,97,0,175,176,171,170,80,81,77,76,43,102,103,99,98,0,177,178,172,171,81,82,78,77,43,103,100,96,99,0,179,180,169,172,82,79,75,78,43,73,72,104,105,0,141,140,181,182,53,53,83,83,43,84,87,102,101,0,153,183,176,175,63,66,81,80,43,94,100,103,95,0,165,180,179,166,73,79,82,74,42,106,100,94,0,184,185,186,84,79,73,42,107,95,103,0,187,188,189,85,74,82,43,108,101,100,106,0,190,191,185,184,86,80,79,84,43,107,109,77,95,0,187,192,193,188,85,87,56,74,43,107,72,75,109,0,187,140,143,192,85,53,54,87,43,81,74,73,106,0,149,142,141,184,60,54,53,84,43,106,73,105,108,0,184,141,182,190,84,53,83,86,43,86,104,72,107,0,155,181,140,187,65,83,53,85,42,110,85,87,0,194,195,183,62,64,66,43,110,87,84,83,0,194,183,153,152,62,66,63,62,43,89,111,79,78,0,158,196,147,146,68,68,58,57,42,111,80,79,0,196,197,147,68,59,58,43,111,89,75,74,0,198,199,143,142,68,68,54,54,43,110,83,105,104,0,200,201,182,181,62,62,83,83,43,89,88,109,75,0,199,202,192,143,68,67,87,54,43,80,111,74,81,0,148,198,142,149,59,68,54,60,43,83,82,108,105,0,201,203,190,182,62,61,86,83,43,85,110,104,86,0,154,200,181,155,64,62,83,65,42,108,82,84,0,190,203,204,86,61,63,42,81,76,79,0,149,205,150,60,55,58,42,109,88,78,0,192,202,206,87,67,57,42,86,102,87,0,155,207,156,65,81,66,42,108,84,101,0,190,204,191,86,63,80,43,81,106,94,76,0,149,184,186,205,60,84,73,55,42,109,78,77,0,192,206,193,87,57,56,43,107,103,102,86,0,187,189,207,155,85,82,81,65],
+
+ "bones" : [],
+
+ "skinIndices" : [],
+
+ "skinWeights" : [],
+
+ "animations" : []
+
+
+}
diff --git a/examples/canvas3d/plasmaeffects/doc/images/plasmaeffects-example.png b/examples/canvas3d/plasmaeffects/doc/images/plasmaeffects-example.png
new file mode 100644
index 0000000..2ba5d6b
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/doc/images/plasmaeffects-example.png
Binary files differ
diff --git a/examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc b/examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc
new file mode 100644
index 0000000..8124dde
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/doc/src/plasmaeffects.qdoc
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example plasmaeffects
+ \since QtCanvas3D 1.0
+ \title Plasma Effects Example
+ \ingroup qtcanvas3d-examples
+ \brief Apply oldsk00l plasma effects into a canvas
+
+ The Plasma Effects Example concentrates on showing how to use different shaders in Canvas3D.
+
+ For a more thorough look into the QML side see the \l {Textured Cube Example} and
+ for a more thorough look into the JavaScript side see the \l {Lit and Textured Cube Example}.
+
+ \image plasmaeffects-example.png
+
+ \section1 Initialization
+
+ During \c{initGL}'s shader initialization, we'll create two separate shader programs.
+
+ First for the cubes:
+
+ \snippet plasmaeffects/qml/plasmaeffects/plasmaeffects.js 0
+
+ Then for the background:
+
+ \snippet plasmaeffects/qml/plasmaeffects/plasmaeffects.js 1
+
+ We'll need to use them one by one to get the uniform locations:
+
+ \snippet plasmaeffects/qml/plasmaeffects/plasmaeffects.js 2
+ \dots 0
+ \snippet plasmaeffects/qml/plasmaeffects/plasmaeffects.js 3
+
+ \section1 Usage
+
+ To use the shaders, simply take the right one into use before drawing in \c{renderGL}:
+
+ \snippet plasmaeffects/qml/plasmaeffects/plasmaeffects.js 4
+ \dots 0
+ \snippet plasmaeffects/qml/plasmaeffects/plasmaeffects.js 5
+ */
diff --git a/examples/canvas3d/plasmaeffects/main.cpp b/examples/canvas3d/plasmaeffects/main.cpp
new file mode 100644
index 0000000..1051a8c
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtCore/QDir>
+#include <QtQuick/QQuickView>
+#include <QtQml/QQmlEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView viewer;
+
+ // The following are needed to make examples run without having to install the module
+ // in desktop environments.
+#ifdef Q_OS_WIN
+ QString extraImportPath(QStringLiteral("%1/../../../../%2"));
+#else
+ QString extraImportPath(QStringLiteral("%1/../../../%2"));
+#endif
+ viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
+ QString::fromLatin1("qml")));
+
+ viewer.setSource(QUrl("qrc:/qml/plasmaeffects/main.qml"));
+
+ viewer.setTitle(QStringLiteral("Olds00l Plasma"));
+ viewer.setResizeMode(QQuickView::SizeRootObjectToView);
+ viewer.show();
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/plasmaeffects/plasmaeffects.pro b/examples/canvas3d/plasmaeffects/plasmaeffects.pro
new file mode 100644
index 0000000..dde84d0
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/plasmaeffects.pro
@@ -0,0 +1,11 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCES += main.cpp
+
+OTHER_FILES += qml/plasmaeffects/* \
+ doc/src/* \
+ doc/images/*
+
+RESOURCES += plasmaeffects.qrc
diff --git a/examples/canvas3d/plasmaeffects/plasmaeffects.qrc b/examples/canvas3d/plasmaeffects/plasmaeffects.qrc
new file mode 100644
index 0000000..e602681
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/plasmaeffects.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/plasmaeffects/glMatrix-0.9.5.min.js</file>
+ <file>qml/plasmaeffects/main.qml</file>
+ <file>qml/plasmaeffects/plasmaeffects.js</file>
+ <file>qml/plasmaeffects/qtlogo_gray.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/glMatrix-0.9.5.min.js b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml
new file mode 100644
index 0000000..37a5f70
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/main.qml
@@ -0,0 +1,166 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtCanvas3D 1.0
+
+import "plasmaeffects.js" as GLCode
+
+Item {
+ id: mainview
+ width: 1280
+ height: 768
+ visible: true
+
+ Canvas3D {
+ id: canvas3d
+ anchors.fill:parent
+ imageLoader: textureImageLoader
+ focus: true
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ property double zRotAnim: 0
+ property bool isRunning: true
+
+ // Called by Canvas 3D once on Scene Graph render thread
+ // to allow one time initializations to happen
+ function initGL() {
+ GLCode.initGL(canvas3d, textureImageLoader);
+ }
+
+ // Called by Canvas 3D for every frame
+ // rendered on Scene Graph render thread
+ function renderGL() {
+ GLCode.renderGL(canvas3d);
+ }
+
+ Keys.onSpacePressed: {
+ canvas3d.isRunning = !canvas3d.isRunning
+ if (canvas3d.isRunning) {
+ objAnimationX.pause();
+ objAnimationY.pause();
+ objAnimationZ.pause();
+ } else {
+ objAnimationX.resume();
+ objAnimationY.resume();
+ objAnimationZ.resume();
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationX
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 0.0
+ to: 120.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 120.0
+ to: 0.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationY
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 0.0
+ to: 240.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 240.0
+ to: 0.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationZ
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: -100.0
+ to: 100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: 100.0
+ to: -100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ }
+ }
+
+ TextureImageLoader {
+ id: textureImageLoader
+
+ function imageLoaded(textureImage) {
+ if (canvas3d.logAllCalls)
+ console.log("Texture loaded, size "+textureImage.width+"x"+textureImage.height);
+ GLCode.textureLoaded(textureImage);
+ }
+
+ function imageLoadingError(textureImage) {
+ if (GLCode.textureLoadError !== undefined) {
+ GLCode.textureLoadError(textureImage);
+ }
+ console.log("Texture load FAILED, "+textureImage.errorString);
+ }
+ }
+}
diff --git a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js
new file mode 100644
index 0000000..4848de7
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/plasmaeffects.js
@@ -0,0 +1,549 @@
+Qt.include("glMatrix-0.9.5.min.js")
+
+var gl;
+var cubeTexture = 0;
+
+var cubeShaderProgram;
+var cubeAttribute_vertexPosition;
+var cubeAttribute_textureCoord;
+var cubeAttribute_vertexColor;
+var cubeUniform_time;
+var cubeUniform_pMatrix;
+var cubeUniform_mvMatrix;
+var cubeUniform_textureSampler;
+
+var cubeVertexPositionBuffer;
+var cubeVertexIndexBuffer;
+var cubeVertexColorBuffer;
+var cubeVerticesTextureCoordBuffer;
+
+var bkgShaderProgram;
+var bkgAttribute_vertexPosition;
+var bkgAttribute_textureCoord;
+var bkgUniform_time;
+
+var bkgVertexPositionBuffer;
+var bkgVerticesTextureCoordBuffer;
+
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+
+var startTime;
+var elapsedTime;
+var skipTime = 0;
+var pausedTime;
+var wasRunning = true;
+
+var canvas3d;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+function initGL(canvas, textureLoader) {
+ canvas3d = canvas;
+ log("*******************************************************************************************");
+ log("initGL ENTER...");
+
+ try {
+ startTime = Date.now();
+
+ // Get the OpenGL context object that represents the API we call
+ gl = canvas.getContext("canvas3d", {antialias:true, depth:true});
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.enable(gl.DEPTH_WRITE);
+ gl.depthMask(true);
+ gl.depthFunc(gl.LESS);
+
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+ gl.disable(gl.BLEND);
+
+ // Set viewport
+ gl.viewport(0, 0, canvas.width * canvas.devicePixelRatio,
+ canvas.height * canvas.devicePixelRatio);
+
+ // Initialize vertex and color buffers
+ initBuffers();
+
+ // Initialize the shader program
+ initShaders();
+
+ // Load the texture
+ textureLoader.loadImage("qrc:/qml/plasmaeffects/qtlogo_gray.png");
+
+ log("...initGL EXIT");
+ } catch(e) {
+ console.log("...initGL FAILURE!");
+ console.log(""+e);
+ console.log(""+e.message);
+ }
+ log("*******************************************************************************************");
+}
+
+function textureLoaded(textureImage) {
+ log("textureLoaded ENTER...")
+
+ if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture == 0) {
+ if (canvas3d.logAllCalls)
+ console.log(" processing "+textureImage.source);
+ cubeTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ }
+
+ log("...textureLoaded EXIT");
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function renderGL(canvas) {
+ if (canvas.isRunning) {
+ if (!wasRunning) {
+ wasRunning = true;
+ startTime += skipTime;
+ }
+ elapsedTime = Date.now() - startTime;
+ } else {
+ if (wasRunning) {
+ // First time renderGL hit when paused
+ wasRunning = false;
+ pausedTime = Date.now();
+ }
+ skipTime = Date.now() - pausedTime;
+ }
+
+ // Clear screen
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.clearDepth(1.0);
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // Set states for background drawing
+ gl.disable(gl.DEPTH_TEST);
+ gl.depthMask(false);
+ gl.disable(gl.DEPTH_WRITE);
+
+ //! [4]
+ // Draw background
+ gl.useProgram(bkgShaderProgram);
+
+ //! [4]
+
+ // Update time
+ gl.uniform1f(bkgUniform_time, elapsedTime / 1000.0);
+
+ // Draw the screen space rect
+ gl.bindBuffer(gl.ARRAY_BUFFER, bkgVertexPositionBuffer);
+ gl.enableVertexAttribArray(bkgAttribute_vertexPosition);
+ gl.vertexAttribPointer(bkgAttribute_vertexPosition, 2, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, bkgVerticesTextureCoordBuffer);
+ gl.enableVertexAttribArray(bkgAttribute_textureCoord);
+ gl.vertexAttribPointer(bkgAttribute_textureCoord, 2, gl.FLOAT, false, 0, 0);
+
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
+
+ gl.enable(gl.DEPTH_TEST);
+ gl.depthMask(true);
+ gl.enable(gl.DEPTH_WRITE);
+
+ //! [5]
+ // Draw cubes
+ gl.useProgram(cubeShaderProgram);
+ //! [5]
+
+ // Calculate the perspective projection
+ mat4.perspective(pMatrix, degToRad(45), canvas.width / canvas.height, 0.1, 100.0);
+ gl.uniformMatrix4fva(cubeUniform_pMatrix, false, pMatrix);
+
+ // Bind the correct buffers
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.enableVertexAttribArray(cubeAttribute_vertexPosition);
+ gl.vertexAttribPointer(cubeAttribute_vertexPosition, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ gl.enableVertexAttribArray(cubeAttribute_vertexColor);
+ gl.vertexAttribPointer(cubeAttribute_vertexColor, 4, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesTextureCoordBuffer);
+ gl.enableVertexAttribArray(cubeAttribute_textureCoord);
+ gl.vertexAttribPointer(cubeAttribute_textureCoord, 2, gl.FLOAT, false, 0, 0);
+
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+ gl.uniform1i(cubeUniform_textureSampler, 0);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+
+ // Update time
+ gl.uniform1f(cubeUniform_time, elapsedTime / 1000.0);
+
+ // Draw first cube
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [-(canvas.yRotAnim - 120.0) / 90.0,
+ -(canvas.xRotAnim - 60.0) / 40.0,
+ -25.0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotAnim) * degToRad(canvas.xRotAnim),
+ [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotAnim), [0, 0, 1]);
+
+ gl.uniformMatrix4fva(cubeUniform_mvMatrix, false, mvMatrix);
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+
+ // Draw first cube
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [-(canvas.xRotAnim - 60.0) / 30.0,
+ -(canvas.zRotAnim - 100.0) / 60.0,
+ -20.0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(10), [0, 1, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(30), [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotAnim), [0, 0, 1]);
+
+ gl.uniformMatrix4fva(cubeUniform_mvMatrix, false, mvMatrix);
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+
+ // Draw second cube
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [(canvas.xRotAnim - 60.0) / 30.0,
+ (canvas.zRotAnim - 100.0) / 60.0,
+ -15.0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotAnim), [0, 1, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotAnim), [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotAnim), [0, 0, 1]);
+
+ gl.uniformMatrix4fva(cubeUniform_mvMatrix, false, mvMatrix);
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+
+ // Draw third cube
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [(canvas.yRotAnim - 120.0) / 120.0,
+ (canvas.xRotAnim - 60.0) / 60.0,
+ -10.0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotAnim) * degToRad(canvas.xRotAnim),
+ [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotAnim), [0, 0, 1]);
+
+ gl.uniformMatrix4fva(cubeUniform_mvMatrix, false, mvMatrix);
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+}
+
+function initBuffers()
+{
+ log(" initBuffers ENTER...");
+
+ cubeVertexPositionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([// 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);
+
+ cubeVertexIndexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ Arrays.newUint16Array([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);
+
+ var colors = [[0.0, 1.0, 1.0, 1.0], // Front face: cyan
+ [1.0, 0.0, 0.0, 1.0], // Back face: red
+ [0.0, 1.0, 0.0, 1.0], // Top face: green
+ [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
+ [1.0, 1.0, 0.0, 1.0], // Right face: yellow
+ [1.0, 0.0, 1.0, 1.0]]; // Left face: purple
+
+ var generatedColors = [];
+ for (var j = 0; j < 6; j++) {
+ var c = colors[j];
+
+ for (var i = 0; i < 4; i++) {
+ generatedColors = generatedColors.concat(c);
+ }
+ }
+
+ cubeVertexColorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array(generatedColors),
+ gl.STATIC_DRAW);
+
+ cubeVerticesTextureCoordBuffer = gl.createBuffer();
+ 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,
+ Arrays.newFloat32Array(textureCoordinates),
+ gl.STATIC_DRAW);
+
+ bkgVertexPositionBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, bkgVertexPositionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([-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);
+
+ bkgVerticesTextureCoordBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, bkgVerticesTextureCoordBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([0.0, 0.0,
+ 1.0, 0.0,
+ 0.0, 1.0,
+ 0.0, 1.0,
+ 1.0, 0.0,
+ 1.0, 1.0]),
+ gl.STATIC_DRAW);
+ log(" ...initBuffers EXIT")
+}
+
+function initShaders()
+{
+ // CUBE SHADER
+
+ log(" initShaders ENTER...")
+ var cubeVertexShader = getShader(gl,
+ "attribute highp vec3 aVertexPosition;
+ attribute mediump vec4 aVertexColor;
+ attribute highp vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying mediump vec4 vColor;
+ varying highp vec2 vTextureCoord;
+ varying highp vec4 vPos;
+
+ void main(void) {
+ vPos = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vColor = aVertexColor;
+ vTextureCoord = aTextureCoord;
+ }", gl.VERTEX_SHADER);
+ var cubeFragmentShader = getShader(gl,
+ "#define PI 3.1415926535897932384626433832795
+ uniform highp float uTime;
+
+ varying mediump vec4 vColor;
+ varying highp vec2 vTextureCoord;
+ varying highp vec4 vPos;
+
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ highp vec4 volScale = vec4(3.0, 3.0, 3.0, 2.0);
+ highp vec4 volume = vPos * volScale - volScale/2.0;
+
+ highp vec2 scaling = vec2(20.0,20.0);
+ highp vec2 coord = vTextureCoord * scaling - scaling/2.0;
+ highp float value = sin(volume.x+coord.x+uTime);
+ value += sin((volume.y+coord.y+uTime)/1.5);
+ value += sin((volume.z+coord.y+uTime)/1.5);
+
+ coord += scaling/2.0 * vec2(sin(uTime/3.0), cos(uTime/2.0));
+ value += sin(sqrt(coord.x*coord.x + coord.y*coord.y + 1.0) + uTime);
+ value = value/2.0;
+ value = sin(PI*value);
+ highp vec4 col = vec4(value, value, value, 1.0);
+ highp vec4 textureColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ gl_FragColor = vec4(col.rgb * vColor.rgb * textureColor.rgb, textureColor.a);
+ }", gl.FRAGMENT_SHADER);
+
+ //! [0]
+ cubeShaderProgram = gl.createProgram();
+ gl.attachShader(cubeShaderProgram, cubeVertexShader);
+ gl.attachShader(cubeShaderProgram, cubeFragmentShader);
+ gl.linkProgram(cubeShaderProgram);
+ //! [0]
+
+ if (!gl.getProgramParameter(cubeShaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialise shaders");
+ console.log(gl.getProgramInfoLog(cubeShaderProgram));
+ }
+
+ //! [2]
+ gl.useProgram(cubeShaderProgram);
+
+ cubeAttribute_vertexPosition = gl.getAttribLocation(cubeShaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(cubeAttribute_vertexPosition);
+ cubeAttribute_vertexColor = gl.getAttribLocation(cubeShaderProgram, "aVertexColor");
+ gl.enableVertexAttribArray(cubeAttribute_vertexColor);
+ cubeAttribute_textureCoord = gl.getAttribLocation(cubeShaderProgram, "aTextureCoord");
+ gl.enableVertexAttribArray(cubeAttribute_textureCoord);
+
+ cubeUniform_time = gl.getUniformLocation(cubeShaderProgram, "uTime");
+ cubeUniform_pMatrix = gl.getUniformLocation(cubeShaderProgram, "uPMatrix");
+ cubeUniform_mvMatrix = gl.getUniformLocation(cubeShaderProgram, "uMVMatrix");
+ cubeUniform_textureSampler = gl.getUniformLocation(cubeShaderProgram, "uSampler")
+
+ //! [2]
+ // BACKGROUND SHADER
+ var bkgVertexShader = getShader(gl,
+ "attribute highp vec2 aVertexPosition;
+ attribute highp vec2 aTextureCoord;
+
+ varying highp vec2 vTextureCoord;
+
+ void main(void) {
+ gl_Position = vec4(aVertexPosition, 0.0, 1.0);
+ vTextureCoord = aTextureCoord;
+ }", gl.VERTEX_SHADER);
+ var bkgFragmentShader = getShader(gl,
+ "uniform highp float uTime;
+ varying highp vec2 vTextureCoord;
+
+ void main(void) {
+ highp vec2 position = vTextureCoord.xy;
+
+ highp float centerX = position.x - 0.5 + sin(uTime / 2.0) * 0.1;
+ highp float centerY = position.y - 0.5 + cos(uTime / 2.0) * 0.1;
+
+ highp float x = log(sqrt(centerX*centerX + centerY*centerY));
+ highp float y = atan(centerX, centerY);
+
+ highp float color = cos(x * cos(uTime / 30.0) * 80.0) + cos(x * cos(uTime / 30.0) * 10.0) +
+ cos(y * cos(uTime / 20.0) * 40.0) + cos(y * sin(uTime / 50.0) * 40.0);
+ color *= 0.5;
+
+ gl_FragColor = vec4(color * sin(uTime / 10.0) * 0.5, color * (1.0 - sin(uTime / 10.0)) * 0.5, sin( color + uTime / 3.0 ) * 0.3, 1.0 );
+ }", gl.FRAGMENT_SHADER);
+ var bkgFragmentShaderBW = getShader(gl,
+ "uniform highp float uTime;
+ varying highp vec2 vTextureCoord;
+
+ void main(void) {
+ highp vec2 position = vTextureCoord.xy;
+
+ highp float centerX = position.x - 0.5 + sin(uTime / 3.0) * 0.1;
+ highp float centerY = position.y - 0.5 + cos(uTime / 3.0) * 0.1;
+
+ highp float x = log(sqrt(centerX*centerX + centerY*centerY));
+ highp float y = atan(centerX, centerY);
+
+ highp float color = cos(x * cos(uTime / 30.0) * 80.0) + cos(x * cos(uTime / 30.0) * 10.0);
+ color += cos(y * cos(uTime / 20.0) * 40.0) + cos(y * sin(uTime / 50.0) * 40.0);
+ color *= 0.2;
+ gl_FragColor = vec4(color, color, color, 1.0 );
+ }", gl.FRAGMENT_SHADER);
+
+ //! [1]
+ bkgShaderProgram = gl.createProgram();
+ gl.attachShader(bkgShaderProgram, bkgVertexShader);
+ gl.attachShader(bkgShaderProgram, bkgFragmentShader);
+ gl.linkProgram(bkgShaderProgram);
+ //! [1]
+
+ if (!gl.getProgramParameter(bkgShaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialize background shader");
+ console.log(gl.getProgramInfoLog(bkgShaderProgram));
+ }
+ //! [3]
+
+ gl.useProgram(bkgShaderProgram);
+
+ bkgAttribute_vertexPosition = gl.getAttribLocation(bkgShaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(bkgAttribute_vertexPosition);
+ bkgAttribute_textureCoord = gl.getAttribLocation(bkgShaderProgram, "aTextureCoord");
+ gl.enableVertexAttribArray(bkgAttribute_textureCoord);
+
+ bkgUniform_time = gl.getUniformLocation(bkgShaderProgram, "uTime");
+ gl.bindTexture(gl.TEXTURE_2D, 0);
+ //! [3]
+
+ log(" ...initShaders EXIT");
+}
+
+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;
+}
diff --git a/examples/canvas3d/plasmaeffects/qml/plasmaeffects/qtlogo_gray.png b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/qtlogo_gray.png
new file mode 100644
index 0000000..c865c0b
--- /dev/null
+++ b/examples/canvas3d/plasmaeffects/qml/plasmaeffects/qtlogo_gray.png
Binary files differ
diff --git a/examples/canvas3d/pureqml/cube.js b/examples/canvas3d/pureqml/cube.js
new file mode 100644
index 0000000..eaeb688
--- /dev/null
+++ b/examples/canvas3d/pureqml/cube.js
@@ -0,0 +1,203 @@
+Qt.include("glMatrix-0.9.5.min.js")
+
+//
+// Draws a cube that has different colors assigned to the vertices.
+// Each face of the cube has the linear interpolation of the corner colors.
+//
+
+var gl;
+var vertexPositionAttrLoc;
+var shaderProgram;
+var cubeVertexPositionBuffer;
+var cubeVertexIndexBuffer;
+var cubeVertexColorBuffer;
+var vertexShader;
+var fragmentShader;
+var vertexColorAttrLoc;
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+var pMatrixUniformLoc;
+var mvMatrixUniformLoc;
+
+var canvas3d;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+function initGL(canvas) {
+ canvas3d = canvas
+ try {
+ // Get the context object that represents the 3D API
+ gl = canvas3d.getContext("canvas3d", {depth:true, antialias:true});
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.depthMask(true);
+
+ log("canvas width:"+canvas.width+" height:"+canvas.height+" devicePixelRatio:"+canvas.devicePixelRatio);
+ gl.viewport(0, 0, canvas.width * canvas.devicePixelRatio, canvas.height * canvas.devicePixelRatio);
+
+ // Initialize vertex and color buffers
+ initBuffers();
+
+ // Initialize the shader program
+ initShaders();
+ } catch(e) {
+ console.log("initGL FAILURE!");
+ console.log(""+e);
+ console.log(""+e.message);
+ }
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function renderGL() {
+ log("Render Enter *******")
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ mat4.perspective(pMatrix, degToRad(45), canvas3d.width / canvas3d.height, 0.1, 100.0);
+ mat4.identity(mvMatrix);
+ mat4.translate(mvMatrix, mvMatrix, [0.0, 0.0, -5.0]);
+ //! [0]
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas3d.xRotAnim), [0, 1, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas3d.yRotAnim), [1, 0, 0]);
+ //! [0]
+
+ gl.useProgram(shaderProgram);
+
+ gl.uniformMatrix4fva(pMatrixUniformLoc, false, pMatrix);
+ gl.uniformMatrix4fva(mvMatrixUniformLoc, false, mvMatrix);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.enableVertexAttribArray(vertexPositionAttrLoc);
+ gl.vertexAttribPointer(vertexPositionAttrLoc, 3, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ gl.enableVertexAttribArray(vertexColorAttrLoc);
+ gl.vertexAttribPointer(vertexColorAttrLoc, 4, gl.FLOAT, false, 0, 0);
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+ log("Render Exit *******")
+}
+
+function initBuffers() {
+ // Create a cubeVertexPositionBuffer and put a single clipspace rectangle in
+ // it (2 triangles)
+ cubeVertexPositionBuffer = gl.createBuffer();
+ cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([ // front
+ -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
+ -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);
+
+ cubeVertexIndexBuffer = gl.createBuffer();
+ cubeVertexIndexBuffer.name = "cubeVertexIndexBuffer";
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ Arrays.newUint16Array([// front
+ 0, 1, 2,
+ 2, 3, 0,
+ // top
+ 3, 2, 6,
+ 6, 7, 3,
+ // back
+ 7, 6, 5,
+ 5, 4, 7,
+ // bottom
+ 4, 5, 1,
+ 1, 0, 4,
+ // left
+ 4, 0, 3,
+ 3, 7, 4,
+ // right
+ 1, 5, 6,
+ 6, 2, 1]),
+ gl.STATIC_DRAW);
+
+ cubeVertexColorBuffer = gl.createBuffer();
+ cubeVertexColorBuffer.name = "cubeVertexColorBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([// front
+ 0.000, 1.000, 0.000,
+ 0.000, 0.000, 1.000,
+ 1.000, 1.000, 1.000,
+ 1.000, 0.000, 0.000,
+ // back
+ 1.000, 0.000, 1.000,
+ 1.000, 1.000, 0.000,
+ 0.000, 0.000, 0.000,
+ 0.000, 1.000, 1.000]),
+ gl.STATIC_DRAW);
+}
+
+function initShaders() {
+ log(" Initializing shaders...");
+
+ vertexShader = getShader(gl, "attribute highp vec3 aVertexPosition; \
+ attribute highp vec4 aVertexColor; \
+ uniform highp mat4 uMVMatrix; \
+ uniform highp mat4 uPMatrix; \
+ varying highp vec4 vColor; \
+ void main(void) { \
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0); \
+ vColor = aVertexColor; \
+ }", gl.VERTEX_SHADER);
+ fragmentShader = getShader(gl, "varying highp vec4 vColor; \
+ void main(void) { \
+ gl_FragColor = vColor; \
+ }", gl.FRAGMENT_SHADER);
+
+ shaderProgram = gl.createProgram();
+ shaderProgram.name = "shaderProgram";
+ 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.
+ vertexPositionAttrLoc = gl.getAttribLocation(shaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttrLoc);
+ vertexColorAttrLoc = gl.getAttribLocation(shaderProgram, "aVertexColor");
+ gl.enableVertexAttribArray(vertexColorAttrLoc);
+
+ pMatrixUniformLoc = gl.getUniformLocation(shaderProgram, "uPMatrix");
+ pMatrixUniformLoc.name = "pMatrixUniformLoc";
+ mvMatrixUniformLoc = gl.getUniformLocation(shaderProgram, "uMVMatrix");
+ mvMatrixUniformLoc.name = "mvMatrixUniformLoc";
+ log(" ...done")
+}
+
+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;
+}
diff --git a/examples/canvas3d/pureqml/doc/images/pureqml-example.png b/examples/canvas3d/pureqml/doc/images/pureqml-example.png
new file mode 100644
index 0000000..9e8fc58
--- /dev/null
+++ b/examples/canvas3d/pureqml/doc/images/pureqml-example.png
Binary files differ
diff --git a/examples/canvas3d/pureqml/doc/src/pureqml.qdoc b/examples/canvas3d/pureqml/doc/src/pureqml.qdoc
new file mode 100644
index 0000000..c7ae423
--- /dev/null
+++ b/examples/canvas3d/pureqml/doc/src/pureqml.qdoc
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example pureqml
+ \since QtCanvas3D 1.0
+ \title Pure QML Example
+ \ingroup qtcanvas3d-examples
+ \brief A pure QML application project
+
+ The Pure QML Example demonstrates the use of Canvas3D in a pure Qt Quick UI project, that
+ has no compilable parts at all. It also briefly demonstrates how to interact with the object
+ in Canvas3D using a MouseArea.
+
+ \image pureqml-example.png
+
+ \section1 Pure QML
+
+ Our main qml file is similar to a normal Qt Quick Application. The main difference is that
+ there is no \c{.pro} file and nothing to compile. We create the Canvas3D the normal way:
+
+ \snippet pureqml/pureqml.qml 0
+
+ \section1 MouseArea Interaction
+
+ We added properties for x and y rotations into the Canvas3D:
+
+ \snippet pureqml/pureqml.qml 1
+
+ Then we add a \c MouseArea that fills the whole window, and connect the Canvas3D properties
+ to \c mouseX and \c mouseY on their correspodinh onChanged functions:
+
+ \snippet pureqml/pureqml.qml 2
+
+ An finally, we just use the Canvas3D properties on the JavaScript side directly for matrix
+ rotations:
+
+ \snippet pureqml/cube.js 0
+
+ */
diff --git a/examples/canvas3d/pureqml/glMatrix-0.9.5.min.js b/examples/canvas3d/pureqml/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/pureqml/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/pureqml/pureqml.qml b/examples/canvas3d/pureqml/pureqml.qml
new file mode 100644
index 0000000..1295a64
--- /dev/null
+++ b/examples/canvas3d/pureqml/pureqml.qml
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.2
+import QtCanvas3D 1.0
+
+import "cube.js" as GLCode
+
+Item {
+ id: mainview
+ width: 600
+ height: 600
+
+ //! [2]
+ MouseArea {
+ anchors.fill: parent
+ onMouseXChanged:
+ canvas3d.xRotAnim = mouseX / 3
+ onMouseYChanged:
+ canvas3d.yRotAnim = mouseY / 3
+ }
+ //! [2]
+
+ //! [0]
+ Canvas3D {
+ id: canvas3d
+ anchors.fill: parent
+ //! [1]
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ //! [1]
+ function initGL() {
+ GLCode.initGL(canvas3d);
+ }
+ function renderGL() {
+ GLCode.renderGL();
+ }
+ }
+ //! [0]
+}
diff --git a/examples/canvas3d/pureqml/pureqml.qmlproject b/examples/canvas3d/pureqml/pureqml.qmlproject
new file mode 100644
index 0000000..45ddaaf
--- /dev/null
+++ b/examples/canvas3d/pureqml/pureqml.qmlproject
@@ -0,0 +1,20 @@
+/* File generated by Qt Creator, version 2.7.0 */
+
+import QmlProject 1.1
+
+Project {
+ mainFile: "pureqml.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+ JavaScriptFiles {
+ directory: "."
+ }
+ ImageFiles {
+ directory: "."
+ }
+ /* List of plugin directories passed to QML runtime */
+ // importPaths: [ "../exampleplugin" ]
+}
diff --git a/examples/canvas3d/textureandlight/doc/images/textureandlight-example.png b/examples/canvas3d/textureandlight/doc/images/textureandlight-example.png
new file mode 100644
index 0000000..cd63f9e
--- /dev/null
+++ b/examples/canvas3d/textureandlight/doc/images/textureandlight-example.png
Binary files differ
diff --git a/examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc b/examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc
new file mode 100644
index 0000000..495242a
--- /dev/null
+++ b/examples/canvas3d/textureandlight/doc/src/textureandlight.qdoc
@@ -0,0 +1,129 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example textureandlight
+ \since QtCanvas3D 1.0
+ \title Lit and Textured Cube Example
+ \ingroup qtcanvas3d-examples
+ \brief A simple cube with texturing and lighting
+
+ The Lit and Textured Cube differs only a little from \l {Textured Cube Example} on QML side, so
+ in this example we'll focus a bit more on the js object.
+
+ \image textureandlight-example.png
+
+ \section1 Matrix Library
+
+ First we'll include a fast matrix library. Using this makes it a lot easier to
+ handle all matrix transformations:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 0
+
+ \section1 initGL function
+
+ Let's take a closer look at the \c initGL function. It is called by Canvas3D once the render
+ node is ready.
+
+ First of all, we'll need to get Context3D from our Canvas3D. We want a context that supports
+ depth buffer and antialising:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 1
+
+ Then we'll initialize the OpenGL state for the context:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 2
+
+ Next, let's take a look into shader initialization in \c initShaders function, which we call
+ in the \c{initGL}. First of all we'll define the vertex shader:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 3
+
+ We'll follow that up by defining fragment shader:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 4
+
+ Then we'll need to create the shader program (Program3D), attach the shaders to it, and then
+ link and use the program:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 5
+
+ And finally look up and store the vertex attributes and uniform locations:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 6
+
+ After initializing the shader program, we'll set up the vertex buffer in \c initBuffers
+ function. Let's look at the vertex index buffer creation as an example:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 7
+
+ As can be seen, first we create the buffer, then bind it and finally insert the data into it.
+ We won't take a look at the other buffers, as they are all handled in a similar fashion.
+
+ After that, as the final step in \c{initGL}, we'll request a texture from TextureImageLoader
+ passed to \c initGL as a parameter. Once the texture image is successfully loaded, we create
+ the actual texture in \c textureLoaded function called by the TextureImageLoader:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 8
+
+ \section1 renderGL function
+
+ \c renderGL is called by Canvas3D whenever it is ready to receive a new frame. Let's go through
+ the steps that are done in each render cycle.
+
+ First we check if canvas has been resized or if pixel ratio has changed, and update the
+ projection matrix if necessary:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 9
+
+ Then we'll clear the render area using the clear color set in \c{initGL}:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 10
+
+ Next we'll reset the model view matrix and apply translation and rotations:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 11
+
+ As we have a lit cube, we'll invert and transpose the model view matrix to be used for lighting
+ calculations:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 12
+
+ And finally we'll draw the cube:
+
+ \snippet textureandlight/qml/textureandlight/textureandlight.js 13
+
+ */
diff --git a/examples/canvas3d/textureandlight/main.cpp b/examples/canvas3d/textureandlight/main.cpp
new file mode 100644
index 0000000..400cb93
--- /dev/null
+++ b/examples/canvas3d/textureandlight/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtCore/QDir>
+#include <QtQuick/QQuickView>
+#include <QtQml/QQmlEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView viewer;
+
+ // The following are needed to make examples run without having to install the module
+ // in desktop environments.
+#ifdef Q_OS_WIN
+ QString extraImportPath(QStringLiteral("%1/../../../../%2"));
+#else
+ QString extraImportPath(QStringLiteral("%1/../../../%2"));
+#endif
+ viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
+ QString::fromLatin1("qml")));
+
+ viewer.setSource(QUrl("qrc:/qml/textureandlight/main.qml"));
+
+ viewer.setTitle(QStringLiteral("Textured and Lit Cube"));
+ viewer.setResizeMode(QQuickView::SizeRootObjectToView);
+ viewer.show();
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/textureandlight/qml/textureandlight/glMatrix-0.9.5.min.js b/examples/canvas3d/textureandlight/qml/textureandlight/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/textureandlight/qml/textureandlight/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/textureandlight/qml/textureandlight/main.qml b/examples/canvas3d/textureandlight/qml/textureandlight/main.qml
new file mode 100644
index 0000000..3c9c2b7
--- /dev/null
+++ b/examples/canvas3d/textureandlight/qml/textureandlight/main.qml
@@ -0,0 +1,172 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtCanvas3D 1.0
+
+import "textureandlight.js" as GLCode // Textured cube with directional light
+
+Item {
+ id: mainview
+ width: 1280
+ height: 768
+ visible: true
+
+ Canvas3D {
+ id: canvas3d
+ anchors.fill:parent
+ imageLoader: textureImageLoader
+ focus: true
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ property double zRotAnim: 0
+ property bool isRunning: true
+
+ // Called by Canvas 3D once on Scene Graph render thread
+ // to allow one time initializations to happen
+ function initGL() {
+ GLCode.initGL(canvas3d, textureImageLoader);
+ }
+
+ // Called by Canvas 3D for every frame
+ // rendered on Scene Graph render thread
+ function renderGL() {
+ GLCode.renderGL(canvas3d);
+ }
+
+ Keys.onSpacePressed: {
+ canvas3d.isRunning = !canvas3d.isRunning
+ if (canvas3d.isRunning) {
+ objAnimationX.pause();
+ objAnimationY.pause();
+ objAnimationZ.pause();
+ } else {
+ objAnimationX.resume();
+ objAnimationY.resume();
+ objAnimationZ.resume();
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationX
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 0.0
+ to: 120.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 120.0
+ to: 0.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationY
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 0.0
+ to: 240.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 240.0
+ to: 0.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationZ
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: -100.0
+ to: 100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: 100.0
+ to: -100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ }
+ }
+
+ TextureImageLoader {
+ id: textureImageLoader
+
+ function loadTexture(file) {
+ if (canvas3d.logAllCalls)
+ console.log("TextureImageLoader.loadTexture(qrc:/qml/textureandlight/"+file+")")
+ return textureImageLoader.loadImage("qrc:/qml/textureandlight/"+file);
+ }
+
+ function imageLoaded(textureImage) {
+ if (canvas3d.logAllCalls)
+ console.log("Texture loaded, size "+textureImage.width+"x"+textureImage.height);
+ GLCode.textureLoaded(textureImage);
+ }
+
+ function imageLoadingError(textureImage) {
+ if (GLCode.textureLoadError !== undefined) {
+ GLCode.textureLoadError(textureImage);
+ }
+ console.log("Texture load FAILED, "+textureImage.errorString);
+ }
+ }
+}
diff --git a/examples/canvas3d/textureandlight/qml/textureandlight/qtlogo.png b/examples/canvas3d/textureandlight/qml/textureandlight/qtlogo.png
new file mode 100644
index 0000000..ed609ef
--- /dev/null
+++ b/examples/canvas3d/textureandlight/qml/textureandlight/qtlogo.png
Binary files differ
diff --git a/examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js b/examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js
new file mode 100644
index 0000000..24f4abc
--- /dev/null
+++ b/examples/canvas3d/textureandlight/qml/textureandlight/textureandlight.js
@@ -0,0 +1,390 @@
+//! [0]
+Qt.include("glMatrix-0.9.5.min.js")
+//! [0]
+
+//
+// Draws a cube that has the Qt logo as decal texture on each face.
+// A simple per vertex lighting equation is used to emulate light landing on the rotating cube.
+//
+
+var gl;
+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 width = 0;
+var height = 0;
+var canvas3d;
+
+function initGL(canvas, textureLoader) {
+ canvas3d = canvas;
+ //! [1]
+ // Get the OpenGL context object that represents the API we call
+ gl = canvas.getContext("canvas3d", {depth:true, antialias:true});
+ //! [1]
+
+ //! [2]
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.depthFunc(gl.DEPTH_LESS);
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.clearDepth(1.0);
+ //! [2]
+
+ // Set viewport
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ // Initialize the shader program
+ initShaders();
+
+ // Initialize vertex and color buffers
+ initBuffers();
+
+ // Load the texture
+ textureLoader.loadTexture("qtlogo.png");
+}
+
+//! [8]
+function textureLoaded(textureImage) {
+ if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture == 0) {
+ if (canvas3d.logAllCalls)
+ console.log(" processing "+textureImage.source);
+ // Create the Texture3D object
+ cubeTexture = gl.createTexture();
+ // Bind it
+ gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+ // Set the properties
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // pixels
+ // Set texture filtering parameters
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
+ // Generate mipmap
+ gl.generateMipmap(gl.TEXTURE_2D);
+ }
+}
+//! [8]
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+function renderGL(canvas) {
+ //! [9]
+ // Check for resize
+ var pixelRatio = canvas.devicePixelRatio;
+ var currentWidth = canvas.width * pixelRatio;
+ var currentHeight = canvas.height * pixelRatio;
+ if (currentWidth !== width || currentHeight !== height ) {
+ width = currentWidth;
+ height = currentHeight;
+ mat4.perspective(pMatrix, degToRad(45), width / height, 0.1, 500.0);
+ gl.uniformMatrix4fva(pMatrixUniform, false, pMatrix);
+ }
+ //! [9]
+
+ //! [10]
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+ //! [10]
+
+ //! [11]
+ 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]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotAnim), [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotAnim), [0, 0, 1]);
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+ //! [11]
+
+ //! [12]
+ mat4.invert(nMatrix, mvMatrix);
+ mat4.transpose(nMatrix, nMatrix);
+ gl.uniformMatrix4fva(nUniform, false, nMatrix);
+ //! [12]
+
+ //! [13]
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+ //! [13]
+}
+
+function initBuffers()
+{
+ var cubeVertexPositionBuffer = gl.createBuffer();
+ cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([// 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.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+
+ if (canvas3d.logAllCalls)
+ console.log(" cubeVertexIndexBuffer");
+ //! [7]
+ var cubeVertexIndexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ Arrays.newUint16Array([
+ 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);
+ //! [7]
+
+ var cubeVertexColorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ var colors = [
+ [0.0, 1.0, 1.0, 1.0], // Front face: white
+ [1.0, 0.0, 0.0, 1.0], // Back face: red
+ [0.0, 1.0, 0.0, 1.0], // Top face: green
+ [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
+ [1.0, 1.0, 0.0, 1.0], // Right face: yellow
+ [1.0, 0.0, 1.0, 1.0] // Left face: purple
+ ];
+ var generatedColors = [];
+ for (var j = 0; j < 6; j++) {
+ var c = colors[j];
+
+ for (var i = 0; i < 4; i++) {
+ generatedColors = generatedColors.concat(c);
+ }
+ }
+ gl.bufferData(gl.ARRAY_BUFFER, Arrays.newFloat32Array(generatedColors), gl.STATIC_DRAW);
+ gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ var cubeVerticesTextureCoordBuffer = gl.createBuffer();
+ 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, Arrays.newFloat32Array(textureCoordinates),
+ gl.STATIC_DRAW);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+
+ var cubeVerticesNormalBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVerticesNormalBuffer);
+ gl.bufferData(gl.ARRAY_BUFFER, Arrays.newFloat32Array([
+ // 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.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
+}
+
+function initShaders()
+{
+ //! [3]
+ var vertexShader = getShader(gl,
+ "attribute highp vec3 aVertexNormal;
+ attribute highp vec3 aVertexPosition;
+ attribute mediump vec4 aVertexColor;
+ 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);
+ vColor = aVertexColor;
+ 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);
+ //! [3]
+ //! [4]
+ var fragmentShader = getShader(gl,
+ "varying mediump vec4 vColor;
+ varying highp vec2 vTextureCoord;
+ varying highp vec3 vLighting;
+
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ mediump vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ mediump vec3 blendColor = mix(vColor.rgb, texelColor.rgb, texelColor.a);
+ gl_FragColor = vec4(blendColor * vLighting, 1.0);
+ }", gl.FRAGMENT_SHADER);
+ //! [4]
+ //! [5]
+ // Create the Program3D for shader
+ var shaderProgram = gl.createProgram();
+
+ // Attach the shader sources to the shader program
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+
+ // Link the program
+ gl.linkProgram(shaderProgram);
+
+ // Check the linking status
+ if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+ console.log("Could not initialise shaders");
+ console.log(gl.getProgramInfoLog(shaderProgram));
+ }
+
+ // Take the shader program into use
+ gl.useProgram(shaderProgram);
+ //! [5]
+
+ //! [6]
+ // Look up where the vertex data needs to go
+ vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
+ gl.enableVertexAttribArray(vertexPositionAttribute);
+ vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
+ gl.enableVertexAttribArray(vertexColorAttribute);
+ textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ vertexNormalAttribute = gl.getAttribLocation(shaderProgram, "aVertexNormal");
+ gl.enableVertexAttribArray(vertexNormalAttribute);
+
+ // Get the uniform locations
+ pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
+ mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
+ nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix");
+
+ // Setup texture sampler uniform
+ var textureSamplerUniform = gl.getUniformLocation(shaderProgram, "uSampler")
+ gl.activeTexture(gl.TEXTURE0);
+ gl.uniform1i(textureSamplerUniform, 0);
+ gl.bindTexture(gl.TEXTURE_2D, 0);
+ //! [6]
+}
+
+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;
+}
diff --git a/examples/canvas3d/textureandlight/textureandlight.pro b/examples/canvas3d/textureandlight/textureandlight.pro
new file mode 100644
index 0000000..d38bc69
--- /dev/null
+++ b/examples/canvas3d/textureandlight/textureandlight.pro
@@ -0,0 +1,11 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCES += main.cpp
+
+OTHER_FILES += qml/textureandlight/* \
+ doc/src/* \
+ doc/images/*
+
+RESOURCES += textureandlight.qrc
diff --git a/examples/canvas3d/textureandlight/textureandlight.qrc b/examples/canvas3d/textureandlight/textureandlight.qrc
new file mode 100644
index 0000000..5c84809
--- /dev/null
+++ b/examples/canvas3d/textureandlight/textureandlight.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/textureandlight/glMatrix-0.9.5.min.js</file>
+ <file>qml/textureandlight/main.qml</file>
+ <file>qml/textureandlight/textureandlight.js</file>
+ <file>qml/textureandlight/qtlogo.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/canvas3d/texturedcube/doc/images/texturedcube-example.png b/examples/canvas3d/texturedcube/doc/images/texturedcube-example.png
new file mode 100644
index 0000000..1723f92
--- /dev/null
+++ b/examples/canvas3d/texturedcube/doc/images/texturedcube-example.png
Binary files differ
diff --git a/examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc b/examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc
new file mode 100644
index 0000000..560304d
--- /dev/null
+++ b/examples/canvas3d/texturedcube/doc/src/texturedcube.qdoc
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example texturedcube
+ \since QtCanvas3D 1.0
+ \title Textured Cube Example
+ \ingroup qtcanvas3d-examples
+ \brief A simple textured cube
+
+ The Textured Cube example shows how to create a simple Canvas3D displaying a single moving
+ textured cube.
+
+ \image texturedcube-example.png
+
+ \section1 Creating Canvas3D
+
+ We'll add a Canvas3D component into the main component:
+
+ \snippet texturedcube/qml/texturedcube/main.qml 0
+ \dots
+
+ Inside it, we create the \c initGL and \c renderGL functions to forward the initialization
+ and rendering calls to the js object:
+
+ \snippet texturedcube/qml/texturedcube/main.qml 1
+
+ As we want to add a texture in the js object, we need to set the \c imageLoader property in
+ the canvas:
+
+ \snippet texturedcube/qml/texturedcube/main.qml 2
+
+ The TextureImageLoader itself is outside the Canvas3D and handles texture load successes and
+ possible errors:
+
+ \snippet texturedcube/qml/texturedcube/main.qml 3
+
+ \section1 The JavaScript Object
+
+ First we import the js object in the QML:
+
+ \snippet texturedcube/qml/texturedcube/main.qml 4
+
+ In the \c initGL function of the js object, we initialize the OpenGL state:
+
+ \snippet texturedcube/qml/texturedcube/texturedcube.js 0
+
+ The \c renderGL function does the actual drawing into the canvas:
+
+ \snippet texturedcube/qml/texturedcube/texturedcube.js 1
+
+ \section1 The Animation
+
+ Animating the cube is done simply by adding a \c SequantialAnimation for different Canvas3D
+ properties. Here's one as an example, affecting the x rotation of the cube:
+
+ \snippet texturedcube/qml/texturedcube/main.qml 5
+
+ */
diff --git a/examples/canvas3d/texturedcube/main.cpp b/examples/canvas3d/texturedcube/main.cpp
new file mode 100644
index 0000000..f34fe5b
--- /dev/null
+++ b/examples/canvas3d/texturedcube/main.cpp
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui/QGuiApplication>
+#include <QtCore/QDir>
+#include <QtQuick/QQuickView>
+#include <QtQml/QQmlEngine>
+
+int main(int argc, char *argv[])
+{
+ QGuiApplication app(argc, argv);
+
+ QQuickView viewer;
+
+ // The following are needed to make examples run without having to install the module
+ // in desktop environments.
+#ifdef Q_OS_WIN
+ QString extraImportPath(QStringLiteral("%1/../../../../%2"));
+#else
+ QString extraImportPath(QStringLiteral("%1/../../../%2"));
+#endif
+ viewer.engine()->addImportPath(extraImportPath.arg(QGuiApplication::applicationDirPath(),
+ QString::fromLatin1("qml")));
+
+ viewer.setSource(QUrl("qrc:/qml/texturedcube/main.qml"));
+
+ viewer.setTitle(QStringLiteral("Textured Cube"));
+ viewer.setResizeMode(QQuickView::SizeRootObjectToView);
+ viewer.show();
+
+ return app.exec();
+}
diff --git a/examples/canvas3d/texturedcube/qml/texturedcube/glMatrix-0.9.5.min.js b/examples/canvas3d/texturedcube/qml/texturedcube/glMatrix-0.9.5.min.js
new file mode 100644
index 0000000..9a2526a
--- /dev/null
+++ b/examples/canvas3d/texturedcube/qml/texturedcube/glMatrix-0.9.5.min.js
@@ -0,0 +1,4128 @@
+/**
+ * @fileoverview gl-matrix - High performance matrix and vector operations
+ * @author Brandon Jones
+ * @author Colin MacKenzie IV
+ * @version 2.2.0
+ */
+
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/*
+(function(_global) {
+ "use strict";
+
+ var shim = {};
+ if (typeof(exports) === 'undefined') {
+ if(typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
+ shim.exports = {};
+ define(function() {
+ return shim.exports;
+ });
+ } else {
+ // gl-matrix lives in a browser, define its namespaces in global
+ shim.exports = typeof(window) !== 'undefined' ? window : _global;
+ }
+ }
+ else {
+ // gl-matrix lives in commonjs, define its namespaces in exports
+ shim.exports = exports;
+ }
+
+ (function(exports) {*/
+ /* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+
+if(!GLMAT_EPSILON) {
+ var GLMAT_EPSILON = 0.000001;
+}
+
+if(!GLMAT_ARRAY_TYPE) {
+ var GLMAT_ARRAY_TYPE = Array;//(typeof Float32Array !== 'undefined') ? Float32Array : Array;
+}
+
+if(!GLMAT_RANDOM) {
+ var GLMAT_RANDOM = Math.random;
+}
+
+/**
+ * @class Common utilities
+ * @name glMatrix
+ */
+var glMatrix = {};
+
+/**
+ * Sets the type of array used when creating new vectors and matricies
+ *
+ * @param {Type} type Array type, such as Float32Array or Array
+ */
+glMatrix.setMatrixArrayType = function(type) {
+ GLMAT_ARRAY_TYPE = type;
+}
+
+/*if(typeof(exports) !== 'undefined') {
+ exports.glMatrix = glMatrix;
+}*/
+
+var degree = Math.PI / 180;
+
+/**
+* Convert Degree To Radian
+*
+* @param {Number} Angle in Degrees
+*/
+glMatrix.toRadian = function(a){
+ return a * degree;
+}
+;
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2 Dimensional Vector
+ * @name vec2
+ */
+
+var vec2 = {};
+
+/**
+ * Creates a new, empty vec2
+ *
+ * @returns {vec2} a new 2D vector
+ */
+vec2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = 0;
+ out[1] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with values from an existing vector
+ *
+ * @param {vec2} a vector to clone
+ * @returns {vec2} a new 2D vector
+ */
+vec2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Creates a new vec2 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} a new 2D vector
+ */
+vec2.fromValues = function(x, y) {
+ var out = new GLMAT_ARRAY_TYPE(2);
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Copy the values from one vec2 to another
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the source vector
+ * @returns {vec2} out
+ */
+vec2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ return out;
+};
+
+/**
+ * Set the components of a vec2 to the given values
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @returns {vec2} out
+ */
+vec2.set = function(out, x, y) {
+ out[0] = x;
+ out[1] = y;
+ return out;
+};
+
+/**
+ * Adds two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.subtract}
+ * @function
+ */
+vec2.sub = vec2.subtract;
+
+/**
+ * Multiplies two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.multiply}
+ * @function
+ */
+vec2.mul = vec2.multiply;
+
+/**
+ * Divides two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ return out;
+};
+
+/**
+ * Alias for {@link vec2.divide}
+ * @function
+ */
+vec2.div = vec2.divide;
+
+/**
+ * Returns the minimum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec2} out
+ */
+vec2.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ return out;
+};
+
+/**
+ * Scales a vec2 by a scalar number
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec2} out
+ */
+vec2.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ return out;
+};
+
+/**
+ * Adds two vec2's after scaling the second operand by a scalar value
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec2} out
+ */
+vec2.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec2.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.distance}
+ * @function
+ */
+vec2.dist = vec2.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec2.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredDistance}
+ * @function
+ */
+vec2.sqrDist = vec2.squaredDistance;
+
+/**
+ * Calculates the length of a vec2
+ *
+ * @param {vec2} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec2.length = function (a) {
+ var x = a[0],
+ y = a[1];
+ return Math.sqrt(x*x + y*y);
+};
+
+/**
+ * Alias for {@link vec2.length}
+ * @function
+ */
+vec2.len = vec2.length;
+
+/**
+ * Calculates the squared length of a vec2
+ *
+ * @param {vec2} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec2.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1];
+ return x*x + y*y;
+};
+
+/**
+ * Alias for {@link vec2.squaredLength}
+ * @function
+ */
+vec2.sqrLen = vec2.squaredLength;
+
+/**
+ * Negates the components of a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to negate
+ * @returns {vec2} out
+ */
+vec2.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ return out;
+};
+
+/**
+ * Normalize a vec2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a vector to normalize
+ * @returns {vec2} out
+ */
+vec2.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1];
+ var len = x*x + y*y;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec2's
+ *
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec2.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1];
+};
+
+/**
+ * Computes the cross product of two vec2's
+ * Note that the cross product must by definition produce a 3D vector
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @returns {vec3} out
+ */
+vec2.cross = function(out, a, b) {
+ var z = a[0] * b[1] - a[1] * b[0];
+ out[0] = out[1] = 0;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec2's
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the first operand
+ * @param {vec2} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec2} out
+ */
+vec2.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec2} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec2} out
+ */
+vec2.random = function (out, scale) {
+ scale = scale || 1.0;
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ out[0] = Math.cos(r) * scale;
+ out[1] = Math.sin(r) * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y;
+ out[1] = m[1] * x + m[3] * y;
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat2d
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat2d} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat2d = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[2] * y + m[4];
+ out[1] = m[1] * x + m[3] * y + m[5];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat3
+ * 3rd vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat3} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat3 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[3] * y + m[6];
+ out[1] = m[1] * x + m[4] * y + m[7];
+ return out;
+};
+
+/**
+ * Transforms the vec2 with a mat4
+ * 3rd vector component is implicitly '0'
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec2} out the receiving vector
+ * @param {vec2} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec2} out
+ */
+vec2.transformMat4 = function(out, a, m) {
+ var x = a[0],
+ y = a[1];
+ out[0] = m[0] * x + m[4] * y + m[12];
+ out[1] = m[1] * x + m[5] * y + m[13];
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec2s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec2.forEach = (function() {
+ var vec = vec2.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 2;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec2} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec2.str = function (a) {
+ return 'vec2(' + a[0] + ', ' + a[1] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec2 = vec2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3 Dimensional Vector
+ * @name vec3
+ */
+
+var vec3 = {};
+
+/**
+ * Creates a new, empty vec3
+ *
+ * @returns {vec3} a new 3D vector
+ */
+vec3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with values from an existing vector
+ *
+ * @param {vec3} a vector to clone
+ * @returns {vec3} a new 3D vector
+ */
+vec3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Creates a new vec3 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} a new 3D vector
+ */
+vec3.fromValues = function(x, y, z) {
+ var out = new GLMAT_ARRAY_TYPE(3);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Copy the values from one vec3 to another
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the source vector
+ * @returns {vec3} out
+ */
+vec3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ return out;
+};
+
+/**
+ * Set the components of a vec3 to the given values
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @returns {vec3} out
+ */
+vec3.set = function(out, x, y, z) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ return out;
+};
+
+/**
+ * Adds two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.subtract}
+ * @function
+ */
+vec3.sub = vec3.subtract;
+
+/**
+ * Multiplies two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.multiply}
+ * @function
+ */
+vec3.mul = vec3.multiply;
+
+/**
+ * Divides two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ return out;
+};
+
+/**
+ * Alias for {@link vec3.divide}
+ * @function
+ */
+vec3.div = vec3.divide;
+
+/**
+ * Returns the minimum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ return out;
+};
+
+/**
+ * Scales a vec3 by a scalar number
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec3} out
+ */
+vec3.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ return out;
+};
+
+/**
+ * Adds two vec3's after scaling the second operand by a scalar value
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec3} out
+ */
+vec3.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec3.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.distance}
+ * @function
+ */
+vec3.dist = vec3.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec3.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredDistance}
+ * @function
+ */
+vec3.sqrDist = vec3.squaredDistance;
+
+/**
+ * Calculates the length of a vec3
+ *
+ * @param {vec3} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec3.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return Math.sqrt(x*x + y*y + z*z);
+};
+
+/**
+ * Alias for {@link vec3.length}
+ * @function
+ */
+vec3.len = vec3.length;
+
+/**
+ * Calculates the squared length of a vec3
+ *
+ * @param {vec3} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec3.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ return x*x + y*y + z*z;
+};
+
+/**
+ * Alias for {@link vec3.squaredLength}
+ * @function
+ */
+vec3.sqrLen = vec3.squaredLength;
+
+/**
+ * Negates the components of a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to negate
+ * @returns {vec3} out
+ */
+vec3.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ return out;
+};
+
+/**
+ * Normalize a vec3
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a vector to normalize
+ * @returns {vec3} out
+ */
+vec3.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2];
+ var len = x*x + y*y + z*z;
+ if (len > 0) {
+ //TODO: evaluate use of glm_invsqrt here?
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec3's
+ *
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec3.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+};
+
+/**
+ * Computes the cross product of two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @returns {vec3} out
+ */
+vec3.cross = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2],
+ bx = b[0], by = b[1], bz = b[2];
+
+ out[0] = ay * bz - az * by;
+ out[1] = az * bx - ax * bz;
+ out[2] = ax * by - ay * bx;
+ return out;
+};
+
+/**
+ * Performs a linear interpolation between two vec3's
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the first operand
+ * @param {vec3} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec3} out
+ */
+vec3.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec3} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec3} out
+ */
+vec3.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ var r = GLMAT_RANDOM() * 2.0 * Math.PI;
+ var z = (GLMAT_RANDOM() * 2.0) - 1.0;
+ var zScale = Math.sqrt(1.0-z*z) * scale;
+
+ out[0] = Math.cos(r) * zScale;
+ out[1] = Math.sin(r) * zScale;
+ out[2] = z * scale;
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat4.
+ * 4th vector component is implicitly '1'
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12];
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13];
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a mat3.
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {mat4} m the 3x3 matrix to transform with
+ * @returns {vec3} out
+ */
+vec3.transformMat3 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2];
+ out[0] = x * m[0] + y * m[3] + z * m[6];
+ out[1] = x * m[1] + y * m[4] + z * m[7];
+ out[2] = x * m[2] + y * m[5] + z * m[8];
+ return out;
+};
+
+/**
+ * Transforms the vec3 with a quat
+ *
+ * @param {vec3} out the receiving vector
+ * @param {vec3} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec3} out
+ */
+vec3.transformQuat = function(out, a, q) {
+ // benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
+
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec3s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec3.forEach = (function() {
+ var vec = vec3.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 3;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec3} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec3.str = function (a) {
+ return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec3 = vec3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4 Dimensional Vector
+ * @name vec4
+ */
+
+var vec4 = {};
+
+/**
+ * Creates a new, empty vec4
+ *
+ * @returns {vec4} a new 4D vector
+ */
+vec4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with values from an existing vector
+ *
+ * @param {vec4} a vector to clone
+ * @returns {vec4} a new 4D vector
+ */
+vec4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Creates a new vec4 initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} a new 4D vector
+ */
+vec4.fromValues = function(x, y, z, w) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Copy the values from one vec4 to another
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the source vector
+ * @returns {vec4} out
+ */
+vec4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set the components of a vec4 to the given values
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {vec4} out
+ */
+vec4.set = function(out, x, y, z, w) {
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = w;
+ return out;
+};
+
+/**
+ * Adds two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.add = function(out, a, b) {
+ out[0] = a[0] + b[0];
+ out[1] = a[1] + b[1];
+ out[2] = a[2] + b[2];
+ out[3] = a[3] + b[3];
+ return out;
+};
+
+/**
+ * Subtracts vector b from vector a
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.subtract = function(out, a, b) {
+ out[0] = a[0] - b[0];
+ out[1] = a[1] - b[1];
+ out[2] = a[2] - b[2];
+ out[3] = a[3] - b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.subtract}
+ * @function
+ */
+vec4.sub = vec4.subtract;
+
+/**
+ * Multiplies two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.multiply = function(out, a, b) {
+ out[0] = a[0] * b[0];
+ out[1] = a[1] * b[1];
+ out[2] = a[2] * b[2];
+ out[3] = a[3] * b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.multiply}
+ * @function
+ */
+vec4.mul = vec4.multiply;
+
+/**
+ * Divides two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.divide = function(out, a, b) {
+ out[0] = a[0] / b[0];
+ out[1] = a[1] / b[1];
+ out[2] = a[2] / b[2];
+ out[3] = a[3] / b[3];
+ return out;
+};
+
+/**
+ * Alias for {@link vec4.divide}
+ * @function
+ */
+vec4.div = vec4.divide;
+
+/**
+ * Returns the minimum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.min = function(out, a, b) {
+ out[0] = Math.min(a[0], b[0]);
+ out[1] = Math.min(a[1], b[1]);
+ out[2] = Math.min(a[2], b[2]);
+ out[3] = Math.min(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Returns the maximum of two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {vec4} out
+ */
+vec4.max = function(out, a, b) {
+ out[0] = Math.max(a[0], b[0]);
+ out[1] = Math.max(a[1], b[1]);
+ out[2] = Math.max(a[2], b[2]);
+ out[3] = Math.max(a[3], b[3]);
+ return out;
+};
+
+/**
+ * Scales a vec4 by a scalar number
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {vec4} out
+ */
+vec4.scale = function(out, a, b) {
+ out[0] = a[0] * b;
+ out[1] = a[1] * b;
+ out[2] = a[2] * b;
+ out[3] = a[3] * b;
+ return out;
+};
+
+/**
+ * Adds two vec4's after scaling the second operand by a scalar value
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} scale the amount to scale b by before adding
+ * @returns {vec4} out
+ */
+vec4.scaleAndAdd = function(out, a, b, scale) {
+ out[0] = a[0] + (b[0] * scale);
+ out[1] = a[1] + (b[1] * scale);
+ out[2] = a[2] + (b[2] * scale);
+ out[3] = a[3] + (b[3] * scale);
+ return out;
+};
+
+/**
+ * Calculates the euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} distance between a and b
+ */
+vec4.distance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.distance}
+ * @function
+ */
+vec4.dist = vec4.distance;
+
+/**
+ * Calculates the squared euclidian distance between two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} squared distance between a and b
+ */
+vec4.squaredDistance = function(a, b) {
+ var x = b[0] - a[0],
+ y = b[1] - a[1],
+ z = b[2] - a[2],
+ w = b[3] - a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredDistance}
+ * @function
+ */
+vec4.sqrDist = vec4.squaredDistance;
+
+/**
+ * Calculates the length of a vec4
+ *
+ * @param {vec4} a vector to calculate length of
+ * @returns {Number} length of a
+ */
+vec4.length = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return Math.sqrt(x*x + y*y + z*z + w*w);
+};
+
+/**
+ * Alias for {@link vec4.length}
+ * @function
+ */
+vec4.len = vec4.length;
+
+/**
+ * Calculates the squared length of a vec4
+ *
+ * @param {vec4} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ */
+vec4.squaredLength = function (a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ return x*x + y*y + z*z + w*w;
+};
+
+/**
+ * Alias for {@link vec4.squaredLength}
+ * @function
+ */
+vec4.sqrLen = vec4.squaredLength;
+
+/**
+ * Negates the components of a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to negate
+ * @returns {vec4} out
+ */
+vec4.negate = function(out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = -a[3];
+ return out;
+};
+
+/**
+ * Normalize a vec4
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a vector to normalize
+ * @returns {vec4} out
+ */
+vec4.normalize = function(out, a) {
+ var x = a[0],
+ y = a[1],
+ z = a[2],
+ w = a[3];
+ var len = x*x + y*y + z*z + w*w;
+ if (len > 0) {
+ len = 1 / Math.sqrt(len);
+ out[0] = a[0] * len;
+ out[1] = a[1] * len;
+ out[2] = a[2] * len;
+ out[3] = a[3] * len;
+ }
+ return out;
+};
+
+/**
+ * Calculates the dot product of two vec4's
+ *
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @returns {Number} dot product of a and b
+ */
+vec4.dot = function (a, b) {
+ return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3];
+};
+
+/**
+ * Performs a linear interpolation between two vec4's
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the first operand
+ * @param {vec4} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {vec4} out
+ */
+vec4.lerp = function (out, a, b, t) {
+ var ax = a[0],
+ ay = a[1],
+ az = a[2],
+ aw = a[3];
+ out[0] = ax + t * (b[0] - ax);
+ out[1] = ay + t * (b[1] - ay);
+ out[2] = az + t * (b[2] - az);
+ out[3] = aw + t * (b[3] - aw);
+ return out;
+};
+
+/**
+ * Generates a random vector with the given scale
+ *
+ * @param {vec4} out the receiving vector
+ * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned
+ * @returns {vec4} out
+ */
+vec4.random = function (out, scale) {
+ scale = scale || 1.0;
+
+ //TODO: This is a pretty awful way of doing this. Find something better.
+ out[0] = GLMAT_RANDOM();
+ out[1] = GLMAT_RANDOM();
+ out[2] = GLMAT_RANDOM();
+ out[3] = GLMAT_RANDOM();
+ vec4.normalize(out, out);
+ vec4.scale(out, out, scale);
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a mat4.
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {mat4} m matrix to transform with
+ * @returns {vec4} out
+ */
+vec4.transformMat4 = function(out, a, m) {
+ var x = a[0], y = a[1], z = a[2], w = a[3];
+ out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
+ out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
+ out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
+ out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
+ return out;
+};
+
+/**
+ * Transforms the vec4 with a quat
+ *
+ * @param {vec4} out the receiving vector
+ * @param {vec4} a the vector to transform
+ * @param {quat} q quaternion to transform with
+ * @returns {vec4} out
+ */
+vec4.transformQuat = function(out, a, q) {
+ var x = a[0], y = a[1], z = a[2],
+ qx = q[0], qy = q[1], qz = q[2], qw = q[3],
+
+ // calculate quat * vec
+ ix = qw * x + qy * z - qz * y,
+ iy = qw * y + qz * x - qx * z,
+ iz = qw * z + qx * y - qy * x,
+ iw = -qx * x - qy * y - qz * z;
+
+ // calculate result * inverse quat
+ out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
+ out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
+ out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
+ return out;
+};
+
+/**
+ * Perform some operation over an array of vec4s.
+ *
+ * @param {Array} a the array of vectors to iterate over
+ * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed
+ * @param {Number} offset Number of elements to skip at the beginning of the array
+ * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array
+ * @param {Function} fn Function to call for each vector in the array
+ * @param {Object} [arg] additional argument to pass to fn
+ * @returns {Array} a
+ * @function
+ */
+vec4.forEach = (function() {
+ var vec = vec4.create();
+
+ return function(a, stride, offset, count, fn, arg) {
+ var i, l;
+ if(!stride) {
+ stride = 4;
+ }
+
+ if(!offset) {
+ offset = 0;
+ }
+
+ if(count) {
+ l = Math.min((count * stride) + offset, a.length);
+ } else {
+ l = a.length;
+ }
+
+ for(i = offset; i < l; i += stride) {
+ vec[0] = a[i]; vec[1] = a[i+1]; vec[2] = a[i+2]; vec[3] = a[i+3];
+ fn(vec, vec, arg);
+ a[i] = vec[0]; a[i+1] = vec[1]; a[i+2] = vec[2]; a[i+3] = vec[3];
+ }
+
+ return a;
+ };
+})();
+
+/**
+ * Returns a string representation of a vector
+ *
+ * @param {vec4} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+vec4.str = function (a) {
+ return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.vec4 = vec4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x2 Matrix
+ * @name mat2
+ */
+
+var mat2 = {};
+
+/**
+ * Creates a new identity mat2
+ *
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat2 initialized with values from an existing matrix
+ *
+ * @param {mat2} a matrix to clone
+ * @returns {mat2} a new 2x2 matrix
+ */
+mat2.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2 to another
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Set a mat2 to the identity matrix
+ *
+ * @param {mat2} out the receiving matrix
+ * @returns {mat2} out
+ */
+mat2.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a1 = a[1];
+ out[1] = a[2];
+ out[2] = a1;
+ } else {
+ out[0] = a[0];
+ out[1] = a[2];
+ out[2] = a[1];
+ out[3] = a[3];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+
+ // Calculate the determinant
+ det = a0 * a3 - a2 * a1;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = a3 * det;
+ out[1] = -a1 * det;
+ out[2] = -a2 * det;
+ out[3] = a0 * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the source matrix
+ * @returns {mat2} out
+ */
+mat2.adjoint = function(out, a) {
+ // Caching this value is nessecary if out == a
+ var a0 = a[0];
+ out[0] = a[3];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a0;
+
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2
+ *
+ * @param {mat2} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2.determinant = function (a) {
+ return a[0] * a[3] - a[2] * a[1];
+};
+
+/**
+ * Multiplies two mat2's
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the first operand
+ * @param {mat2} b the second operand
+ * @returns {mat2} out
+ */
+mat2.multiply = function (out, a, b) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3];
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = a0 * b0 + a1 * b2;
+ out[1] = a0 * b1 + a1 * b3;
+ out[2] = a2 * b0 + a3 * b2;
+ out[3] = a2 * b1 + a3 * b3;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2.multiply}
+ * @function
+ */
+mat2.mul = mat2.multiply;
+
+/**
+ * Rotates a mat2 by the given angle
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2} out
+ */
+mat2.rotate = function (out, a, rad) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+ out[0] = a0 * c + a1 * s;
+ out[1] = a0 * -s + a1 * c;
+ out[2] = a2 * c + a3 * s;
+ out[3] = a2 * -s + a3 * c;
+ return out;
+};
+
+/**
+ * Scales the mat2 by the dimensions in the given vec2
+ *
+ * @param {mat2} out the receiving matrix
+ * @param {mat2} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2} out
+ **/
+mat2.scale = function(out, a, v) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ v0 = v[0], v1 = v[1];
+ out[0] = a0 * v0;
+ out[1] = a1 * v1;
+ out[2] = a2 * v0;
+ out[3] = a3 * v1;
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2
+ *
+ * @param {mat2} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2.str = function (a) {
+ return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2 = mat2;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 2x3 Matrix
+ * @name mat2d
+ *
+ * @description
+ * A mat2d contains six elements defined as:
+ * <pre>
+ * [a, b,
+ * c, d,
+ * tx,ty]
+ * </pre>
+ * This is a short form for the 3x3 matrix:
+ * <pre>
+ * [a, b, 0
+ * c, d, 0
+ * tx,ty,1]
+ * </pre>
+ * The last column is ignored so the array is shorter and operations are faster.
+ */
+
+var mat2d = {};
+
+/**
+ * Creates a new identity mat2d
+ *
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Creates a new mat2d initialized with values from an existing matrix
+ *
+ * @param {mat2d} a matrix to clone
+ * @returns {mat2d} a new 2x3 matrix
+ */
+mat2d.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(6);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Copy the values from one mat2d to another
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ return out;
+};
+
+/**
+ * Set a mat2d to the identity matrix
+ *
+ * @param {mat2d} out the receiving matrix
+ * @returns {mat2d} out
+ */
+mat2d.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ out[4] = 0;
+ out[5] = 0;
+ return out;
+};
+
+/**
+ * Inverts a mat2d
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the source matrix
+ * @returns {mat2d} out
+ */
+mat2d.invert = function(out, a) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5];
+
+ var det = aa * ad - ab * ac;
+ if(!det){
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = ad * det;
+ out[1] = -ab * det;
+ out[2] = -ac * det;
+ out[3] = aa * det;
+ out[4] = (ac * aty - ad * atx) * det;
+ out[5] = (ab * atx - aa * aty) * det;
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat2d
+ *
+ * @param {mat2d} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat2d.determinant = function (a) {
+ return a[0] * a[3] - a[1] * a[2];
+};
+
+/**
+ * Multiplies two mat2d's
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the first operand
+ * @param {mat2d} b the second operand
+ * @returns {mat2d} out
+ */
+mat2d.multiply = function (out, a, b) {
+ var aa = a[0], ab = a[1], ac = a[2], ad = a[3],
+ atx = a[4], aty = a[5],
+ ba = b[0], bb = b[1], bc = b[2], bd = b[3],
+ btx = b[4], bty = b[5];
+
+ out[0] = aa*ba + ab*bc;
+ out[1] = aa*bb + ab*bd;
+ out[2] = ac*ba + ad*bc;
+ out[3] = ac*bb + ad*bd;
+ out[4] = ba*atx + bc*aty + btx;
+ out[5] = bb*atx + bd*aty + bty;
+ return out;
+};
+
+/**
+ * Alias for {@link mat2d.multiply}
+ * @function
+ */
+mat2d.mul = mat2d.multiply;
+
+
+/**
+ * Rotates a mat2d by the given angle
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat2d} out
+ */
+mat2d.rotate = function (out, a, rad) {
+ var aa = a[0],
+ ab = a[1],
+ ac = a[2],
+ ad = a[3],
+ atx = a[4],
+ aty = a[5],
+ st = Math.sin(rad),
+ ct = Math.cos(rad);
+
+ out[0] = aa*ct + ab*st;
+ out[1] = -aa*st + ab*ct;
+ out[2] = ac*ct + ad*st;
+ out[3] = -ac*st + ct*ad;
+ out[4] = ct*atx + st*aty;
+ out[5] = ct*aty - st*atx;
+ return out;
+};
+
+/**
+ * Scales the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.scale = function(out, a, v) {
+ var vx = v[0], vy = v[1];
+ out[0] = a[0] * vx;
+ out[1] = a[1] * vy;
+ out[2] = a[2] * vx;
+ out[3] = a[3] * vy;
+ out[4] = a[4] * vx;
+ out[5] = a[5] * vy;
+ return out;
+};
+
+/**
+ * Translates the mat2d by the dimensions in the given vec2
+ *
+ * @param {mat2d} out the receiving matrix
+ * @param {mat2d} a the matrix to translate
+ * @param {vec2} v the vec2 to translate the matrix by
+ * @returns {mat2d} out
+ **/
+mat2d.translate = function(out, a, v) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4] + v[0];
+ out[5] = a[5] + v[1];
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat2d
+ *
+ * @param {mat2d} a matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat2d.str = function (a) {
+ return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat2d = mat2d;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 3x3 Matrix
+ * @name mat3
+ */
+
+var mat3 = {};
+
+/**
+ * Creates a new identity mat3
+ *
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Copies the upper-left 3x3 values into the given mat3.
+ *
+ * @param {mat3} out the receiving 3x3 matrix
+ * @param {mat4} a the source 4x4 matrix
+ * @returns {mat3} out
+ */
+mat3.fromMat4 = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[4];
+ out[4] = a[5];
+ out[5] = a[6];
+ out[6] = a[8];
+ out[7] = a[9];
+ out[8] = a[10];
+ return out;
+};
+
+/**
+ * Creates a new mat3 initialized with values from an existing matrix
+ *
+ * @param {mat3} a matrix to clone
+ * @returns {mat3} a new 3x3 matrix
+ */
+mat3.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(9);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copy the values from one mat3 to another
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Set a mat3 to the identity matrix
+ *
+ * @param {mat3} out the receiving matrix
+ * @returns {mat3} out
+ */
+mat3.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 1;
+ out[5] = 0;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a12 = a[5];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a01;
+ out[5] = a[7];
+ out[6] = a02;
+ out[7] = a12;
+ } else {
+ out[0] = a[0];
+ out[1] = a[3];
+ out[2] = a[6];
+ out[3] = a[1];
+ out[4] = a[4];
+ out[5] = a[7];
+ out[6] = a[2];
+ out[7] = a[5];
+ out[8] = a[8];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b01 = a22 * a11 - a12 * a21,
+ b11 = -a22 * a10 + a12 * a20,
+ b21 = a21 * a10 - a11 * a20,
+
+ // Calculate the determinant
+ det = a00 * b01 + a01 * b11 + a02 * b21;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = b01 * det;
+ out[1] = (-a22 * a01 + a02 * a21) * det;
+ out[2] = (a12 * a01 - a02 * a11) * det;
+ out[3] = b11 * det;
+ out[4] = (a22 * a00 - a02 * a20) * det;
+ out[5] = (-a12 * a00 + a02 * a10) * det;
+ out[6] = b21 * det;
+ out[7] = (-a21 * a00 + a01 * a20) * det;
+ out[8] = (a11 * a00 - a01 * a10) * det;
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the source matrix
+ * @returns {mat3} out
+ */
+mat3.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ out[0] = (a11 * a22 - a12 * a21);
+ out[1] = (a02 * a21 - a01 * a22);
+ out[2] = (a01 * a12 - a02 * a11);
+ out[3] = (a12 * a20 - a10 * a22);
+ out[4] = (a00 * a22 - a02 * a20);
+ out[5] = (a02 * a10 - a00 * a12);
+ out[6] = (a10 * a21 - a11 * a20);
+ out[7] = (a01 * a20 - a00 * a21);
+ out[8] = (a00 * a11 - a01 * a10);
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat3
+ *
+ * @param {mat3} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat3.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8];
+
+ return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
+};
+
+/**
+ * Multiplies two mat3's
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the first operand
+ * @param {mat3} b the second operand
+ * @returns {mat3} out
+ */
+mat3.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ b00 = b[0], b01 = b[1], b02 = b[2],
+ b10 = b[3], b11 = b[4], b12 = b[5],
+ b20 = b[6], b21 = b[7], b22 = b[8];
+
+ out[0] = b00 * a00 + b01 * a10 + b02 * a20;
+ out[1] = b00 * a01 + b01 * a11 + b02 * a21;
+ out[2] = b00 * a02 + b01 * a12 + b02 * a22;
+
+ out[3] = b10 * a00 + b11 * a10 + b12 * a20;
+ out[4] = b10 * a01 + b11 * a11 + b12 * a21;
+ out[5] = b10 * a02 + b11 * a12 + b12 * a22;
+
+ out[6] = b20 * a00 + b21 * a10 + b22 * a20;
+ out[7] = b20 * a01 + b21 * a11 + b22 * a21;
+ out[8] = b20 * a02 + b21 * a12 + b22 * a22;
+ return out;
+};
+
+/**
+ * Alias for {@link mat3.multiply}
+ * @function
+ */
+mat3.mul = mat3.multiply;
+
+/**
+ * Translate a mat3 by the given vector
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to translate
+ * @param {vec2} v vector to translate by
+ * @returns {mat3} out
+ */
+mat3.translate = function(out, a, v) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+ x = v[0], y = v[1];
+
+ out[0] = a00;
+ out[1] = a01;
+ out[2] = a02;
+
+ out[3] = a10;
+ out[4] = a11;
+ out[5] = a12;
+
+ out[6] = x * a00 + y * a10 + a20;
+ out[7] = x * a01 + y * a11 + a21;
+ out[8] = x * a02 + y * a12 + a22;
+ return out;
+};
+
+/**
+ * Rotates a mat3 by the given angle
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat3} out
+ */
+mat3.rotate = function (out, a, rad) {
+ var a00 = a[0], a01 = a[1], a02 = a[2],
+ a10 = a[3], a11 = a[4], a12 = a[5],
+ a20 = a[6], a21 = a[7], a22 = a[8],
+
+ s = Math.sin(rad),
+ c = Math.cos(rad);
+
+ out[0] = c * a00 + s * a10;
+ out[1] = c * a01 + s * a11;
+ out[2] = c * a02 + s * a12;
+
+ out[3] = c * a10 - s * a00;
+ out[4] = c * a11 - s * a01;
+ out[5] = c * a12 - s * a02;
+
+ out[6] = a20;
+ out[7] = a21;
+ out[8] = a22;
+ return out;
+};
+
+/**
+ * Scales the mat3 by the dimensions in the given vec2
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat3} a the matrix to rotate
+ * @param {vec2} v the vec2 to scale the matrix by
+ * @returns {mat3} out
+ **/
+mat3.scale = function(out, a, v) {
+ var x = v[0], y = v[1];
+
+ out[0] = x * a[0];
+ out[1] = x * a[1];
+ out[2] = x * a[2];
+
+ out[3] = y * a[3];
+ out[4] = y * a[4];
+ out[5] = y * a[5];
+
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ return out;
+};
+
+/**
+ * Copies the values from a mat2d into a mat3
+ *
+ * @param {mat3} out the receiving matrix
+ * @param {mat2d} a the matrix to copy
+ * @returns {mat3} out
+ **/
+mat3.fromMat2d = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = 0;
+
+ out[3] = a[2];
+ out[4] = a[3];
+ out[5] = 0;
+
+ out[6] = a[4];
+ out[7] = a[5];
+ out[8] = 1;
+ return out;
+};
+
+/**
+* Calculates a 3x3 matrix from the given quaternion
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {quat} q Quaternion to create matrix from
+*
+* @returns {mat3} out
+*/
+mat3.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[3] = yx - wz;
+ out[6] = zx + wy;
+
+ out[1] = yx + wz;
+ out[4] = 1 - xx - zz;
+ out[7] = zy - wx;
+
+ out[2] = zx - wy;
+ out[5] = zy + wx;
+ out[8] = 1 - xx - yy;
+
+ return out;
+};
+
+/**
+* Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix
+*
+* @param {mat3} out mat3 receiving operation result
+* @param {mat4} a Mat4 to derive the normal matrix from
+*
+* @returns {mat3} out
+*/
+mat3.normalFromMat4 = function (out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+
+ out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+
+ out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat3
+ *
+ * @param {mat3} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat3.str = function (a) {
+ return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
+ a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
+ a[6] + ', ' + a[7] + ', ' + a[8] + ')';
+};
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat3 = mat3;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class 4x4 Matrix
+ * @name mat4
+ */
+
+var mat4 = {};
+
+/**
+ * Creates a new identity mat4
+ *
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Creates a new mat4 initialized with values from an existing matrix
+ *
+ * @param {mat4} a matrix to clone
+ * @returns {mat4} a new 4x4 matrix
+ */
+mat4.clone = function(a) {
+ var out = new GLMAT_ARRAY_TYPE(16);
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Copy the values from one mat4 to another
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.copy = function(out, a) {
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Set a mat4 to the identity matrix
+ *
+ * @param {mat4} out the receiving matrix
+ * @returns {mat4} out
+ */
+mat4.identity = function(out) {
+ out[0] = 1;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = 1;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 1;
+ out[11] = 0;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Transpose the values of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.transpose = function(out, a) {
+ // If we are transposing ourselves we can skip a few steps but have to cache some values
+ if (out === a) {
+ var a01 = a[1], a02 = a[2], a03 = a[3],
+ a12 = a[6], a13 = a[7],
+ a23 = a[11];
+
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a01;
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a02;
+ out[9] = a12;
+ out[11] = a[14];
+ out[12] = a03;
+ out[13] = a13;
+ out[14] = a23;
+ } else {
+ out[0] = a[0];
+ out[1] = a[4];
+ out[2] = a[8];
+ out[3] = a[12];
+ out[4] = a[1];
+ out[5] = a[5];
+ out[6] = a[9];
+ out[7] = a[13];
+ out[8] = a[2];
+ out[9] = a[6];
+ out[10] = a[10];
+ out[11] = a[14];
+ out[12] = a[3];
+ out[13] = a[7];
+ out[14] = a[11];
+ out[15] = a[15];
+ }
+
+ return out;
+};
+
+/**
+ * Inverts a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.invert = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32,
+
+ // Calculate the determinant
+ det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+
+ if (!det) {
+ return null;
+ }
+ det = 1.0 / det;
+
+ out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
+ out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
+ out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
+ out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
+ out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
+ out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
+ out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
+ out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
+ out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
+ out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
+ out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
+ out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
+ out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
+ out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
+ out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
+ out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
+
+ return out;
+};
+
+/**
+ * Calculates the adjugate of a mat4
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the source matrix
+ * @returns {mat4} out
+ */
+mat4.adjoint = function(out, a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ out[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
+ out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
+ out[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
+ out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
+ out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
+ out[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
+ out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
+ out[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
+ out[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
+ out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
+ out[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
+ out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
+ out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
+ out[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
+ out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
+ out[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
+ return out;
+};
+
+/**
+ * Calculates the determinant of a mat4
+ *
+ * @param {mat4} a the source matrix
+ * @returns {Number} determinant of a
+ */
+mat4.determinant = function (a) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
+
+ b00 = a00 * a11 - a01 * a10,
+ b01 = a00 * a12 - a02 * a10,
+ b02 = a00 * a13 - a03 * a10,
+ b03 = a01 * a12 - a02 * a11,
+ b04 = a01 * a13 - a03 * a11,
+ b05 = a02 * a13 - a03 * a12,
+ b06 = a20 * a31 - a21 * a30,
+ b07 = a20 * a32 - a22 * a30,
+ b08 = a20 * a33 - a23 * a30,
+ b09 = a21 * a32 - a22 * a31,
+ b10 = a21 * a33 - a23 * a31,
+ b11 = a22 * a33 - a23 * a32;
+
+ // Calculate the determinant
+ return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
+};
+
+/**
+ * Multiplies two mat4's
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the first operand
+ * @param {mat4} b the second operand
+ * @returns {mat4} out
+ */
+mat4.multiply = function (out, a, b) {
+ var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
+ a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
+ a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
+ a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
+
+ // Cache only the current line of the second matrix
+ var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
+ out[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
+ out[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
+ out[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+
+ b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
+ out[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
+ out[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
+ out[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
+ out[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
+ return out;
+};
+
+/**
+ * Alias for {@link mat4.multiply}
+ * @function
+ */
+mat4.mul = mat4.multiply;
+
+/**
+ * Translate a mat4 by the given vector
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to translate
+ * @param {vec3} v vector to translate by
+ * @returns {mat4} out
+ */
+mat4.translate = function (out, a, v) {
+ var x = v[0], y = v[1], z = v[2],
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ a30, a31, a32, a33;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+ a30 = a[12]; a31 = a[13]; a32 = a[14]; a33 = a[15];
+
+ out[0] = a00 + a03*x;
+ out[1] = a01 + a03*y;
+ out[2] = a02 + a03*z;
+ out[3] = a03;
+
+ out[4] = a10 + a13*x;
+ out[5] = a11 + a13*y;
+ out[6] = a12 + a13*z;
+ out[7] = a13;
+
+ out[8] = a20 + a23*x;
+ out[9] = a21 + a23*y;
+ out[10] = a22 + a23*z;
+ out[11] = a23;
+ out[12] = a30 + a33*x;
+ out[13] = a31 + a33*y;
+ out[14] = a32 + a33*z;
+ out[15] = a33;
+
+ return out;
+};
+/**
+ * Scales the mat4 by the dimensions in the given vec3
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to scale
+ * @param {vec3} v the vec3 to scale the matrix by
+ * @returns {mat4} out
+ **/
+mat4.scale = function(out, a, v) {
+ var x = v[0], y = v[1], z = v[2];
+
+ out[0] = a[0] * x;
+ out[1] = a[1] * x;
+ out[2] = a[2] * x;
+ out[3] = a[3] * x;
+ out[4] = a[4] * y;
+ out[5] = a[5] * y;
+ out[6] = a[6] * y;
+ out[7] = a[7] * y;
+ out[8] = a[8] * z;
+ out[9] = a[9] * z;
+ out[10] = a[10] * z;
+ out[11] = a[11] * z;
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ return out;
+};
+
+/**
+ * Rotates a mat4 by the given angle
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @param {vec3} axis the axis to rotate around
+ * @returns {mat4} out
+ */
+mat4.rotate = function (out, a, rad, axis) {
+ var x = axis[0], y = axis[1], z = axis[2],
+ len = Math.sqrt(x * x + y * y + z * z),
+ s, c, t,
+ a00, a01, a02, a03,
+ a10, a11, a12, a13,
+ a20, a21, a22, a23,
+ b00, b01, b02,
+ b10, b11, b12,
+ b20, b21, b22;
+
+ if (Math.abs(len) < GLMAT_EPSILON) { return null; }
+
+ len = 1 / len;
+ x *= len;
+ y *= len;
+ z *= len;
+
+ s = Math.sin(rad);
+ c = Math.cos(rad);
+ t = 1 - c;
+
+ a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
+ a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
+ a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
+
+ // Construct the elements of the rotation matrix
+ b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
+ b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
+ b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
+
+ // Perform rotation-specific matrix multiplication
+ out[0] = a00 * b00 + a10 * b01 + a20 * b02;
+ out[1] = a01 * b00 + a11 * b01 + a21 * b02;
+ out[2] = a02 * b00 + a12 * b01 + a22 * b02;
+ out[3] = a03 * b00 + a13 * b01 + a23 * b02;
+ out[4] = a00 * b10 + a10 * b11 + a20 * b12;
+ out[5] = a01 * b10 + a11 * b11 + a21 * b12;
+ out[6] = a02 * b10 + a12 * b11 + a22 * b12;
+ out[7] = a03 * b10 + a13 * b11 + a23 * b12;
+ out[8] = a00 * b20 + a10 * b21 + a20 * b22;
+ out[9] = a01 * b20 + a11 * b21 + a21 * b22;
+ out[10] = a02 * b20 + a12 * b21 + a22 * b22;
+ out[11] = a03 * b20 + a13 * b21 + a23 * b22;
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the X axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateX = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[0] = a[0];
+ out[1] = a[1];
+ out[2] = a[2];
+ out[3] = a[3];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[4] = a10 * c + a20 * s;
+ out[5] = a11 * c + a21 * s;
+ out[6] = a12 * c + a22 * s;
+ out[7] = a13 * c + a23 * s;
+ out[8] = a20 * c - a10 * s;
+ out[9] = a21 * c - a11 * s;
+ out[10] = a22 * c - a12 * s;
+ out[11] = a23 * c - a13 * s;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Y axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateY = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a20 = a[8],
+ a21 = a[9],
+ a22 = a[10],
+ a23 = a[11];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged rows
+ out[4] = a[4];
+ out[5] = a[5];
+ out[6] = a[6];
+ out[7] = a[7];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c - a20 * s;
+ out[1] = a01 * c - a21 * s;
+ out[2] = a02 * c - a22 * s;
+ out[3] = a03 * c - a23 * s;
+ out[8] = a00 * s + a20 * c;
+ out[9] = a01 * s + a21 * c;
+ out[10] = a02 * s + a22 * c;
+ out[11] = a03 * s + a23 * c;
+ return out;
+};
+
+/**
+ * Rotates a matrix by the given angle around the Z axis
+ *
+ * @param {mat4} out the receiving matrix
+ * @param {mat4} a the matrix to rotate
+ * @param {Number} rad the angle to rotate the matrix by
+ * @returns {mat4} out
+ */
+mat4.rotateZ = function (out, a, rad) {
+ var s = Math.sin(rad),
+ c = Math.cos(rad),
+ a00 = a[0],
+ a01 = a[1],
+ a02 = a[2],
+ a03 = a[3],
+ a10 = a[4],
+ a11 = a[5],
+ a12 = a[6],
+ a13 = a[7];
+
+ if (a !== out) { // If the source and destination differ, copy the unchanged last row
+ out[8] = a[8];
+ out[9] = a[9];
+ out[10] = a[10];
+ out[11] = a[11];
+ out[12] = a[12];
+ out[13] = a[13];
+ out[14] = a[14];
+ out[15] = a[15];
+ }
+
+ // Perform axis-specific matrix multiplication
+ out[0] = a00 * c + a10 * s;
+ out[1] = a01 * c + a11 * s;
+ out[2] = a02 * c + a12 * s;
+ out[3] = a03 * c + a13 * s;
+ out[4] = a10 * c - a00 * s;
+ out[5] = a11 * c - a01 * s;
+ out[6] = a12 * c - a02 * s;
+ out[7] = a13 * c - a03 * s;
+ return out;
+};
+
+/**
+ * Creates a matrix from a quaternion rotation and vector translation
+ * This is equivalent to (but much faster than):
+ *
+ * mat4.identity(dest);
+ * mat4.translate(dest, vec);
+ * var quatMat = mat4.create();
+ * quat4.toMat4(quat, quatMat);
+ * mat4.multiply(dest, quatMat);
+ *
+ * @param {mat4} out mat4 receiving operation result
+ * @param {quat4} q Rotation quaternion
+ * @param {vec3} v Translation vector
+ * @returns {mat4} out
+ */
+mat4.fromRotationTranslation = function (out, q, v) {
+ // Quaternion math
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ xy = x * y2,
+ xz = x * z2,
+ yy = y * y2,
+ yz = y * z2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - (yy + zz);
+ out[1] = xy + wz;
+ out[2] = xz - wy;
+ out[3] = 0;
+ out[4] = xy - wz;
+ out[5] = 1 - (xx + zz);
+ out[6] = yz + wx;
+ out[7] = 0;
+ out[8] = xz + wy;
+ out[9] = yz - wx;
+ out[10] = 1 - (xx + yy);
+ out[11] = 0;
+ out[12] = v[0];
+ out[13] = v[1];
+ out[14] = v[2];
+ out[15] = 1;
+
+ return out;
+};
+
+mat4.fromQuat = function (out, q) {
+ var x = q[0], y = q[1], z = q[2], w = q[3],
+ x2 = x + x,
+ y2 = y + y,
+ z2 = z + z,
+
+ xx = x * x2,
+ yx = y * x2,
+ yy = y * y2,
+ zx = z * x2,
+ zy = z * y2,
+ zz = z * z2,
+ wx = w * x2,
+ wy = w * y2,
+ wz = w * z2;
+
+ out[0] = 1 - yy - zz;
+ out[1] = yx + wz;
+ out[2] = zx - wy;
+ out[3] = 0;
+
+ out[4] = yx - wz;
+ out[5] = 1 - xx - zz;
+ out[6] = zy + wx;
+ out[7] = 0;
+
+ out[8] = zx + wy;
+ out[9] = zy - wx;
+ out[10] = 1 - xx - yy;
+ out[11] = 0;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = 0;
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Generates a frustum matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {Number} left Left bound of the frustum
+ * @param {Number} right Right bound of the frustum
+ * @param {Number} bottom Bottom bound of the frustum
+ * @param {Number} top Top bound of the frustum
+ * @param {Number} near Near bound of the frustum
+ * @param {Number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.frustum = function (out, left, right, bottom, top, near, far) {
+ var rl = 1 / (right - left),
+ tb = 1 / (top - bottom),
+ nf = 1 / (near - far);
+ out[0] = (near * 2) * rl;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = (near * 2) * tb;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = (right + left) * rl;
+ out[9] = (top + bottom) * tb;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (far * near * 2) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a perspective projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} fovy Vertical field of view in radians
+ * @param {number} aspect Aspect ratio. typically viewport width/height
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.perspective = function (out, fovy, aspect, near, far) {
+ var f = 1.0 / Math.tan(fovy / 2),
+ nf = 1 / (near - far);
+ out[0] = f / aspect;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+
+ out[4] = 0;
+ out[5] = f;
+ out[6] = 0;
+ out[7] = 0;
+
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = (far + near) * nf;
+ out[11] = -1;
+
+ out[12] = 0;
+ out[13] = 0;
+ out[14] = (2 * far * near) * nf;
+ out[15] = 0;
+ return out;
+};
+
+/**
+ * Generates a orthogonal projection matrix with the given bounds
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {number} left Left bound of the frustum
+ * @param {number} right Right bound of the frustum
+ * @param {number} bottom Bottom bound of the frustum
+ * @param {number} top Top bound of the frustum
+ * @param {number} near Near bound of the frustum
+ * @param {number} far Far bound of the frustum
+ * @returns {mat4} out
+ */
+mat4.ortho = function (out, left, right, bottom, top, near, far) {
+ var lr = 1 / (left - right),
+ bt = 1 / (bottom - top),
+ nf = 1 / (near - far);
+ out[0] = -2 * lr;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 0;
+ out[4] = 0;
+ out[5] = -2 * bt;
+ out[6] = 0;
+ out[7] = 0;
+ out[8] = 0;
+ out[9] = 0;
+ out[10] = 2 * nf;
+ out[11] = 0;
+ out[12] = (left + right) * lr;
+ out[13] = (top + bottom) * bt;
+ out[14] = (far + near) * nf;
+ out[15] = 1;
+ return out;
+};
+
+/**
+ * Generates a look-at matrix with the given eye position, focal point, and up axis
+ *
+ * @param {mat4} out mat4 frustum matrix will be written into
+ * @param {vec3} eye Position of the viewer
+ * @param {vec3} center Point the viewer is looking at
+ * @param {vec3} up vec3 pointing up
+ * @returns {mat4} out
+ */
+mat4.lookAt = function (out, eye, center, up) {
+ var x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
+ eyex = eye[0],
+ eyey = eye[1],
+ eyez = eye[2],
+ upx = up[0],
+ upy = up[1],
+ upz = up[2],
+ centerx = center[0],
+ centery = center[1],
+ centerz = center[2];
+
+ if (Math.abs(eyex - centerx) < GLMAT_EPSILON &&
+ Math.abs(eyey - centery) < GLMAT_EPSILON &&
+ Math.abs(eyez - centerz) < GLMAT_EPSILON) {
+ return mat4.identity(out);
+ }
+
+ z0 = eyex - centerx;
+ z1 = eyey - centery;
+ z2 = eyez - centerz;
+
+ len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
+ z0 *= len;
+ z1 *= len;
+ z2 *= len;
+
+ x0 = upy * z2 - upz * z1;
+ x1 = upz * z0 - upx * z2;
+ x2 = upx * z1 - upy * z0;
+ len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
+ if (!len) {
+ x0 = 0;
+ x1 = 0;
+ x2 = 0;
+ } else {
+ len = 1 / len;
+ x0 *= len;
+ x1 *= len;
+ x2 *= len;
+ }
+
+ y0 = z1 * x2 - z2 * x1;
+ y1 = z2 * x0 - z0 * x2;
+ y2 = z0 * x1 - z1 * x0;
+
+ len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
+ if (!len) {
+ y0 = 0;
+ y1 = 0;
+ y2 = 0;
+ } else {
+ len = 1 / len;
+ y0 *= len;
+ y1 *= len;
+ y2 *= len;
+ }
+
+ out[0] = x0;
+ out[1] = y0;
+ out[2] = z0;
+ out[3] = 0;
+ out[4] = x1;
+ out[5] = y1;
+ out[6] = z1;
+ out[7] = 0;
+ out[8] = x2;
+ out[9] = y2;
+ out[10] = z2;
+ out[11] = 0;
+ out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
+ out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
+ out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
+ out[15] = 1;
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a mat4
+ *
+ * @param {mat4} mat matrix to represent as a string
+ * @returns {String} string representation of the matrix
+ */
+mat4.str = function (a) {
+ return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
+ a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
+ a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
+ a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.mat4 = mat4;
+}
+;*/
+/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved.
+
+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.
+
+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 HOLDER 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. */
+
+/**
+ * @class Quaternion
+ * @name quat
+ */
+
+var quat = {};
+
+/**
+ * Creates a new identity quat
+ *
+ * @returns {quat} a new quaternion
+ */
+quat.create = function() {
+ var out = new GLMAT_ARRAY_TYPE(4);
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quaternion to represent the shortest rotation from one
+ * vector to another.
+ *
+ * Both vectors are assumed to be unit length.
+ *
+ * @param {quat} out the receiving quaternion.
+ * @param {vec3} a the initial vector
+ * @param {vec3} b the destination vector
+ * @returns {quat} out
+ */
+quat.rotationTo = (function() {
+ var tmpvec3 = vec3.create();
+ var xUnitVec3 = vec3.fromValues(1,0,0);
+ var yUnitVec3 = vec3.fromValues(0,1,0);
+
+ return function(out, a, b) {
+ var dot = vec3.dot(a, b);
+ if (dot < -0.999999) {
+ vec3.cross(tmpvec3, xUnitVec3, a);
+ if (vec3.length(tmpvec3) < 0.000001)
+ vec3.cross(tmpvec3, yUnitVec3, a);
+ vec3.normalize(tmpvec3, tmpvec3);
+ quat.setAxisAngle(out, tmpvec3, Math.PI);
+ return out;
+ } else if (dot > 0.999999) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+ } else {
+ vec3.cross(tmpvec3, a, b);
+ out[0] = tmpvec3[0];
+ out[1] = tmpvec3[1];
+ out[2] = tmpvec3[2];
+ out[3] = 1 + dot;
+ return quat.normalize(out, out);
+ }
+ };
+})();
+
+/**
+ * Sets the specified quaternion with values corresponding to the given
+ * axes. Each axis is a vec3 and is expected to be unit length and
+ * perpendicular to all other specified axes.
+ *
+ * @param {vec3} view the vector representing the viewing direction
+ * @param {vec3} right the vector representing the local "right" direction
+ * @param {vec3} up the vector representing the local "up" direction
+ * @returns {quat} out
+ */
+quat.setAxes = (function() {
+ var matr = mat3.create();
+
+ return function(out, view, right, up) {
+ matr[0] = right[0];
+ matr[3] = right[1];
+ matr[6] = right[2];
+
+ matr[1] = up[0];
+ matr[4] = up[1];
+ matr[7] = up[2];
+
+ matr[2] = -view[0];
+ matr[5] = -view[1];
+ matr[8] = -view[2];
+
+ return quat.normalize(out, quat.fromMat3(out, matr));
+ };
+})();
+
+/**
+ * Creates a new quat initialized with values from an existing quaternion
+ *
+ * @param {quat} a quaternion to clone
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.clone = vec4.clone;
+
+/**
+ * Creates a new quat initialized with the given values
+ *
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} a new quaternion
+ * @function
+ */
+quat.fromValues = vec4.fromValues;
+
+/**
+ * Copy the values from one quat to another
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the source quaternion
+ * @returns {quat} out
+ * @function
+ */
+quat.copy = vec4.copy;
+
+/**
+ * Set the components of a quat to the given values
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {Number} x X component
+ * @param {Number} y Y component
+ * @param {Number} z Z component
+ * @param {Number} w W component
+ * @returns {quat} out
+ * @function
+ */
+quat.set = vec4.set;
+
+/**
+ * Set a quat to the identity quaternion
+ *
+ * @param {quat} out the receiving quaternion
+ * @returns {quat} out
+ */
+quat.identity = function(out) {
+ out[0] = 0;
+ out[1] = 0;
+ out[2] = 0;
+ out[3] = 1;
+ return out;
+};
+
+/**
+ * Sets a quat from the given angle and rotation axis,
+ * then returns it.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {vec3} axis the axis around which to rotate
+ * @param {Number} rad the angle in radians
+ * @returns {quat} out
+ **/
+quat.setAxisAngle = function(out, axis, rad) {
+ rad = rad * 0.5;
+ var s = Math.sin(rad);
+ out[0] = s * axis[0];
+ out[1] = s * axis[1];
+ out[2] = s * axis[2];
+ out[3] = Math.cos(rad);
+ return out;
+};
+
+/**
+ * Adds two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ * @function
+ */
+quat.add = vec4.add;
+
+/**
+ * Multiplies two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {quat} out
+ */
+quat.multiply = function(out, a, b) {
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ out[0] = ax * bw + aw * bx + ay * bz - az * by;
+ out[1] = ay * bw + aw * by + az * bx - ax * bz;
+ out[2] = az * bw + aw * bz + ax * by - ay * bx;
+ out[3] = aw * bw - ax * bx - ay * by - az * bz;
+ return out;
+};
+
+/**
+ * Alias for {@link quat.multiply}
+ * @function
+ */
+quat.mul = quat.multiply;
+
+/**
+ * Scales a quat by a scalar number
+ *
+ * @param {quat} out the receiving vector
+ * @param {quat} a the vector to scale
+ * @param {Number} b amount to scale the vector by
+ * @returns {quat} out
+ * @function
+ */
+quat.scale = vec4.scale;
+
+/**
+ * Rotates a quaternion by the given angle about the X axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateX = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + aw * bx;
+ out[1] = ay * bw + az * bx;
+ out[2] = az * bw - ay * bx;
+ out[3] = aw * bw - ax * bx;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Y axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateY = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ by = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw - az * by;
+ out[1] = ay * bw + aw * by;
+ out[2] = az * bw + ax * by;
+ out[3] = aw * bw - ay * by;
+ return out;
+};
+
+/**
+ * Rotates a quaternion by the given angle about the Z axis
+ *
+ * @param {quat} out quat receiving operation result
+ * @param {quat} a quat to rotate
+ * @param {number} rad angle (in radians) to rotate
+ * @returns {quat} out
+ */
+quat.rotateZ = function (out, a, rad) {
+ rad *= 0.5;
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bz = Math.sin(rad), bw = Math.cos(rad);
+
+ out[0] = ax * bw + ay * bz;
+ out[1] = ay * bw - ax * bz;
+ out[2] = az * bw + aw * bz;
+ out[3] = aw * bw - az * bz;
+ return out;
+};
+
+/**
+ * Calculates the W component of a quat from the X, Y, and Z components.
+ * Assumes that quaternion is 1 unit in length.
+ * Any existing W component will be ignored.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate W component of
+ * @returns {quat} out
+ */
+quat.calculateW = function (out, a) {
+ var x = a[0], y = a[1], z = a[2];
+
+ out[0] = x;
+ out[1] = y;
+ out[2] = z;
+ out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
+ return out;
+};
+
+/**
+ * Calculates the dot product of two quat's
+ *
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @returns {Number} dot product of a and b
+ * @function
+ */
+quat.dot = vec4.dot;
+
+/**
+ * Performs a linear interpolation between two quat's
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ * @function
+ */
+quat.lerp = vec4.lerp;
+
+/**
+ * Performs a spherical linear interpolation between two quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a the first operand
+ * @param {quat} b the second operand
+ * @param {Number} t interpolation amount between the two inputs
+ * @returns {quat} out
+ */
+quat.slerp = function (out, a, b, t) {
+ // benchmarks:
+ // http://jsperf.com/quaternion-slerp-implementations
+
+ var ax = a[0], ay = a[1], az = a[2], aw = a[3],
+ bx = b[0], by = b[1], bz = b[2], bw = b[3];
+
+ var omega, cosom, sinom, scale0, scale1;
+
+ // calc cosine
+ cosom = ax * bx + ay * by + az * bz + aw * bw;
+ // adjust signs (if necessary)
+ if ( cosom < 0.0 ) {
+ cosom = -cosom;
+ bx = - bx;
+ by = - by;
+ bz = - bz;
+ bw = - bw;
+ }
+ // calculate coefficients
+ if ( (1.0 - cosom) > 0.000001 ) {
+ // standard case (slerp)
+ omega = Math.acos(cosom);
+ sinom = Math.sin(omega);
+ scale0 = Math.sin((1.0 - t) * omega) / sinom;
+ scale1 = Math.sin(t * omega) / sinom;
+ } else {
+ // "from" and "to" quaternions are very close
+ // ... so we can do a linear interpolation
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+ // calculate final values
+ out[0] = scale0 * ax + scale1 * bx;
+ out[1] = scale0 * ay + scale1 * by;
+ out[2] = scale0 * az + scale1 * bz;
+ out[3] = scale0 * aw + scale1 * bw;
+
+ return out;
+};
+
+/**
+ * Calculates the inverse of a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate inverse of
+ * @returns {quat} out
+ */
+quat.invert = function(out, a) {
+ var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3],
+ dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
+ invDot = dot ? 1.0/dot : 0;
+
+ // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
+
+ out[0] = -a0*invDot;
+ out[1] = -a1*invDot;
+ out[2] = -a2*invDot;
+ out[3] = a3*invDot;
+ return out;
+};
+
+/**
+ * Calculates the conjugate of a quat
+ * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quat to calculate conjugate of
+ * @returns {quat} out
+ */
+quat.conjugate = function (out, a) {
+ out[0] = -a[0];
+ out[1] = -a[1];
+ out[2] = -a[2];
+ out[3] = a[3];
+ return out;
+};
+
+/**
+ * Calculates the length of a quat
+ *
+ * @param {quat} a vector to calculate length of
+ * @returns {Number} length of a
+ * @function
+ */
+quat.length = vec4.length;
+
+/**
+ * Alias for {@link quat.length}
+ * @function
+ */
+quat.len = quat.length;
+
+/**
+ * Calculates the squared length of a quat
+ *
+ * @param {quat} a vector to calculate squared length of
+ * @returns {Number} squared length of a
+ * @function
+ */
+quat.squaredLength = vec4.squaredLength;
+
+/**
+ * Alias for {@link quat.squaredLength}
+ * @function
+ */
+quat.sqrLen = quat.squaredLength;
+
+/**
+ * Normalize a quat
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {quat} a quaternion to normalize
+ * @returns {quat} out
+ * @function
+ */
+quat.normalize = vec4.normalize;
+
+/**
+ * Creates a quaternion from the given 3x3 rotation matrix.
+ *
+ * NOTE: The resultant quaternion is not normalized, so you should be sure
+ * to renormalize the quaternion yourself where necessary.
+ *
+ * @param {quat} out the receiving quaternion
+ * @param {mat3} m rotation matrix
+ * @returns {quat} out
+ * @function
+ */
+quat.fromMat3 = function(out, m) {
+ // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
+ // article "Quaternion Calculus and Fast Animation".
+ var fTrace = m[0] + m[4] + m[8];
+ var fRoot;
+
+ if ( fTrace > 0.0 ) {
+ // |w| > 1/2, may as well choose w > 1/2
+ fRoot = Math.sqrt(fTrace + 1.0); // 2w
+ out[3] = 0.5 * fRoot;
+ fRoot = 0.5/fRoot; // 1/(4w)
+ out[0] = (m[7]-m[5])*fRoot;
+ out[1] = (m[2]-m[6])*fRoot;
+ out[2] = (m[3]-m[1])*fRoot;
+ } else {
+ // |w| <= 1/2
+ var i = 0;
+ if ( m[4] > m[0] )
+ i = 1;
+ if ( m[8] > m[i*3+i] )
+ i = 2;
+ var j = (i+1)%3;
+ var k = (i+2)%3;
+
+ fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
+ out[i] = 0.5 * fRoot;
+ fRoot = 0.5 / fRoot;
+ out[3] = (m[k*3+j] - m[j*3+k]) * fRoot;
+ out[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
+ out[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
+ }
+
+ return out;
+};
+
+/**
+ * Returns a string representation of a quatenion
+ *
+ * @param {quat} vec vector to represent as a string
+ * @returns {String} string representation of the vector
+ */
+quat.str = function (a) {
+ return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')';
+};
+
+/*
+if(typeof(exports) !== 'undefined') {
+ exports.quat = quat;
+}
+;*/
+
+
+
+
+
+
+
+
+
+
+
+
+/*
+ })(shim.exports);
+})(this);
+*/
diff --git a/examples/canvas3d/texturedcube/qml/texturedcube/main.qml b/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
new file mode 100644
index 0000000..6e8ff22
--- /dev/null
+++ b/examples/canvas3d/texturedcube/qml/texturedcube/main.qml
@@ -0,0 +1,165 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtCanvas3D 1.0
+
+//! [4]
+import "texturedcube.js" as GLCode
+//! [4]
+
+Item {
+ id: mainview
+ width: 1280
+ height: 768
+ visible: true
+
+ //! [0]
+ Canvas3D {
+ id: canvas3d
+ anchors.fill: parent
+ //! [0]
+ //! [2]
+ imageLoader: textureImageLoader
+ //! [2]
+ focus: true
+ property double xRotAnim: 0
+ property double yRotAnim: 0
+ property double zRotAnim: 0
+ property bool isRunning: true
+
+ //! [1]
+ // Called by Canvas 3D once on Scene Graph render thread
+ // to allow one time initializations to happen
+ function initGL() {
+ GLCode.initGL(canvas3d, textureImageLoader);
+ }
+
+ // Called by Canvas 3D for every frame
+ // rendered on Scene Graph render thread
+ function renderGL() {
+ GLCode.renderGL(canvas3d);
+ }
+ //! [1]
+
+ //! [5]
+ SequentialAnimation {
+ id: objAnimationX
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 0.0
+ to: 120.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "xRotAnim"
+ from: 120.0
+ to: 0.0
+ duration: 7000
+ easing.type: Easing.InOutQuad
+ }
+ }
+ //! [5]
+
+ SequentialAnimation {
+ id: objAnimationY
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 0.0
+ to: 240.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "yRotAnim"
+ from: 240.0
+ to: 0.0
+ duration: 5000
+ easing.type: Easing.InOutCubic
+ }
+ }
+
+ SequentialAnimation {
+ id: objAnimationZ
+ loops: Animation.Infinite
+ running: true
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: -100.0
+ to: 100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ NumberAnimation {
+ target: canvas3d
+ property: "zRotAnim"
+ from: 100.0
+ to: -100.0
+ duration: 3000
+ easing.type: Easing.InOutSine
+ }
+ }
+ }
+
+ //! [3]
+ TextureImageLoader {
+ id: textureImageLoader
+
+ function imageLoaded(textureImage) {
+ if (canvas3d.logAllCalls)
+ console.log("Texture loaded, size "+textureImage.width+"x"+textureImage.height);
+ GLCode.textureLoaded(textureImage);
+ }
+
+ function imageLoadingError(textureImage) {
+ if (GLCode.textureLoadError !== undefined) {
+ GLCode.textureLoadError(textureImage);
+ }
+ console.log("Texture load FAILED, "+textureImage.errorString);
+ }
+ }
+ //! [3]
+}
diff --git a/examples/canvas3d/texturedcube/qml/texturedcube/qtlogo_gray.png b/examples/canvas3d/texturedcube/qml/texturedcube/qtlogo_gray.png
new file mode 100644
index 0000000..301eb8b
--- /dev/null
+++ b/examples/canvas3d/texturedcube/qml/texturedcube/qtlogo_gray.png
Binary files differ
diff --git a/examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js b/examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js
new file mode 100644
index 0000000..a0e790f
--- /dev/null
+++ b/examples/canvas3d/texturedcube/qml/texturedcube/texturedcube.js
@@ -0,0 +1,326 @@
+Qt.include("glMatrix-0.9.5.min.js")
+
+//
+// Draws a cube that has the Qt logo texture on each face.
+// Each face also has a unique color that modulates the grayscale Qt logo.
+//
+
+var gl;
+var width = 0;
+var height = 0;
+var cubeTexture = 0;
+var mvMatrix = mat4.create();
+var pMatrix = mat4.create();
+
+var pMatrixUniform;
+var mvMatrixUniform;
+
+var vertexPositionAttribute;
+var textureCoordAttribute;
+var vertexColorAttribute;
+
+var canvas3d;
+
+function log(message) {
+ if (canvas3d.logAllCalls)
+ console.log(message)
+}
+
+//! [0]
+function initGL(canvas, textureLoader) {
+ canvas3d = canvas
+ log("*******************************************************************************************")
+ log("initGL ENTER...")
+
+ // Get the OpenGL context object that represents the API we call
+ gl = canvas.getContext("canvas3d", {depth:true, antialias:true});
+
+ // Setup the OpenGL state
+ gl.enable(gl.DEPTH_TEST);
+ gl.enable(gl.CULL_FACE);
+ gl.cullFace(gl.BACK);
+ gl.clearColor(0.0, 0.0, 0.0, 1.0);
+ gl.clearDepth(1.0);
+ gl.depthFunc(gl.LESS);
+
+ // Set the viewport
+ gl.viewport(0, 0, canvas.width, canvas.height);
+
+ // Initialize the shader program
+ initShaders();
+
+ // Initialize vertex and color buffers
+ initBuffers();
+
+ // Load the texture
+ textureLoader.loadImage("qrc:/qml/texturedcube/qtlogo_gray.png");
+
+ log("...initGL EXIT");
+ log("*******************************************************************************************");
+}
+//! [0]
+
+function textureLoaded(textureImage) {
+ log("textureLoaded ENTER {")
+
+ if (textureImage.imageState == TextureImage.LOADING_FINISHED && cubeTexture == 0) {
+ log(" processing "+textureImage.source);
+ cubeTexture = gl.createTexture();
+ gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+ gl.texImage2D(gl.TEXTURE_2D, // target
+ 0, // level
+ gl.RGBA, // internalformat
+ gl.RGBA, // format
+ gl.UNSIGNED_BYTE, // type
+ textureImage); // 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);
+ }
+
+ log("}");
+}
+
+function degToRad(degrees) {
+ return degrees * Math.PI / 180;
+}
+
+//! [1]
+function renderGL(canvas) {
+ log("*******************************************************************************************");
+ // Check if dimensions or device pixel ratio has changed
+ var pixelRatio = canvas.devicePixelRatio;
+ var currentWidth = canvas.width * pixelRatio;
+ var currentHeight = canvas.height * pixelRatio;
+ if (currentWidth !== width || currentHeight !== height ) {
+ width = currentWidth;
+ height = currentHeight;
+ mat4.perspective(pMatrix, degToRad(45), width / height, 0.1, 500.0);
+ gl.uniformMatrix4fva(pMatrixUniform, false, pMatrix);
+ }
+
+ // Clear the screen
+ gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
+
+ // Set and update the model matrix
+ mat4.identity(mvMatrix);
+ // Apply Canvas3D rotation properties to cube translation to make it move about a bit
+ mat4.translate(mvMatrix, mvMatrix, [(canvas.yRotAnim - 120.0) / 120.0,
+ (canvas.xRotAnim - 60.0) / 50.0,
+ -10.0]);
+ // Apply rotations gotten from Canvas3D properties
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.xRotAnim), [1, 0, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.yRotAnim), [0, 1, 0]);
+ mat4.rotate(mvMatrix, mvMatrix, degToRad(canvas.zRotAnim), [0, 0, 1]);
+ // Set the matrix to shader
+ gl.uniformMatrix4fva(mvMatrixUniform, false, mvMatrix);
+
+ // Draw the cube
+ gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_SHORT, 0);
+ log("*******************************************************************************************");
+}
+//! [1]
+
+function initBuffers()
+{
+ var cubeVertexPositionBuffer = gl.createBuffer();
+ cubeVertexPositionBuffer.name = "cubeVertexPositionBuffer";
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexPositionBuffer);
+ gl.bufferData(
+ gl.ARRAY_BUFFER,
+ Arrays.newFloat32Array([// 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);
+
+ var cubeVertexColorBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, cubeVertexColorBuffer);
+ var colors = [
+ [0.0, 1.0, 1.0, 1.0], // Front face: white
+ [1.0, 0.0, 0.0, 1.0], // Back face: red
+ [0.0, 1.0, 0.0, 1.0], // Top face: green
+ [0.0, 0.0, 1.0, 1.0], // Bottom face: blue
+ [1.0, 1.0, 0.0, 1.0], // Right face: yellow
+ [1.0, 0.0, 1.0, 1.0] // Left face: purple
+ ];
+ var generatedColors = [];
+ for (var j=0; j<6; j++) {
+ var c = colors[j];
+
+ for (var i=0; i<4; i++) {
+ generatedColors = generatedColors.concat(c);
+ }
+ }
+ gl.bufferData(gl.ARRAY_BUFFER, Arrays.newFloat32Array(generatedColors), gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(vertexColorAttribute);
+ gl.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ var cubeVerticesTextureCoordBuffer = gl.createBuffer();
+ 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, Arrays.newFloat32Array(textureCoordinates),
+ gl.STATIC_DRAW);
+ gl.enableVertexAttribArray(textureCoordAttribute);
+ gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ var cubeVertexIndexBuffer = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cubeVertexIndexBuffer);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,
+ Arrays.newUint16Array([
+ 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);
+
+ log(" } initBuffers EXIT")
+}
+
+function initShaders()
+{
+ log(" initShaders ENTER {")
+ var vertexShader = getShader(gl,"
+ attribute highp vec3 aVertexPosition;
+ attribute mediump vec4 aVertexColor;
+ attribute highp vec2 aTextureCoord;
+
+ uniform mat4 uMVMatrix;
+ uniform mat4 uPMatrix;
+
+ varying mediump vec4 vColor;
+ varying highp vec2 vTextureCoord;
+ varying highp vec4 vPos;
+
+ void main(void) {
+ vPos = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
+ vColor = aVertexColor;
+ vTextureCoord = aTextureCoord;
+ }", gl.VERTEX_SHADER);
+ var fragmentShader = getShader(gl,"
+ varying mediump vec4 vColor;
+ varying highp vec2 vTextureCoord;
+ varying highp vec4 vPos;
+
+ uniform sampler2D uSampler;
+
+ void main(void) {
+ gl_FragColor = vColor * texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
+ }", gl.FRAGMENT_SHADER);
+
+ var shaderProgram = gl.createProgram();
+ gl.attachShader(shaderProgram, vertexShader);
+ gl.attachShader(shaderProgram, fragmentShader);
+ gl.linkProgram(shaderProgram);
+ gl.deleteShader(vertexShader);
+ gl.deleteShader(fragmentShader);
+
+ 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);
+ vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
+ gl.enableVertexAttribArray(vertexColorAttribute);
+ textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
+ gl.enableVertexAttribArray(textureCoordAttribute);
+
+ pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
+ mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
+
+ var textureSamplerUniform = gl.getUniformLocation(shaderProgram, "uSampler")
+ gl.activeTexture(gl.TEXTURE0);
+ gl.bindTexture(gl.TEXTURE_2D, cubeTexture);
+ gl.uniform1i(textureSamplerUniform, 0);
+
+ log(" } initShaders EXIT");
+}
+
+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;
+}
diff --git a/examples/canvas3d/texturedcube/texturedcube.pro b/examples/canvas3d/texturedcube/texturedcube.pro
new file mode 100644
index 0000000..89a810f
--- /dev/null
+++ b/examples/canvas3d/texturedcube/texturedcube.pro
@@ -0,0 +1,11 @@
+!include( ../examples.pri ) {
+ error( "Couldn't find the examples.pri file!" )
+}
+
+SOURCES += main.cpp
+
+OTHER_FILES += qml/texturedcube/* \
+ doc/src/* \
+ doc/images/*
+
+RESOURCES += texturedcube.qrc
diff --git a/examples/canvas3d/texturedcube/texturedcube.qrc b/examples/canvas3d/texturedcube/texturedcube.qrc
new file mode 100644
index 0000000..2d42582
--- /dev/null
+++ b/examples/canvas3d/texturedcube/texturedcube.qrc
@@ -0,0 +1,8 @@
+<RCC>
+ <qresource prefix="/">
+ <file>qml/texturedcube/glMatrix-0.9.5.min.js</file>
+ <file>qml/texturedcube/main.qml</file>
+ <file>qml/texturedcube/texturedcube.js</file>
+ <file>qml/texturedcube/qtlogo_gray.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/examples.pro b/examples/examples.pro
new file mode 100644
index 0000000..1b5dfcf
--- /dev/null
+++ b/examples/examples.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += canvas3d
diff --git a/qtcanvas3d.pro b/qtcanvas3d.pro
new file mode 100644
index 0000000..0bcc16b
--- /dev/null
+++ b/qtcanvas3d.pro
@@ -0,0 +1,6 @@
+load(qt_parts)
+
+# We need opengl, minimum es2
+contains(QT_CONFIG, opengles1) {
+ error("QtCanvas3D does not support OpenGL ES 1!")
+}
diff --git a/src/abstractobject3d.cpp b/src/abstractobject3d.cpp
new file mode 100644
index 0000000..abf3dda
--- /dev/null
+++ b/src/abstractobject3d.cpp
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "abstractobject3d_p.h"
+
+CanvasAbstractObject::CanvasAbstractObject(QObject *parent) :
+ QObject(parent)
+{
+ m_name = QString("0x%1").arg((long long) this, 0, 16);
+}
+
+CanvasAbstractObject::~CanvasAbstractObject()
+{
+}
+
+void CanvasAbstractObject::setName(const QString &name)
+{
+ if (m_name == name)
+ return;
+
+ m_name = name;
+
+ emit nameChanged(m_name);
+}
+
+const QString &CanvasAbstractObject::name()
+{
+ return m_name;
+}
diff --git a/src/abstractobject3d_p.h b/src/abstractobject3d_p.h
new file mode 100644
index 0000000..05cde24
--- /dev/null
+++ b/src/abstractobject3d_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef ABSTRACTOBJECT3D_P_H
+#define ABSTRACTOBJECT3D_P_H
+
+#include <QObject>
+#include <QThread>
+
+class CanvasAbstractObject : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
+
+public:
+ explicit CanvasAbstractObject(QObject *parent = 0);
+ virtual ~CanvasAbstractObject();
+
+ void setName(const QString &name);
+ const QString &name();
+
+signals:
+ void nameChanged(const QString &name);
+
+protected:
+ QString m_name;
+};
+
+#endif // ABSTRACTOBJECT3D_P_H
diff --git a/src/arraybuffer.cpp b/src/arraybuffer.cpp
new file mode 100644
index 0000000..3b35b7c
--- /dev/null
+++ b/src/arraybuffer.cpp
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype ArrayBuffer
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains an array buffer.
+ *
+ * An uncreatable QML type that contains an array buffer.
+ */
+
+/*!
+ * \internal
+ */
+CanvasArrayBuffer::CanvasArrayBuffer(QObject *parent) :
+ QObject(parent),
+ m_length(0),
+ m_rawData(0)
+{
+}
+
+/*!
+ * \internal
+ */
+CanvasArrayBuffer::CanvasArrayBuffer(unsigned long length, QObject *parent) :
+ QObject(parent),
+ m_length(length),
+ m_rawData(0)
+{
+ if (length > 0) {
+ m_rawData = new unsigned char[length];
+ for (unsigned long i = 0; i < length; i++)
+ m_rawData[i] = 0;
+ }
+ emit byteLengthChanged(length);
+}
+
+/*!
+ * \internal
+ */
+CanvasArrayBuffer::~CanvasArrayBuffer()
+{
+ delete m_rawData;
+}
+
+/*!
+ * \internal
+ */
+unsigned char *CanvasArrayBuffer::rawData()
+{
+ return m_rawData;
+}
+
+/*!
+ * \internal
+ */
+void CanvasArrayBuffer::copyRawDataFrom(unsigned char *rawData, unsigned long byteLength)
+{
+ if (m_length != byteLength) {
+ delete m_rawData;
+ m_rawData = 0;
+ m_length = 0;
+ }
+
+ m_rawData = new unsigned char[byteLength];
+ m_length = byteLength;
+
+ for (unsigned long i = 0; i < byteLength; i++)
+ m_rawData[i] = rawData[i];
+}
+
+/*!
+ * \qmlproperty int ArrayBuffer::byteLength()
+ * Contains the length of the array in bytes.
+ */
+/*!
+ * \internal
+ */
+unsigned long CanvasArrayBuffer::byteLength() const
+{
+ return m_length;
+}
+
+/*!
+ * \qmlmethod ArrayBuffer ArrayBuffer::slice(int begin)
+ * Returns a new ArrayBuffer that is a copy of this ArrayBuffer's bytes from the \a begin to the
+ * end of the buffer.
+ */
+/*!
+ * \internal
+ */
+CanvasArrayBuffer *CanvasArrayBuffer::slice(long begin)
+{
+ return slice(begin, m_length);
+}
+
+/*!
+ * \qmlmethod ArrayBuffer ArrayBuffer::slice(int begin, int end)
+ * Returns a new ArrayBuffer that is a copy of this ArrayBuffer's bytes from the \a begin to the
+ * \a end.
+ */
+/*!
+ * \internal
+ */
+CanvasArrayBuffer *CanvasArrayBuffer::slice(long begin, long end)
+{
+ if (begin < 0)
+ begin = m_length + begin - 1;
+ if (end < 0)
+ end = m_length + end - 1;
+ long length = end - begin;
+
+ if (length <= 0)
+ return new CanvasArrayBuffer(0, 0);
+
+ CanvasArrayBuffer *newBuffer = new CanvasArrayBuffer(length);
+ for (long i = 0; i < length; i++)
+ newBuffer->m_rawData[i] = m_rawData[i + begin];
+ return newBuffer;
+}
+
+/*!
+ * \qmlmethod bool ArrayBuffer::isView(Object value)
+ * Returns \c true if \a value is ArrayBufferView and \c false otherwise.
+ */
+/*!
+ * \internal
+ */
+bool CanvasArrayBuffer::isView(const QObject &value)
+{
+ QString className = QString(value.metaObject()->className());
+ return (className == "CanvasInt8Array" ||
+ className == "CanvasUint8Array" ||
+ className == "CanvasUint8ClampedArray" ||
+ className == "CanvasInt16Array" ||
+ className == "CanvasUint16Array" ||
+ className == "CanvasInt32Array" ||
+ className == "CanvasUint32Array" ||
+ className == "CanvasFloat32Array" ||
+ className == "CanvasFloat64Array");
+}
diff --git a/src/arraybuffer_p.h b/src/arraybuffer_p.h
new file mode 100644
index 0000000..0f5bd5f
--- /dev/null
+++ b/src/arraybuffer_p.h
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef ARRAYBUFFER_P_H
+#define ARRAYBUFFER_P_H
+
+#include <QObject>
+
+class CanvasArrayBuffer : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CanvasArrayBuffer)
+ Q_PROPERTY(unsigned long byteLength READ byteLength NOTIFY byteLengthChanged)
+
+public:
+ explicit CanvasArrayBuffer(QObject *parent = 0);
+ explicit CanvasArrayBuffer(unsigned long length, QObject *parent = 0);
+ ~CanvasArrayBuffer();
+
+ unsigned long byteLength() const;
+ Q_INVOKABLE CanvasArrayBuffer *slice(long begin);
+ Q_INVOKABLE CanvasArrayBuffer *slice(long begin, long end);
+ Q_INVOKABLE bool isView(const QObject &value);
+
+ void copyRawDataFrom(unsigned char *rawData, unsigned long byteLength);
+
+signals:
+ void byteLengthChanged(unsigned long byteLength);
+
+public slots:
+
+private:
+ unsigned char *rawData();
+
+ unsigned long m_length;
+ unsigned char *m_rawData;
+
+ // Only the type based views have access to the modifiable rawData
+ friend class CanvasInt8Array;
+ friend class CanvasUint8Array;
+ friend class CanvasInt16Array;
+ friend class CanvasUint16Array;
+ friend class CanvasInt32Array;
+ friend class CanvasUint32Array;
+ friend class CanvasFloat32Array;
+ friend class CanvasFloat64Array;
+ friend class CanvasUint8ClampedArray;
+ friend class CanvasArrayBufferView;
+ friend class CanvasTypedArray;
+ friend class CanvasContext;
+};
+
+#endif // ARRAYBUFFER_P_H
diff --git a/src/arraybufferview.cpp b/src/arraybufferview.cpp
new file mode 100644
index 0000000..7679c22
--- /dev/null
+++ b/src/arraybufferview.cpp
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "arraybufferview_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype ArrayBufferView
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains an array buffer view.
+ *
+ * An uncreatable QML type that contains a particular view to the data of an ArrayBuffer.
+ */
+
+/*!
+ * \internal
+ */
+CanvasArrayBufferView::CanvasArrayBufferView(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasAbstractObject(parent),
+ m_buffer(buffer),
+ m_byteOffset(byteOffset)
+{
+ if (m_buffer)
+ m_buffer->setParent(this);
+}
+
+/*!
+ * \internal
+ */
+CanvasArrayBufferView::~CanvasArrayBufferView()
+{
+ delete m_buffer;
+}
+
+/*!
+ * \internal
+ */
+unsigned char* CanvasArrayBufferView::rawDataCptr() const
+{
+ if (!m_buffer)
+ return 0;
+
+ return m_buffer->m_rawData;
+}
+
+/*!
+ * \qmlproperty int ArrayBufferView::byteOffset()
+ * Contains the offset from the start of the ArrayBuffer of the view in bytes.
+ */
+/*!
+ * \internal
+ */
+unsigned long CanvasArrayBufferView::byteOffset()
+{
+ if (m_buffer)
+ return m_byteOffset;
+
+ return 0;
+}
+
+/*!
+ * \qmlproperty int ArrayBufferView::byteLength()
+ * Contains the length of the view in bytes.
+ */
+/*!
+ * \internal
+ */
+unsigned long CanvasArrayBufferView::byteLength()
+{
+ if (m_buffer)
+ return m_buffer->byteLength();
+
+ return 0;
+}
+
+/*!
+ * \qmlproperty ArrayBuffer ArrayBufferView::buffer()
+ * Contains the ArrayBuffer of the view.
+ */
+/*!
+ * \internal
+ */
+CanvasArrayBuffer *CanvasArrayBufferView::buffer()
+{
+ return m_buffer;
+}
diff --git a/src/arraybufferview_p.h b/src/arraybufferview_p.h
new file mode 100644
index 0000000..5e33347
--- /dev/null
+++ b/src/arraybufferview_p.h
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef ARRAYBUFFERVIEW_P_H
+#define ARRAYBUFFERVIEW_P_H
+
+#include "context3d_p.h"
+#include "abstractobject3d_p.h"
+
+class CanvasArrayBuffer;
+
+class CanvasArrayBufferView : public CanvasAbstractObject
+{
+ Q_OBJECT
+ Q_PROPERTY(CanvasArrayBuffer* buffer READ buffer NOTIFY bufferChanged)
+ Q_PROPERTY(unsigned long byteOffset READ byteOffset NOTIFY byteOffsetChanged)
+ Q_PROPERTY(unsigned long byteLength READ byteLength NOTIFY byteLengthChanged)
+
+public:
+ explicit CanvasArrayBufferView(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+ virtual ~CanvasArrayBufferView();
+
+ unsigned char* rawDataCptr() const;
+
+ CanvasArrayBuffer *buffer();
+ unsigned long byteOffset();
+ unsigned long byteLength();
+
+signals:
+ void bufferChanged(CanvasArrayBuffer *buffer);
+ void byteOffsetChanged(unsigned long byteLength);
+ void byteLengthChanged(unsigned long byteLength);
+
+protected:
+ CanvasArrayBuffer *m_buffer;
+ unsigned long m_byteOffset;
+};
+
+#endif // ARRAYBUFFERVIEW_P_H
diff --git a/src/arrayutils.cpp b/src/arrayutils.cpp
new file mode 100644
index 0000000..49282a8
--- /dev/null
+++ b/src/arrayutils.cpp
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "arrayutils_p.h"
diff --git a/src/arrayutils_p.h b/src/arrayutils_p.h
new file mode 100644
index 0000000..d035866
--- /dev/null
+++ b/src/arrayutils_p.h
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef ARRAYUTILS_P_H
+#define ARRAYUTILS_P_H
+
+#include "typedarray_p.h"
+#include "int8array_p.h"
+#include "uint8array_p.h"
+#include "int16array_p.h"
+#include "uint16array_p.h"
+#include "int32array_p.h"
+#include "uint32array_p.h"
+#include "float32array_p.h"
+#include "float64array_p.h"
+#include "uint8clampedarray_p.h"
+
+// Contains static template functions used by the TypedArray classes.
+class ArrayUtils
+{
+public:
+ template<typename T>
+ static bool copyToTarget(T* targetArray, CanvasTypedArray *sourceArray, unsigned long length)
+ {
+ CanvasInt8Array *int8Source = qobject_cast<CanvasInt8Array*>(sourceArray);
+ CanvasUint8Array *uint8Source = qobject_cast<CanvasUint8Array*>(sourceArray);
+ CanvasUint8ClampedArray *uint8ClampedSource = qobject_cast<CanvasUint8ClampedArray*>(sourceArray);
+ CanvasInt16Array *int16Source = qobject_cast<CanvasInt16Array*>(sourceArray);
+ CanvasUint16Array *uint16Source = qobject_cast<CanvasUint16Array*>(sourceArray);
+ CanvasInt32Array *int32Source = qobject_cast<CanvasInt32Array*>(sourceArray);
+ CanvasUint32Array *uint32Source = qobject_cast<CanvasUint32Array*>(sourceArray);
+ CanvasFloat32Array *float32Source = qobject_cast<CanvasFloat32Array*>(sourceArray);
+ CanvasFloat64Array *float64Source = qobject_cast<CanvasFloat64Array*>(sourceArray);
+ if (int8Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(int8Source->get(idx));
+ }
+ } else if (uint8Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(uint8Source->get(idx));
+ }
+ } else if (uint8ClampedSource) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(uint8ClampedSource->get(idx));
+ }
+ } else if (int16Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(int16Source->get(idx));
+ }
+ } else if (uint16Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(uint16Source->get(idx));
+ }
+ } else if (int32Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(int32Source->get(idx));
+ }
+ } else if (uint32Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(uint32Source->get(idx));
+ }
+ } else if (float32Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(float32Source->get(idx));
+ }
+ } else if (float64Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (T)(float64Source->get(idx));
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ static bool copyToTargetClampedByte(unsigned char *targetArray, CanvasTypedArray *sourceArray,
+ unsigned long length)
+ {
+ CanvasInt8Array *int8Source = qobject_cast<CanvasInt8Array*>(sourceArray);
+ CanvasUint8Array *uint8Source = qobject_cast<CanvasUint8Array*>(sourceArray);
+ CanvasUint8ClampedArray *uint8ClampedSource = qobject_cast<CanvasUint8ClampedArray*>(sourceArray);
+ CanvasInt16Array *int16Source = qobject_cast<CanvasInt16Array*>(sourceArray);
+ CanvasUint16Array *uint16Source = qobject_cast<CanvasUint16Array*>(sourceArray);
+ CanvasInt32Array *int32Source = qobject_cast<CanvasInt32Array*>(sourceArray);
+ CanvasUint32Array *uint32Source = qobject_cast<CanvasUint32Array*>(sourceArray);
+ CanvasFloat32Array *float32Source = qobject_cast<CanvasFloat32Array*>(sourceArray);
+ CanvasFloat64Array *float64Source = qobject_cast<CanvasFloat64Array*>(sourceArray);
+ if (int8Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (unsigned char)(int8Source->get(idx));
+ }
+ } else if (uint8Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = (unsigned char)(uint8Source->get(idx));
+ }
+ } else if (uint8ClampedSource) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ targetArray[idx] = uint8ClampedSource->get(idx);
+ }
+ } else if (int16Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ short value = int16Source->get(idx);
+ if (value < 0)
+ value = 0;
+ if (value > 255)
+ value = 255;
+ targetArray[idx] = (unsigned char) value;
+ }
+ } else if (uint16Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ unsigned short value = uint16Source->get(idx);
+ if (value > 255)
+ value = 255;
+ targetArray[idx] = (unsigned char) value;
+ }
+ } else if (int32Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ int value = int32Source->get(idx);
+ if (value < 0)
+ value = 0;
+ if (value > 255)
+ value = 255;
+ targetArray[idx] = (unsigned char) value;
+ }
+ } else if (uint32Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ unsigned int value = uint32Source->get(idx);
+ if (value > 255)
+ value = 255;
+ targetArray[idx] = (unsigned char) value;
+ }
+ } else if (float32Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ float value = float32Source->get(idx);
+ if (value < 0)
+ value = 0;
+ if (value > 255)
+ value = 255;
+ targetArray[idx] = (unsigned char) value;
+ }
+ } else if (float64Source) {
+ for (unsigned long idx = 0; idx < length; idx++) {
+ double value = float64Source->get(idx);
+ if (value < 0)
+ value = 0;
+ if (value > 255)
+ value = 255;
+ targetArray[idx] = (unsigned char) value;
+ }
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ static void fillFloatArrayFromVariantList(const QVariantList &list, float *outArray)
+ {
+ int idx = 0;
+ for (QVariantList::const_iterator it = list.begin(); it != list.end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<float>()) {
+ outArray[idx] = element.toFloat();
+ }
+ else {
+ // Conversion failed, use 0.0 as default value
+ outArray[idx] = 0.f;
+ }
+ idx++;
+ }
+ }
+
+ static void fillIntArrayFromVariantList(const QVariantList &list, int *outArray)
+ {
+ int idx = 0;
+ for (QVariantList::const_iterator it = list.begin(); it != list.end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<int>()) {
+ outArray[idx] = element.toInt();
+ }
+ else {
+ // Conversion failed, use 0.0 as default value
+ outArray[idx] = 0;
+ }
+ idx++;
+ }
+ }
+};
+
+#endif // ARRAYUTILS_P_H
diff --git a/src/buffer3d.cpp b/src/buffer3d.cpp
new file mode 100644
index 0000000..576f4a7
--- /dev/null
+++ b/src/buffer3d.cpp
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "buffer3d_p.h"
+#include "typedarray_p.h"
+
+#include <QDebug>
+#include <QString>
+
+/*!
+ * \qmltype Buffer3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains an OpenGL buffer.
+ *
+ * An uncreatable QML type that contains an OpenGL buffer. You can get it by calling
+ * \l{Context3D::createBuffer()}{Context3D.createBuffer()} method.
+ */
+
+/*!
+ * \internal
+ */
+CanvasBuffer::CanvasBuffer(QObject *parent) :
+ CanvasAbstractObject(parent),
+ m_bindTarget(CanvasBuffer::UNINITIALIZED)
+{
+ initializeOpenGLFunctions();
+ glGenBuffers(1, &m_bufferId);
+}
+
+/*!
+ * \internal
+ */
+CanvasBuffer::~CanvasBuffer()
+{
+ // Crashes on exit as V4VM does it's final cleanup without checking of ownerships
+ del();
+}
+
+/*!
+ * \internal
+ */
+void CanvasBuffer::del()
+{
+ if (m_bufferId)
+ glDeleteBuffers(1, &m_bufferId);
+ m_bufferId = 0;
+}
+
+/*!
+ * \internal
+ */
+bool CanvasBuffer::isAlive()
+{
+ return m_bufferId;
+}
+
+/*!
+ * \internal
+ */
+CanvasBuffer::bindTarget CanvasBuffer::target()
+{
+ return m_bindTarget;
+}
+
+/*!
+ * \internal
+ */
+void CanvasBuffer::setTarget(bindTarget bindPoint)
+{
+ //Q_ASSERT(m_bindTarget == Buffer3D::UNINITIALIZED);
+
+ m_bindTarget = bindPoint;
+}
+
+/*!
+ * \internal
+ */
+GLuint CanvasBuffer::id()
+{
+ return m_bufferId;
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasBuffer *buffer)
+{
+ if (buffer)
+ dbg.nospace() << "Buffer3D("<< buffer->m_name <<", id:" << buffer->m_bufferId << ")";
+ else
+ dbg.nospace() << "Buffer3D("<< ((void*) buffer) <<")";
+ return dbg.maybeSpace();
+}
diff --git a/src/buffer3d_p.h b/src/buffer3d_p.h
new file mode 100644
index 0000000..7f808cf
--- /dev/null
+++ b/src/buffer3d_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef BUFFER3D_P_H
+#define BUFFER3D_P_H
+
+#include "context3d_p.h"
+#include "abstractobject3d_p.h"
+
+#include <QOpenGLFunctions>
+
+class CanvasBuffer : public CanvasAbstractObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ enum bindTarget {
+ UNINITIALIZED = 0,
+ ARRAY_BUFFER,
+ ELEMENT_ARRAY_BUFFER
+ };
+
+ explicit CanvasBuffer(QObject *parent = 0);
+ virtual ~CanvasBuffer();
+
+ void del();
+ bool isAlive();
+ GLuint id();
+ bindTarget target();
+ void setTarget(bindTarget bindPoint);
+
+ friend QDebug operator<< (QDebug d, const CanvasBuffer *buffer);
+
+private:
+ GLuint m_bufferId;
+ bindTarget m_bindTarget;
+};
+
+#endif // BUFFER3D_P_H
diff --git a/src/canvas3d.cpp b/src/canvas3d.cpp
new file mode 100644
index 0000000..46bcdeb
--- /dev/null
+++ b/src/canvas3d.cpp
@@ -0,0 +1,696 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "canvas3d_p.h"
+#include "context3d_p.h"
+#include "typedarray_p.h"
+#include "uint32array_p.h"
+#include "arraybuffer_p.h"
+#include "canvas3dcommon_p.h"
+#include "canvasrendernode_p.h"
+
+#include <QGuiApplication>
+#include <QtGui/QOffscreenSurface>
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFramebufferObject>
+
+static QList<const QQuickWindow *> staticClearList;
+static QHash<Canvas *, QQuickWindow *> canvasWindowList;
+static QHash<QQuickWindow *, bool> windowClearList;
+
+/*!
+ * \qmltype Canvas3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Canvas that provides a 3D rendering context.
+ *
+ * The Canvas3D is a QML element that, when placed in your Qt Quick 2 scene, allows you to
+ * get a 3D rendering context and call 3D rendering API calls through that context object.
+ * Use of the rendering API requires knowledge of OpenGL like rendering APIs.
+ *
+ * There are two functions that are called by the Canvas3D implementation:
+ * \list
+ * \li initGL() method is called before first frame is rendered and usually during that you get
+ * the 3D context and initialize resources to be used later on during the rendering cycle.
+ * \li renderGL() method is called for each frame to be rendered and usually during that you
+ * submit 3D rendering calls to draw whatever 3D content you want to be displayed.
+ * \endlist
+ *
+ * \sa Context3D, {QML Canvas 3D QML Types}
+ */
+
+/*!
+ * \internal
+ */
+Canvas::Canvas(QQuickItem *parent):
+ QQuickItem(parent),
+ m_renderNodeReady(false),
+ m_logAllCalls(false),
+ m_logAllErrors(true),
+ m_mainThread(QThread::currentThread()),
+ m_contextThread(0),
+ m_context3D(0),
+ m_isFirstRender(true),
+ m_glContext(0),
+ m_glContextQt(0),
+ m_contextWindow(0),
+ #if defined(QT_OPENGL_ES_2)
+ m_maxSamples(0),
+ #else
+ m_maxSamples(4),
+ #endif
+ m_samples(0),
+ m_isAnimated(false),
+ m_devicePixelRatio(1.0f),
+ m_imageLoader(0),
+ m_isContextAttribsSet(false),
+ m_antialiasFbo(0),
+ m_renderFbo(0),
+ m_displayFbo(0)
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+ connect(this, &QQuickItem::windowChanged, this, &Canvas::handleWindowChanged);
+ setAntialiasing(false);
+
+ // Set contents to false in case we are in qml designer to make component look nice
+ m_runningInDesigner = QGuiApplication::applicationDisplayName() == "Qml2Puppet";
+ setFlag(ItemHasContents, !m_runningInDesigner);
+}
+
+/*!
+ * \internal
+ */
+Canvas::~Canvas()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+ shutDown();
+}
+
+/*!
+ * \internal
+ */
+void Canvas::shutDown()
+{
+ if (!m_glContext)
+ return;
+
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+
+ disconnect(m_contextWindow, 0, this, 0);
+ disconnect(this, 0, this, 0);
+
+ if (m_logAllCalls) qDebug() << QOpenGLContext::currentContext() << m_glContext << m_glContextQt;
+
+ m_glContext->makeCurrent(m_offscreenSurface);
+ delete m_renderFbo;
+ delete m_displayFbo;
+ delete m_antialiasFbo;
+ delete m_context3D;
+ m_glContext->doneCurrent();
+
+ if (m_logAllCalls) qDebug() << m_contextThread << m_mainThread;
+
+ if (m_contextThread && m_contextThread != m_mainThread)
+ m_glContext->deleteLater();
+ else
+ delete m_glContext;
+ m_glContext = 0;
+
+ // schedule this to be deleted only after we're done cleaning up
+ m_offscreenSurface->deleteLater();
+
+ m_glContextQt = 0;
+}
+
+/*!
+ * \qmlproperty bool Canvas3D::logAllCalls
+ * Specifies if all Canvas3D method calls (including internal ones) are logged to the console.
+ * Defaults to \c{false}.
+ */
+void Canvas::setLogAllCalls(bool logCalls)
+{
+ if (m_logAllCalls != logCalls) {
+ m_logAllCalls = logCalls;
+ emit logAllCallsChanged(logCalls);
+ }
+}
+
+bool Canvas::logAllCalls() const
+{
+ return m_logAllCalls;
+}
+
+/*!
+ * \qmlproperty bool Canvas3D::logAllErrors
+ * Specifies if all Canvas3D errors are logged to the console. Defaults to \c{true}.
+ */
+void Canvas::setLogAllErrors(bool logErrors)
+{
+ if (m_logAllErrors != logErrors) {
+ m_logAllErrors = logErrors;
+ emit logAllErrorsChanged(logErrors);
+ }
+}
+
+bool Canvas::logAllErrors() const
+{
+ return m_logAllErrors;
+}
+
+/*!
+ * \qmlsignal Canvas3D::needRender()
+ * This signal, if emitted, causes a re-rendering cycle to happen. Usually this is needed
+ * if a value that affects the look of the 3D scene has changed, but no other mechanism
+ * triggers the re-render cycle.
+ */
+/*!
+ * \fn Canvas::needRender()
+ * \internal
+ */
+
+/*!
+ * \qmlsignal Canvas3D::initGLCalled()
+ * Emitted after initGL has been called.
+ */
+/*!
+ * \fn Canvas::initGLCalled()
+ * \internal
+ */
+
+/*!
+ * \qmlsignal Canvas3D::textureReady(int id, size size, float devicePixelRatio)
+ * Emitted when a new texture is ready to inform the render node.
+ */
+/*!
+ * \fn Canvas::textureReady(int id, const QSize &size, float devicePixelRatio)
+ * \internal
+ */
+
+/*!
+ * \qmlproperty float Canvas3D::devicePixelRatio
+ * Specifies the ratio between logical pixels (used by the Qt Quick) and actual physical
+ * on-screen pixels (used by the 3D rendering).
+ */
+float Canvas::devicePixelRatio()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+ QQuickWindow *win = window();
+ if (win)
+ return win->devicePixelRatio();
+ else
+ return 1.0f;
+}
+
+/*!
+ * \qmlmethod Context3D Canvas3D::getContext(string type)
+ * Returns the 3D rendering context that allows 3D rendering calls to be made.
+ * The \a type parameter is ignored for now, but a string is expected to be given.
+ */
+/*!
+ * \internal
+ */
+CanvasContext *Canvas::getContext(const QString &type)
+{
+ QVariantMap map;
+ return getContext(type, map);
+}
+
+/*!
+ * \qmlmethod Context3D Canvas3D::getContext(string type, ContextAttributes options)
+ * Returns the 3D rendering context that allows 3D rendering calls to be made.
+ * The \a type parameter is ignored for now, but a string is expected to be given.
+ * The \a options parameter is only parsed when the first call to getContext() is
+ * made and is ignored in subsequent calls if given. If the first call is made without
+ * giving the \a options parameter, then the context and render target is initialized with
+ * default configuration.
+ *
+ * \sa ContextAttributes, Context3D
+ */
+/*!
+ * \internal
+ */
+CanvasContext *Canvas::getContext(const QString &type, const QVariantMap &options)
+{
+ Q_UNUSED(type);
+
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "(" << type << ", " << options << ")";
+
+ if (!m_isContextAttribsSet) {
+ m_isContextAttribsSet = true;
+ m_contextAttribs.setFrom(options);
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Attribs:" << m_contextAttribs;
+
+ // If we can't do antialiasing, ensure we don't even try to enable it
+ if (m_maxSamples == 0)
+ m_contextAttribs.setAntialias(false);
+
+ // Ensure ignored attributes are left to their default state
+ m_contextAttribs.setAlpha(false);
+ m_contextAttribs.setPremultipliedAlpha(false);
+ m_contextAttribs.setPreserveDrawingBuffer(false);
+ m_contextAttribs.setPreferLowPowerToHighPerformance(false);
+ m_contextAttribs.setFailIfMajorPerformanceCaveat(false);
+ }
+
+ if (!m_context3D) {
+ updateWindowParameters();
+
+ // Initialize the swap buffer chain
+ QOpenGLFramebufferObjectFormat format;
+ if (m_contextAttribs.depth() && m_contextAttribs.stencil() && !m_contextAttribs.antialias())
+ format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ else if (m_contextAttribs.depth() && !m_contextAttribs.antialias())
+ format.setAttachment(QOpenGLFramebufferObject::Depth);
+ else if (m_contextAttribs.stencil() && !m_contextAttribs.antialias())
+ format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ else
+ format.setAttachment(QOpenGLFramebufferObject::NoAttachment);
+
+ QOpenGLFramebufferObjectFormat antialiasFboFormat;
+ if (m_contextAttribs.antialias()) {
+ antialiasFboFormat.setSamples(m_maxSamples);
+
+ if (m_contextAttribs.depth() && m_contextAttribs.stencil())
+ antialiasFboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ else if (m_contextAttribs.depth())
+ antialiasFboFormat.setAttachment(QOpenGLFramebufferObject::Depth);
+ else if (m_contextAttribs.stencil())
+ antialiasFboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
+ else
+ antialiasFboFormat.setAttachment(QOpenGLFramebufferObject::NoAttachment);
+ }
+
+ QSurfaceFormat surfaceFormat = m_glContextQt->format();
+ surfaceFormat.setSwapBehavior(QSurfaceFormat::SingleBuffer);
+ surfaceFormat.setSwapInterval(0);
+
+ if (m_contextAttribs.antialias())
+ surfaceFormat.setSamples(m_maxSamples);
+ else
+ surfaceFormat.setSamples(0);
+
+ if (m_contextAttribs.alpha())
+ surfaceFormat.setAlphaBufferSize(8);
+ else
+ surfaceFormat.setAlphaBufferSize(0);
+
+ if (m_contextAttribs.depth())
+ surfaceFormat.setDepthBufferSize(24);
+
+ // Ensure
+ if (m_contextAttribs.stencil())
+ surfaceFormat.setStencilBufferSize(8);
+ else
+ surfaceFormat.setStencilBufferSize(-1);
+
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " QOpenGLContext with surfaceFormat :" << surfaceFormat;
+
+ m_contextWindow = window();
+ m_contextThread = QThread::currentThread();
+ m_glContext = new QOpenGLContext();
+ m_glContext->setFormat(surfaceFormat);
+ m_glContext->setShareContext(m_glContextQt);
+ m_glContext->create();
+
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " QOffscreenSurface with surfaceFormat :" << surfaceFormat;
+
+ m_offscreenSurface = new QOffscreenSurface();
+ m_offscreenSurface->setFormat(m_glContext->format());
+ m_offscreenSurface->create();
+
+ m_glContext->makeCurrent(m_offscreenSurface);
+
+ // Initialize OpenGL functions using the created GL context
+ initializeOpenGLFunctions();
+
+ // Create the FBOs
+ QOpenGLFramebufferObjectFormat fmt = format;
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Creating FBO's with attachment format of :" << fmt.attachment();
+ m_displayFbo = new QOpenGLFramebufferObject(m_initialisedSize, fmt);
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " m_displayFbo handle:" << m_displayFbo->handle() << " isValid" << m_displayFbo->isValid();
+
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Creating FBO's with attachment format of :" << format.attachment();
+ m_renderFbo = new QOpenGLFramebufferObject(m_initialisedSize, format);
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " m_renderFbo handle:" << m_renderFbo->handle() << " isValid" << m_renderFbo->isValid();
+ m_renderFbo->bind();
+
+ if (m_contextAttribs.antialias()) {
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Creating MSAA buffer with samples:" << antialiasFboFormat.samples() << "and attachment format of :" << antialiasFboFormat.attachment();
+ m_antialiasFbo = new QOpenGLFramebufferObject(m_initialisedSize, antialiasFboFormat);
+ }
+
+ m_context3D = new CanvasContext(m_glContext, m_initialisedSize.width() * m_devicePixelRatio,
+ m_initialisedSize.height() * m_devicePixelRatio);
+ m_context3D->setCanvas(this);
+ m_context3D->setDevicePixelRatio(m_devicePixelRatio);
+ m_context3D->setContextAttributes(m_contextAttribs);
+
+ emit contextChanged(m_context3D);
+ }
+
+ return m_context3D;
+}
+
+/*!
+ * \internal
+ */
+GLuint Canvas::drawFBOHandle()
+{
+ GLuint fbo = 0;
+ if (m_renderFbo)
+ fbo = m_renderFbo->handle();
+
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "():" << fbo;
+
+ return fbo;
+}
+
+/*!
+ * \internal
+ */
+void Canvas::handleWindowChanged(QQuickWindow *window)
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "(" << window << ")";
+ if (!window)
+ return;
+
+ QMetaObject::invokeMethod(this, "renderNext", Qt::QueuedConnection);
+}
+
+/*!
+ * \internal
+ */
+void Canvas::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+
+ m_cachedGeometry = newGeometry;
+
+ QMetaObject::invokeMethod(this, "renderNext", Qt::QueuedConnection);
+}
+
+/*!
+ * \internal
+ */
+void Canvas::itemChange(ItemChange change, const ItemChangeData &value)
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << change;
+ QQuickItem::itemChange(change, value);
+
+ QMetaObject::invokeMethod(this, "renderNext", Qt::QueuedConnection);
+}
+
+/*!
+ * \internal
+ */
+CanvasContext *Canvas::context()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "()";
+ return m_context3D;
+}
+
+/*!
+ * \qmlproperty TextureImageLoader Canvas3D::imageLoader
+ * Specifies the texture image loader that can be used to load images and used with the Context3D
+ * texture methods.
+ * \sa Context3D, TextureImageLoader
+ */
+/*!
+ * \internal
+ */
+CanvasTextureImageLoader *Canvas::imageLoader()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+ return m_imageLoader;
+}
+
+void Canvas::setImageLoader(CanvasTextureImageLoader *loader)
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "(loader: " << loader << ")";
+ if (loader == m_imageLoader)
+ return;
+
+ m_imageLoader = loader;
+ loader->setCanvas(this);
+
+ emit imageLoaderChanged(loader);
+}
+
+/*!
+ \qmlproperty bool Canvas3D::animated
+ Specifies whether the Canvas3D continuously calls the \c renderGL() method to render new
+ frames or not. In most cases this property should be set to true as the 3D content is
+ dynamic.
+ */
+void Canvas::setAnimated(bool animated)
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+ if (animated != m_isAnimated) {
+ m_isAnimated = animated;
+ emit animatedChanged(animated);
+ QMetaObject::invokeMethod(this, "renderNext", Qt::QueuedConnection);
+ }
+}
+
+bool Canvas::isAnimated()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+ return m_isAnimated;
+}
+
+/*!
+ * \internal
+ */
+void Canvas::updateWindowParameters()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+
+ // Update the device pixel ratio, window size and bounding box
+ QQuickWindow *win = window();
+
+ if (win) {
+ qreal pixelRatio = win->devicePixelRatio();
+ if (pixelRatio != m_devicePixelRatio) {
+ m_devicePixelRatio = pixelRatio;
+ emit devicePixelRatioChanged(pixelRatio);
+ win->update();
+ }
+ }
+
+ if (m_context3D) {
+ if (m_context3D->devicePixelRatio() != m_devicePixelRatio)
+ m_context3D->setDevicePixelRatio(m_devicePixelRatio);
+ }
+}
+
+/*!
+ * \internal
+ */
+void Canvas::ready()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+
+ connect(window(), &QQuickWindow::sceneGraphInvalidated,
+ this, &Canvas::shutDown,
+ Qt::QueuedConnection);
+
+ update();
+}
+
+/*!
+ * \internal
+ */
+QSGNode *Canvas::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *data)
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << "("<<oldNode<<", " << data << ")";
+ updateWindowParameters();
+ m_initialisedSize = boundingRect().size().toSize() * m_devicePixelRatio;
+ if (m_logAllCalls) qDebug() << " m_initialisedSize:" << m_initialisedSize << "devicePixelRatio:" << m_devicePixelRatio;
+ if (m_runningInDesigner
+ || m_initialisedSize.width() <= 0
+ || m_initialisedSize.height() <= 0
+ || !window()) {
+ delete oldNode;
+ if (m_logAllCalls) qDebug() << " Returns null";
+ return 0;
+ }
+
+ CanvasRenderNode *node = static_cast<CanvasRenderNode *>(oldNode);
+
+ if (!m_glContextQt) {
+ m_glContextQt = window()->openglContext();
+
+ QMetaObject::invokeMethod(this, "ready");
+ return 0;
+ }
+
+ if (!node) {
+ node = new CanvasRenderNode(this, window());
+
+ /* Set up connections to get the production of FBO textures in sync with vsync on the
+ * main thread.
+ *
+ * When a new texture is ready on the rendering thread, we use a direct connection to
+ * the texture node to let it know a new texture can be used. The node will then
+ * emit pendingNewTexture which we bind to QQuickWindow::update to schedule a redraw.
+ *
+ * When the scene graph starts rendering the next frame, the prepareNode() function
+ * is used to update the node with the new texture. Once it completes, it emits
+ * textureInUse() which we connect to the FBO rendering thread's renderNext() to have
+ * it start producing content into its current "back buffer".
+ *
+ * This FBO rendering pipeline is throttled by vsync on the scene graph rendering thread.
+ */
+ connect(this, &Canvas::textureReady,
+ node, &CanvasRenderNode::newTexture,
+ Qt::DirectConnection);
+
+ connect(node, &CanvasRenderNode::pendingNewTexture,
+ window(), &QQuickWindow::update,
+ Qt::QueuedConnection);
+
+ connect(window(), &QQuickWindow::beforeRendering,
+ node, &CanvasRenderNode::prepareNode,
+ Qt::DirectConnection);
+
+ connect(node, &CanvasRenderNode::textureInUse,
+ this, &Canvas::renderNext,
+ Qt::QueuedConnection);
+
+ // Get the production of FBO textures started..
+ QMetaObject::invokeMethod(this, "renderNext", Qt::QueuedConnection);
+
+ update();
+ }
+
+ node->setRect(boundingRect());
+ QMetaObject::invokeMethod(this, "renderNext", Qt::QueuedConnection);
+
+ m_renderNodeReady = true;
+
+ return node;
+}
+
+/*!
+ * \internal
+ */
+void Canvas::renderNext()
+{
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__;
+
+ updateWindowParameters();
+
+ // Don't try to do anything before the render node has been created
+ if (!m_renderNodeReady) {
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Render node not ready, returning";
+ return;
+ }
+
+ if (!m_glContext) {
+ // Call the initialize function from QML/JavaScript until it calls the getContext() that in turn creates the buffers
+ // Allow the JavaScript code to call the getContext() to create the context object and FBOs
+ QVariant ignoredReturnedValue;
+ QMetaObject::invokeMethod(this, "initGL",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, ignoredReturnedValue));
+
+ emit initGLCalled();
+
+ if (!m_isContextAttribsSet) {
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Context attributes not set, returning";
+ return;
+ }
+
+ if (!m_glContext) {
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " GLContext3D not created, returning";
+ return;
+ }
+ }
+
+ // We have a GL context, make it current
+ m_glContext->makeCurrent(m_offscreenSurface);
+
+ // Bind the correct render target FBO
+ if (m_context3D->currentFramebuffer() == 0) {
+ if (m_contextAttribs.antialias())
+ m_antialiasFbo->bind();
+ else
+ m_renderFbo->bind();
+ } else {
+ glBindFramebuffer(GL_FRAMEBUFFER, m_context3D->currentFramebuffer());
+ }
+
+ // Ensure we have correct clip rect set in the context
+ QRect viewport = m_context3D->glViewportRect();
+ glViewport(viewport.x(), viewport.y(), viewport.width(), viewport.height());
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " viewport set to " << viewport;
+
+ // Check that we're complete component before drawing
+ if (!isComponentComplete())
+ return;
+
+ // Check if there is a image loader ask it to notify any image loads
+ if (m_imageLoader)
+ m_imageLoader->notifyLoadedImages();
+
+ // Call render in QML JavaScript side
+ QVariant ignoredReturnedValue;
+ QMetaObject::invokeMethod(this, "renderGL",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, ignoredReturnedValue));
+
+ // Resolve MSAA
+ if (m_contextAttribs.antialias()) {
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Resolving MSAA";
+ QOpenGLFramebufferObject::blitFramebuffer(m_displayFbo, m_antialiasFbo);
+ }
+
+ // We need to flush the contents to the FBO before posting
+ // the texture to the other thread, otherwise, we might
+ // get unexpected results.
+ glFlush();
+ glFinish();
+ qSwap(m_renderFbo, m_displayFbo);
+ if (m_logAllCalls) qDebug() << "Canvas3D::" << __FUNCTION__ << " Displaying texture " << m_displayFbo->texture() << " from FBO: " << m_displayFbo->handle();
+
+ // Rebind default FBO
+ QOpenGLFramebufferObject::bindDefault();
+ m_glContext->doneCurrent();
+
+ // Notify the render node of new texture
+ emit textureReady(m_displayFbo->texture(), m_initialisedSize, m_devicePixelRatio);
+}
diff --git a/src/canvas3d_p.h b/src/canvas3d_p.h
new file mode 100644
index 0000000..d135968
--- /dev/null
+++ b/src/canvas3d_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CANVAS3D_P_H
+#define CANVAS3D_P_H
+
+#include "canvas3dcommon_p.h"
+#include "context3d_p.h"
+#include "teximage3dloader_p.h"
+
+#include <QQuickItem>
+#include <QQuickWindow>
+
+class QOffscreenSurface;
+
+class QT_CANVAS3D_EXPORT Canvas : public QQuickItem, QOpenGLFunctions
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(Canvas)
+ Q_INTERFACES(QQmlParserStatus)
+ Q_PROPERTY(CanvasContext *context READ context NOTIFY contextChanged)
+ Q_PROPERTY(bool animated READ isAnimated WRITE setAnimated NOTIFY animatedChanged)
+ Q_PROPERTY(bool logAllCalls READ logAllCalls WRITE setLogAllCalls NOTIFY logAllCallsChanged)
+ Q_PROPERTY(bool logAllErrors READ logAllErrors WRITE setLogAllErrors NOTIFY logAllErrorsChanged)
+ Q_PROPERTY(float devicePixelRatio READ devicePixelRatio NOTIFY devicePixelRatioChanged)
+ Q_PROPERTY(CanvasTextureImageLoader *imageLoader READ imageLoader WRITE setImageLoader NOTIFY imageLoaderChanged)
+
+public:
+ Canvas(QQuickItem *parent = 0);
+ ~Canvas();
+
+ void handleWindowChanged(QQuickWindow *win);
+ float devicePixelRatio();
+ void setAnimated(bool animated);
+ bool isAnimated();
+
+ void setLogAllCalls(bool logCalls);
+ bool logAllCalls() const;
+ void setLogAllErrors(bool logErrors);
+ bool logAllErrors() const;
+
+ GLuint drawFBOHandle();
+
+ CanvasTextureImageLoader *imageLoader();
+ void setImageLoader(CanvasTextureImageLoader *loader);
+
+ Q_INVOKABLE CanvasContext *getContext(const QString &name);
+ Q_INVOKABLE CanvasContext *getContext(const QString &name, const QVariantMap &options);
+ CanvasContext *context();
+
+public slots:
+ void ready();
+ void shutDown();
+ void renderNext();
+
+signals:
+ void needRender();
+ void devicePixelRatioChanged(float ratio);
+ void animatedChanged(bool animated);
+ void imageLoaderChanged(CanvasTextureImageLoader *loader);
+ void logAllCallsChanged(bool logCalls);
+ void logAllErrorsChanged(bool logErrors);
+ void contextChanged(CanvasContext *context);
+ void initGLCalled();
+
+ void textureReady(int id, const QSize &size, float devicePixelRatio);
+
+protected:
+ virtual void geometryChanged(const QRectF & newGeometry, const QRectF & oldGeometry);
+ virtual void itemChange(ItemChange change, const ItemChangeData &value);
+ virtual QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *);
+
+private:
+ void setupAntialiasing();
+ void updateWindowParameters();
+
+ bool m_renderNodeReady;
+ bool m_logAllCalls;
+ bool m_logAllErrors;
+ QThread *m_mainThread;
+ QThread *m_contextThread;
+ QRectF m_cachedGeometry;
+ CanvasContext *m_context3D;
+ bool m_isFirstRender;
+ QSize m_initialisedSize;
+
+ QOpenGLContext *m_glContext;
+ QOpenGLContext *m_glContextQt;
+ QQuickWindow *m_contextWindow;
+
+ int m_maxSamples;
+ int m_samples;
+ bool m_isAnimated;
+ float m_devicePixelRatio;
+
+ CanvasTextureImageLoader *m_imageLoader;
+ bool m_runningInDesigner;
+ CanvasContextAttributes m_contextAttribs;
+ bool m_isContextAttribsSet;
+
+ QOpenGLFramebufferObject *m_antialiasFbo;
+ QOpenGLFramebufferObject *m_renderFbo;
+ QOpenGLFramebufferObject *m_displayFbo;
+
+ QOffscreenSurface *m_offscreenSurface;
+};
+
+#endif // CANVAS3D_P_H
+
diff --git a/src/canvas3dcommon_p.h b/src/canvas3dcommon_p.h
new file mode 100644
index 0000000..76c85bf
--- /dev/null
+++ b/src/canvas3dcommon_p.h
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CANVAS3DCOMMON_P_H
+#define CANVAS3DCOMMON_P_H
+
+#define QT_CANVAS3D_EXPORT Q_DECL_EXPORT
+
+#define VERBOSE_ALL_TYPED_ARRAY_CALLS false
+
+#endif // CANVAS3DCOMMON_P_H
diff --git a/src/canvasrendernode.cpp b/src/canvasrendernode.cpp
new file mode 100644
index 0000000..a82277c
--- /dev/null
+++ b/src/canvasrendernode.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "canvasrendernode_p.h"
+#include "canvas3d_p.h"
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLFramebufferObject>
+
+CanvasRenderNode::CanvasRenderNode(Canvas *canvas, QQuickWindow *window) :
+ QObject(),
+ QSGSimpleTextureNode(),
+ m_canvas(canvas),
+ m_id(0),
+ m_size(0,0),
+ m_texture(0),
+ m_window(window)
+{
+ if (m_canvas->logAllCalls()) qDebug() << "CanvasRenderNode::" << __FUNCTION__;
+
+ // Our texture node must have a texture, so use the default 0 texture.
+ m_texture = m_window->createTextureFromId(0, QSize(1, 1));
+ setTexture(m_texture);
+ setFiltering(QSGTexture::Linear);
+ setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically);
+}
+
+CanvasRenderNode::~CanvasRenderNode()
+{
+ if (m_canvas->logAllCalls()) qDebug() << "CanvasRenderNode::" << __FUNCTION__;
+ delete m_texture;
+}
+
+void CanvasRenderNode::newTexture(int id, const QSize &size)
+{
+ if (m_canvas->logAllCalls()) qDebug() << "CanvasRenderNode::" << __FUNCTION__ << "(" << id << ", " << size << ")";
+ m_mutex.lock();
+ m_id = id;
+ m_size = size;
+ m_mutex.unlock();
+
+ // We cannot call QQuickWindow::update directly here, as this is only allowed
+ // from the rendering thread or GUI thread.
+ emit pendingNewTexture();
+}
+
+// Before the scene graph starts to render, we update to the pending texture
+void CanvasRenderNode::prepareNode()
+{
+ if (m_canvas->logAllCalls()) qDebug() << "CanvasRenderNode::" << __FUNCTION__;
+ m_mutex.lock();
+ int newId = m_id;
+ QSize size = m_size;
+ m_id = 0;
+ m_mutex.unlock();
+
+ if (newId) {
+ if (m_canvas->logAllCalls()) qDebug() << "CanvasRenderNode::" << __FUNCTION__ << " showing new texture:" << newId << " size:" << size << " targetRect:" << rect();
+ delete m_texture;
+ m_texture = m_window->createTextureFromId(newId, size);
+ setTexture(m_texture);
+ if (m_canvas->logAllCalls()) qDebug() << "CanvasRenderNode::" << __FUNCTION__ << " SGTexture size:" << m_texture->textureSize() << " normalizedTextureSubRect:" << m_texture->normalizedTextureSubRect();
+
+ // This will notify the main thread that the texture is now being rendered
+ // and it can start rendering to the other one.
+ emit textureInUse();
+ } else {
+ if (m_canvas->logAllCalls()) qDebug() << "CanvasRenderNode::" << __FUNCTION__ << " showing previous texture";
+ }
+}
diff --git a/src/canvasrendernode_p.h b/src/canvasrendernode_p.h
new file mode 100644
index 0000000..0c529b9
--- /dev/null
+++ b/src/canvasrendernode_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CANVASRENDERNODE_P_H
+#define CANVASRENDERNODE_P_H
+
+#include <QtQuick/QSGSimpleTextureNode>
+#include <QtQuick/QQuickWindow>
+#include <QtCore/QMutex>
+
+class Canvas;
+
+class CanvasRenderNode : public QObject, public QSGSimpleTextureNode
+{
+ Q_OBJECT
+
+public:
+ CanvasRenderNode(Canvas *canvas, QQuickWindow *window);
+ ~CanvasRenderNode();
+
+signals:
+ void textureInUse();
+ void pendingNewTexture();
+
+public slots:
+ void newTexture(int id, const QSize &size);
+ void prepareNode();
+
+private:
+ Canvas *m_canvas;
+ int m_id;
+ QSize m_size;
+ QMutex m_mutex;
+ QSGTexture *m_texture;
+ QQuickWindow *m_window;
+};
+
+#endif // CANVASRENDERNODE_P_H
diff --git a/src/context3d.cpp b/src/context3d.cpp
new file mode 100644
index 0000000..08993f3
--- /dev/null
+++ b/src/context3d.cpp
@@ -0,0 +1,3523 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "canvas3d_p.h"
+#include "context3d_p.h"
+#include "texture3d_p.h"
+#include "shader3d_p.h"
+#include "program3d_p.h"
+#include "buffer3d_p.h"
+#include "framebuffer3d_p.h"
+#include "renderbuffer3d_p.h"
+#include "uniformlocation_p.h"
+#include "arraybuffer_p.h"
+#include "int8array_p.h"
+#include "uint8array_p.h"
+#include "int16array_p.h"
+#include "uint16array_p.h"
+#include "int32array_p.h"
+#include "uint32array_p.h"
+#include "float32array_p.h"
+#include "float64array_p.h"
+#include "teximage3d_p.h"
+#include "arrayutils_p.h"
+#include "shaderprecisionformat_p.h"
+#include "enumtostringmap_p.h"
+#include "canvas3dcommon_p.h"
+#include "contextextensions_p.h"
+
+#include <QtGui/QOpenGLShader>
+
+/*!
+ * \qmltype Context3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Provides 3D rendering API and context.
+ *
+ * An uncreatable QML type that provides a WebGL-like API that can be used to draw 3D graphics to
+ * the Canvas3D element. You can get it by calling \l{Canvas3D::getContext}{Canvas3D.getContext}
+ * method.
+ *
+ * \sa Canvas3D
+ */
+
+// Owned by the SG Render Thread!
+CanvasContext::CanvasContext(QOpenGLContext *context, int width, int height, QObject *parent) :
+ QObject(parent),
+ QOpenGLFunctions(context),
+ m_logAllCalls(false),
+ m_logAllErrors(true),
+ m_glViewportRect(0, 0, width, height),
+ m_devicePixelRatio(1.0),
+ m_currentProgram(0),
+ m_currentArrayBuffer(0),
+ m_currentElementArrayBuffer(0),
+ m_currentTexture(0),
+ m_context(0),
+ m_error(NO_ERROR),
+ m_currentFramebuffer(0),
+ m_map(EnumToStringMap::newInstance()),
+ m_canvas(0)
+{
+ m_context = context;
+#ifndef QT_NO_DEBUG
+ const GLubyte *version = glGetString(GL_VERSION);
+ qDebug() << "Context3D::" << __FUNCTION__ << "OpenGL version:" << (const char *)version;
+ version = glGetString(GL_SHADING_LANGUAGE_VERSION);
+ qDebug() << "Context3D::" << __FUNCTION__ << "GLSL version:" << (const char *)version;
+ QString extensions = QString((char *)glGetString(GL_EXTENSIONS));
+ QStringList list = extensions.split(" ");
+ qDebug() << "Context3D::" << __FUNCTION__ << "EXTENSIONS: " << list;
+#endif
+}
+
+/*!
+ * \internal
+ */
+CanvasContext::~CanvasContext()
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__;
+ EnumToStringMap::deleteInstance();
+}
+
+/*!
+ * \qmlproperty bool Context3D::canvas
+ * Holds the Canvas3D for the Context3D.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::setCanvas(Canvas *canvas)
+{
+ if (m_canvas != canvas) {
+ m_canvas = canvas;
+ emit canvasChanged(canvas);
+ }
+}
+
+Canvas *CanvasContext::canvas()
+{
+ return m_canvas;
+}
+
+/*!
+ * \internal
+ */
+QString CanvasContext::glEnumToString(glEnums value) const
+{
+ return m_map->lookUp(value);
+}
+
+/*!
+ * \qmlproperty bool Context3D::logAllCalls
+ * Specifies if all Context3D method calls (including internal ones) are logged to the console.
+ * Defaults to \c{false}.
+ * Setting this to \c true may help in debugging your code as you get a full listing of the 3D calls
+ * and parameters your code does.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::setLogAllCalls(bool logCalls)
+{
+ if (m_logAllCalls != logCalls) {
+ m_logAllCalls = logCalls;
+ emit logAllCallsChanged(logCalls);
+ }
+}
+
+bool CanvasContext::logAllCalls() const
+{
+ return m_logAllCalls;
+}
+
+/*!
+ * \qmlproperty bool Context3D::logAllErrors
+ * Specifies if all Context3D errors are logged to the console in addition to just setting the
+ * getError() return value. Defaults to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::setLogAllErrors(bool logErrors)
+{
+ if (m_logAllErrors != logErrors) {
+ m_logAllErrors = logErrors;
+ emit logAllErrorsChanged(logErrors);
+ }
+}
+
+bool CanvasContext::logAllErrors() const
+{
+ return m_logAllErrors;
+}
+
+/*!
+ * \internal
+ */
+void CanvasContext::setContextAttributes(const CanvasContextAttributes &attribs)
+{
+ m_contextAttributes.setFrom(attribs);
+}
+
+/*!
+ * \internal
+ */
+float CanvasContext::devicePixelRatio()
+{
+ return m_devicePixelRatio;
+}
+
+/*!
+ * \internal
+ */
+void CanvasContext::setDevicePixelRatio(float ratio)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << ratio << ")";
+ m_devicePixelRatio = ratio;
+}
+
+/*!
+ * \internal
+ */
+QRect CanvasContext::glViewportRect() const
+{
+ return m_glViewportRect;
+}
+
+/*!
+ * \internal
+ */
+GLuint CanvasContext::currentFramebuffer()
+{
+ if (!m_currentFramebuffer)
+ return 0;
+
+ return m_currentFramebuffer->id();
+}
+
+/*!
+ * \qmlmethod ShaderPrecisionFormat Context3D::getShaderPrecisionFormat(glEnums shadertype, glEnums precisiontype)
+ * Return a new ShaderPrecisionFormat describing the range and precision for the specified shader
+ * numeric format.
+ * \a shadertype Type of the shader, either \c Context3D.FRAGMENT_SHADER or
+ * \c{Context3D.VERTEX_SHADER}.
+ * \a precisiontype Can be \c{Context3D.LOW_FLOAT}, \c{Context3D.MEDIUM_FLOAT},
+ * \c{Context3D.HIGH_FLOAT}, \c{Context3D.LOW_INT}, \c{Context3D.MEDIUM_INT} or
+ * \c{Context3D.HIGH_INT}.
+ *
+ * \sa ShaderPrecisionFormat
+ */
+/*!
+ * \internal
+ */
+CanvasShaderPrecisionFormat *CanvasContext::getShaderPrecisionFormat(glEnums shadertype,
+ glEnums precisiontype)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(shaderType:" << glEnumToString(shadertype) << ", precisiontype:" << glEnumToString(precisiontype) << ")";
+
+ GLint range[2];
+ range[0] = 1;
+ range[1] = 1;
+ GLint precision = 1;
+
+ glGetShaderPrecisionFormat((GLenum)(shadertype), (GLenum)(precisiontype), range, &precision);
+ CanvasShaderPrecisionFormat *format = new CanvasShaderPrecisionFormat();
+ format->setPrecision(int(precision));
+ format->setRangeMin(int(range[0]));
+ format->setRangeMax(int(range[1]));
+ return format;
+}
+
+/*!
+ * \qmlmethod list<variant> Context3D::getSupportedExtensions()
+ * Returns an array of the extension strings supported by this implementation
+ */
+/*!
+ * \internal
+ */
+QVariantList CanvasContext::getSupportedExtensions()
+{
+ if (m_logAllCalls) qDebug() << Q_FUNC_INFO;
+ // TODO: Just returns empty variant list. To be implemented?
+ return QVariantList();
+}
+
+/*!
+ * \qmlmethod variant Context3D::getExtension(string name)
+ * Returns an object if given \a name matches a supported extension.
+ * Otherwise returns \c{null}. The returned object may contain constants and/or functions provided
+ * by the extension, but at minimum a unique object is returned.
+ * \a name is the case-insensitive name of the extension to be returned.
+ */
+/*!
+ * \internal
+ */
+QVariant CanvasContext::getExtension(const QString &name)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(name:" << name << ")";
+
+ if (name == "WEBGL_debug_renderer_info")
+ return QVariant::fromValue(new WEBGL_debug_renderer_info);
+
+ return QVariant();
+}
+
+/*!
+ * \qmlmethod bool Context3D::isContextLost()
+ * Always returns false.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isContextLost()
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(): false";
+ return false;
+}
+
+/*!
+ * \qmlmethod ContextAttributes Context3D::getContextAttributes()
+ * Returns a copy of the actual context parameters that are used in the current context.
+ */
+/*!
+ * \internal
+ */
+CanvasContextAttributes *CanvasContext::getContextAttributes()
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "()";
+
+ CanvasContextAttributes *attributes = new CanvasContextAttributes();
+ attributes->setAlpha(m_contextAttributes.alpha());
+ attributes->setDepth(m_contextAttributes.depth());
+ attributes->setStencil(m_contextAttributes.stencil());
+ attributes->setAntialias(m_contextAttributes.antialias());
+ attributes->setPremultipliedAlpha(m_contextAttributes.premultipliedAlpha());
+ attributes->setPreserveDrawingBuffer(m_contextAttributes.preserveDrawingBuffer());
+ attributes->setPreferLowPowerToHighPerformance(
+ m_contextAttributes.preferLowPowerToHighPerformance());
+ attributes->setFailIfMajorPerformanceCaveat(
+ m_contextAttributes.failIfMajorPerformanceCaveat());
+
+ // Returning a pointer to QObject that has NO parent set
+ // -> V4VM should respect this take ownership
+ return attributes;
+}
+
+/*!
+ * \qmlmethod void Context3D::flush()
+ * Indicates to graphics driver that previously sent commands must complete within finite time.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::flush()
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "()";
+ glFlush();
+}
+
+/*!
+ * \qmlmethod void Context3D::finish()
+ * Forces all previous 3D rendering commands to complete.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::finish()
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "()";
+ glFinish();
+}
+
+/*!
+ * \qmlmethod Texture3D Context3D::createTexture()
+ * Create a Texture3D object and initialize a name for it as by calling \c{glGenTextures()}.
+ */
+/*!
+ * \internal
+ */
+CanvasTexture *CanvasContext::createTexture()
+{
+ CanvasTexture *texture = new CanvasTexture(this);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "():" << texture;
+
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return texture;
+}
+
+/*!
+ * \qmlmethod void Context3D::deleteTexture(Texture3D texture)
+ * Deletes the given texture as if by calling \c{glDeleteTextures()}.
+ * Calling this method repeatedly on the same object has no side effects.
+ * \a texture is the Texture3D to be deleted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::deleteTexture(CanvasTexture *texture)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( texture:" << texture << ")";
+ if (texture) {
+ texture->del();
+ } else {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": invalid texture handle:" << texture;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::scissor(int x, int y, int width, int height)
+ * Defines a rectangle that constrains the drawing.
+ * \a x is theleft edge of the rectangle.
+ * \a y is the bottom edge of the rectangle.
+ * \a width is the width of the rectangle.
+ * \a height is the height of the rectangle.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::scissor(int x, int y, int width, int height)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( x:" << x <<
+ ", y:" << y <<
+ ", width:" << width <<
+ ", height:" << height << ")";
+
+ glScissor(x, y, width, height);
+}
+
+/*!
+ * \qmlmethod void Context3D::activeTexture(glEnums texture)
+ * Sets the given texture unit as active. Number of texture units is implementation dependent,
+ * but must be at least 8. Initially \c Context3D.TEXTURE0 is active.
+ * \a texture must be one of \c Context3D.TEXTUREi values where \c i ranges from \c 0 to
+ * \c{(Context3D.MAX_COMBINED_TEXTURE_IMAGE_UNITS-1)}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::activeTexture(glEnums texture)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( texture:" << glEnumToString(texture) << ")";
+ glActiveTexture(GLenum(texture));
+}
+
+/*!
+ * \qmlmethod void Context3D::bindTexture(glEnums target, Texture3D texture)
+ * Bind a Texture3D to a texturing target.
+ * \a target is the target of the active texture unit to which the Texture3D will be bound.
+ * Must be either \c{Context3D.TEXTURE_2D} or \c{Context3D.TEXTURE_CUBE_MAP}.
+ * \a texture is the Texture3D to be bound.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bindTexture(glEnums target, CanvasTexture *texture)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" << glEnumToString(target) << ", texture:" << texture << ")";
+ m_currentTexture = texture;
+ if (texture) {
+ if (!texture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": Trying to bind deleted texture object";
+ return;
+ }
+ m_currentTexture->bind(target);
+ } else {
+ glBindTexture(GLenum(target), 0);
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::generateMipmap(glEnums target)
+ * Generates a complete set of mipmaps for a texture object of the currently active texture unit.
+ * \a target defines the texture target to which the texture object is bound whose mipmaps will be
+ * generated. Must be either \c{Context3D.TEXTURE_2D} or \c{Context3D.TEXTURE_CUBE_MAP}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::generateMipmap(glEnums target)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" << glEnumToString(target) << ")";
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ } else {
+ glGenerateMipmap(target);
+ }
+}
+
+/*!
+ * \qmlmethod bool Context3D::isTexture(Object anyObject)
+ * Returns true if the given object is a valid Texture3D object.
+ * \a anyObject is the object that is to be verified as a valid texture.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isTexture(QObject *anyObject)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( anyObject:" << anyObject << ")";
+
+ if (!anyObject)
+ return false;
+
+ QString className = QString(anyObject->metaObject()->className());
+ if (className != "CanvasTexture")
+ return false;
+
+ CanvasTexture *texture = static_cast<CanvasTexture *>(anyObject);
+ if (!texture->isAlive())
+ return false;
+ return glIsTexture(texture->textureId());
+}
+
+/*!
+ * \qmlmethod void Context3D::compressedTexImage2D(glEnums target, int level, glEnums internalformat, int width, int height, int border, TypedArray pixels)
+ * Not supported, \c{Context3D.INVALID_OPERATION} is generated when called.
+ * \a target, \a level, \a internalformat, \a width, \a height, \a border and \a pixels are ignored.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::compressedTexImage2D(glEnums target, int level, glEnums internalformat,
+ int width, int height, int border,
+ CanvasTypedArray *pixels)
+{
+ Q_UNUSED(target)
+ Q_UNUSED(level)
+ Q_UNUSED(internalformat)
+ Q_UNUSED(width)
+ Q_UNUSED(height)
+ Q_UNUSED(border)
+ Q_UNUSED(pixels)
+
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ } else {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM Core WebGL API doesn't support compressed images";
+ m_error = INVALID_ENUM;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::compressedTexSubImage2D(glEnums target, int level, int xoffset, int yoffset, int width, int height, glEnums format, TypedArray pixels)
+ * Not supported, \c{Context3D.INVALID_OPERATION} is generated when called.
+ * \a target, \a level, \a xoffset, \a yoffset, \a width, \a height, \a format and \a pixels are
+ * ignored.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::compressedTexSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ int width, int height,
+ glEnums format,
+ CanvasTypedArray *pixels)
+{
+ Q_UNUSED(target)
+ Q_UNUSED(level)
+ Q_UNUSED(xoffset)
+ Q_UNUSED(yoffset)
+ Q_UNUSED(width)
+ Q_UNUSED(height)
+ Q_UNUSED(format)
+ Q_UNUSED(pixels)
+
+ if (!pixels) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ }
+
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ } else {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM Core WebGL API doesn't support compressed images";
+ m_error = INVALID_ENUM;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::copyTexImage2D(glEnums target, int level, glEnums internalformat, int x, int y, int width, int height, int border)
+ * Copies pixels into currently bound 2D texture.
+ * \a target specifies the target texture of the active texture unit. Must be \c{Context3D.TEXTURE_2D},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_X},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Y},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Z}.
+ * \a level specifies the level of detail number. Level \c 0 is the base image level. Level \c n is
+ * the \c{n}th mipmap reduction image.
+ * \a internalformat specifies the internal format of the texture. Must be \c{Context3D.ALPHA},
+ * \c{Context3D.LUMINANCE}, \c{Context3D.LUMINANCE_ALPHA}, \c{Context3D.RGB} or \c{Context3D.RGBA}.
+ * \a x specifies the window coordinate of the left edge of the rectangular region of pixels to be
+ * copied.
+ * \a y specifies the window coordinate of the lower edge of the rectangular region of pixels to be
+ * copied.
+ * \a width specifies the width of the texture image. All implementations will support 2D texture
+ * images that are at least 64 texels wide and cube-mapped texture images that are at least 16
+ * texels wide.
+ * \a height specifies the height of the texture image. All implementations will support 2D texture
+ * images that are at least 64 texels high and cube-mapped texture images that are at least 16
+ * texels high.
+ * \a border must be \c{0}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::copyTexImage2D(glEnums target, int level, glEnums internalformat,
+ int x, int y, int width, int height,
+ int border)
+{
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ } else {
+ glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::copyTexSubImage2D(glEnums target, int level, int xoffset, int yoffset, int x, int y, int width, int height)
+ * Copies to into a currently bound 2D texture subimage.
+ * \a target specifies the target texture of the active texture unit. Must be \c{Context3D.TEXTURE_2D},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_X},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Y},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Z}.
+ * \a level specifies the level of detail number. Level \c 0 is the base image level. Level \c n is
+ * the \c{n}th mipmap reduction image.
+ * \a xoffset specifies the texel offset in the x direction within the texture array.
+ * \a yoffset specifies the texel offset in the y direction within the texture array.
+ * \a x specifies the window coordinate of the left edge of the rectangular region of pixels to be
+ * copied.
+ * \a y specifies the window coordinate of the lower edge of the rectangular region of pixels to be
+ * copied.
+ * \a width specifies the width of the texture subimage.
+ * \a height specifies the height of the texture subimage.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::copyTexSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ int x, int y,
+ int width, int height)
+{
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ } else {
+ copyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::texImage2D(glEnums target, int level, glEnums internalformat, int width, int height, int border, glEnums format, glEnums type, TypedArray pixels)
+ * Specify a 2D texture image.
+ * \a target specifies the target texture of the active texture unit. Must be \c{Context3D.TEXTURE_2D},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_X},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Y},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP_NEGATIVE_Z}.
+ * \a level specifies the level of detail number. Level \c 0 is the base image level. Level \c n is
+ * the \c{n}th mipmap reduction image.
+ * \a internalformat specifies the internal format of the texture. Must be \c{Context3D.ALPHA},
+ * \c{Context3D.LUMINANCE}, \c{Context3D.LUMINANCE_ALPHA}, \c{Context3D.RGB} or \c{Context3D.RGBA}.
+ * \a width specifies the width of the texture image. All implementations will support 2D texture
+ * images that are at least 64 texels wide and cube-mapped texture images that are at least 16
+ * texels wide.
+ * \a height specifies the height of the texture image. All implementations will support 2D texture
+ * images that are at least 64 texels high and cube-mapped texture images that are at least 16
+ * texels high.
+ * \a border must be \c{0}.
+ * \a format specifies the format of the texel data given in \a pixels, must match the value
+ * of \a internalFormat.
+ * \a type specifies the data type of the data given in \a pixels, must match the TypedArray type
+ * of \a pixels. Must be \c{Context3D.UNSIGNED_BYTE}, \c{Context3D.UNSIGNED_SHORT_5_6_5},
+ * \c{Context3D.UNSIGNED_SHORT_4_4_4_4} or \c{Context3D.UNSIGNED_SHORT_5_5_5_1}.
+ * \a pixels specifies the TypedArray containing the image data. If pixels is \c{null}, a buffer
+ * of sufficient size initialized to 0 is passed.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat,
+ int width, int height, int border,
+ glEnums format, glEnums type,
+ CanvasTypedArray *pixels)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" << glEnumToString(target) <<
+ ", level:" << level <<
+ ", internalformat:" << glEnumToString(internalformat) <<
+ ", width:" << width <<
+ ", height:" << height <<
+ ", border:" << border <<
+ ", format:" << glEnumToString(format) <<
+ ", type:" << glEnumToString(type) <<
+ ", pixels:" << pixels << ")";
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ return;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ bool deleteTempPixels = false;
+ if (!pixels) {
+ deleteTempPixels = true;
+ if (type == UNSIGNED_BYTE )
+ pixels = new CanvasUint8Array(getSufficientSize(internalformat, width, height));
+ else
+ pixels = new CanvasUint16Array(getSufficientSize(internalformat, width, height));
+ }
+
+ QString className(pixels->metaObject()->className());
+
+ switch (type) {
+ case UNSIGNED_BYTE:
+ if (className != "CanvasUint8Array") {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Invalid TypedArray supplied, expected Uint8Array, received " << pixels->metaObject()->className();
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ glTexImage2D(target, level, internalformat, width, height, border, format, type,
+ static_cast<CanvasUint8Array *>(pixels)->rawDataCptr());
+ break;
+ case UNSIGNED_SHORT_4_4_4_4:
+ case UNSIGNED_SHORT_5_6_5:
+ case UNSIGNED_SHORT_5_5_5_1:
+ if (className != "CanvasUint16Array") {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Invalid TypedArray supplied, expected Uint16Array, received " << pixels->metaObject()->className();
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ glTexImage2D(target, level, internalformat, width, height, border, format, type,
+ static_cast<CanvasUint16Array *>(pixels)->rawDataCptr());
+ break;
+ default:
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM Invalid type enum";
+ m_error = INVALID_ENUM;
+ break;
+ }
+
+ if (deleteTempPixels) {
+ delete pixels;
+ pixels = 0;
+ }
+}
+
+
+/*!
+ * \qmlmethod void Context3D::texSubImage2D(glEnums target, int level, int xoffset, int yoffset, int width, int height, glEnums format, glEnums type, TypedArray pixels)
+ * Specify a 2D texture subimage.
+ * \a target Target texture of the active texture unit. Must be \c{Context3D.TEXTURE_2D},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_X},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_Y},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_Z}.
+ * \a level Level of detail number. Level \c 0 is the base image level. Level \c n is the \c{n}th
+ * mipmap reduction image.
+ * \a xoffset Specifies a texel offset in the x direction within the texture array.
+ * \a yoffset Specifies a texel offset in the y direction within the texture array.
+ * \a width Width of the texture subimage.
+ * \a height Height of the texture subimage.
+ * \a format Format of the texel data given in \a pixels, must match the value
+ * of \a internalFormat.
+ * \a type Data type of the data given in \a pixels, must match the TypedArray type
+ * of \a pixels. Must be \c{Context3D.UNSIGNED_BYTE}, \c{Context3D.UNSIGNED_SHORT_5_6_5},
+ * \c{Context3D.UNSIGNED_SHORT_4_4_4_4} or \c{Context3D.UNSIGNED_SHORT_5_5_5_1}.
+ * \a pixels TypedArray containing the image data. If pixels is \c null, a buffer of
+ * sufficient size initialized to 0 is passed.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::texSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ int width, int height,
+ glEnums format, glEnums type,
+ CanvasTypedArray *pixels)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" << glEnumToString(target) <<
+ ", level:" << level <<
+ ", xoffset:" << xoffset <<
+ ", yoffset:" << yoffset <<
+ ", width:" << width <<
+ ", height:" << height <<
+ ", format:" << glEnumToString(format) <<
+ ", type:" << glEnumToString(type) <<
+ ", pixels:" << pixels << ")";
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ return;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ if (!pixels) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_VALUE pixels was null";
+ m_error = INVALID_VALUE;
+ return;
+ }
+
+ QString className(pixels->metaObject()->className());
+
+ switch (type) {
+ case UNSIGNED_BYTE:
+ if (className != "CanvasUint8Array") {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Invalid TypedArray supplied, expected Uint8Array, received " << pixels->metaObject()->className();
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type,
+ static_cast<CanvasUint8Array *>(pixels)->rawDataCptr());
+ break;
+ case UNSIGNED_SHORT_4_4_4_4:
+ case UNSIGNED_SHORT_5_6_5:
+ case UNSIGNED_SHORT_5_5_5_1:
+ if (className != "CanvasUint16Array") {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Invalid TypedArray supplied, expected Uint16Array, received " << pixels->metaObject()->className();
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ glTexImage2D(target, level, xoffset, yoffset, width, height, format, type,
+ static_cast<CanvasUint16Array *>(pixels)->rawDataCptr());
+ break;
+ default:
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM Invalid type enum";
+ m_error = INVALID_ENUM;
+ break;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::texImage2D(glEnums target, int level, glEnums internalformat, glEnums format, glEnums type, TextureImage image)
+ * Uploads the given TextureImage element to the currently bound Texture3D.
+ * \a target Target texture of the active texture unit. Must be \c{Context3D.TEXTURE_2D},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_X},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_Y},
+ * \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_Z}.
+ * \a level Level of detail number. Level \c 0 is the base image level. Level \c n is the \c{n}th
+ * mipmap reduction image.
+ * \a internalformat Internal format of the texture, conceptually the given image is first
+ * converted to this format, then uploaded. Must be \c{Context3D.ALPHA}, \c{Context3D.LUMINANCE},
+ * \c{Context3D.LUMINANCE_ALPHA}, \c{Context3D.RGB} or \c{Context3D.RGBA}.
+ * \a format Format of the texture, must match the value of \a internalFormat.
+ * \a type Type of the data, conceptually the given image is first converted to this type, then
+ * uploaded. Must be \c{Context3D.UNSIGNED_BYTE}, \c{Context3D.UNSIGNED_SHORT_5_6_5},
+ * \c{Context3D.UNSIGNED_SHORT_4_4_4_4} or \c{Context3D.UNSIGNED_SHORT_5_5_5_1}.
+ * \a image A complete TextureImage loaded using the TextureImageLoader.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::texImage2D(glEnums target, int level, glEnums internalformat,
+ glEnums format, glEnums type, CanvasTextureImage *image)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" <<
+ glEnumToString(target) <<
+ ", level:" << level <<
+ ", internalformat:" << glEnumToString(internalformat) <<
+ ", format:" << glEnumToString(format) <<
+ ", type:" << glEnumToString(type) <<
+ ", image:" << image << ")";
+
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ return;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ void *bits;
+ switch (type) {
+ case UNSIGNED_BYTE:
+ case UNSIGNED_SHORT_5_6_5:
+ case UNSIGNED_SHORT_4_4_4_4:
+ case UNSIGNED_SHORT_5_5_5_1:
+ bits = image->convertToFormat(type);
+ break;
+ default:
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM Invalid type enum";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (bits == 0) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":Conversion of pixels to format failed.";
+ return;
+ }
+
+ glTexImage2D(target, level, internalformat, image->width(), image->height(), 0, format, type,
+ bits);
+}
+
+/*!
+ * \qmlmethod void Context3D::texSubImage2D(glEnums target, int level, int xoffset, int yoffset, glEnums format, glEnums type, TextureImage image)
+ * Uploads the given TextureImage element to the currently bound Texture3D.
+ * \a target specifies the target texture of the active texture unit. Must be
+ * \c{Context3D.TEXTURE_2D}, \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_X},
+ * \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_X}, \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Y},
+ * \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_Y}, \c{Context3D.TEXTURE_CUBE_MAP_POSITIVE_Z}, or
+ * \c{Context3D.TEXTURE_CUBE_MAP__NEGATIVE_Z}.
+ * \a level Level of detail number. Level \c 0 is the base image level. Level \c n is the \c{n}th
+ * mipmap reduction image.
+ * \a internalformat Internal format of the texture, conceptually the given image is first
+ * converted to this format, then uploaded. Must be \c{Context3D.ALPHA}, \c{Context3D.LUMINANCE},
+ * \c{Context3D.LUMINANCE_ALPHA}, \c{Context3D.RGB} or \c{Context3D.RGBA}.
+ * \a format Format of the texture, must match the value of \a internalFormat.
+ * \a type Type of the data, conceptually the given image is first converted to this type, then
+ * uploaded. Must be \c{Context3D.UNSIGNED_BYTE}, \c{Context3D.UNSIGNED_SHORT_5_6_5},
+ * \c{Context3D.UNSIGNED_SHORT_4_4_4_4} or \c{Context3D.UNSIGNED_SHORT_5_5_5_1}.
+ * \a image A complete TextureImage loaded using the TextureImageLoader.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::texSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ glEnums format, glEnums type, CanvasTextureImage *image)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" <<
+ glEnumToString(target) <<
+ ", level:" << level <<
+ ", xoffset:" << xoffset <<
+ ", yoffset:" << yoffset <<
+ ", format:" << glEnumToString(format) <<
+ ", type:" << glEnumToString(type) <<
+ ", image:" << image << ")";
+
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ return;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ if (!image) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_VALUE image was null";
+ m_error = INVALID_VALUE;
+ return;
+ }
+
+ void *bits;
+ switch (type) {
+ case UNSIGNED_BYTE:
+ case UNSIGNED_SHORT_5_6_5:
+ case UNSIGNED_SHORT_4_4_4_4:
+ case UNSIGNED_SHORT_5_5_5_1:
+ bits = image->convertToFormat(type);
+ break;
+ default:
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM Invalid type enum";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (bits == 0) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":Conversion of pixels to format failed.";
+ return;
+ }
+
+ glTexSubImage2D(target, level, xoffset, yoffset, image->width(), image->height(), format,
+ type, bits);
+}
+
+/*!
+ * \qmlmethod void Context3D::texParameterf(glEnums target, glEnums pname, float param)
+ * Sets texture parameters.
+ * \a target specifies the target texture of the active texture unit. Must be
+ * \c{Context3D.TEXTURE_2D} or \c{Context3D.TEXTURE_CUBE_MAP}.
+ * \a pname specifies the symbolic name of a texture parameter. pname can be
+ * \c{Context3D.TEXTURE_MIN_FILTER}, \c{Context3D.TEXTURE_MAG_FILTER}, \c{Context3D.TEXTURE_WRAP_S} or
+ * \c{Context3D.TEXTURE_WRAP_T}.
+ * \a param specifies the new float value to be set to \a pname
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::texParameterf(glEnums target, glEnums pname, float param)
+{
+ if (m_logAllCalls) qDebug() << "texParameterf( target:" <<
+ glEnumToString(target) <<
+ ", pname:" << glEnumToString(pname) <<
+ ", param:" << param << ")";
+
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ return;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ glTexParameterf(GLenum(target), GLenum(pname), GLfloat(param));
+}
+
+/*!
+ * \qmlmethod void Context3D::texParameteri(glEnums target, glEnums pname, float param)
+ * Sets texture parameters.
+ * \a target specifies the target texture of the active texture unit. Must be
+ * \c{Context3D.TEXTURE_2D} or \c{Context3D.TEXTURE_CUBE_MAP}.
+ * \a pname specifies the symbolic name of a texture parameter. pname can be
+ * \c{Context3D.TEXTURE_MIN_FILTER}, \c{Context3D.TEXTURE_MAG_FILTER}, \c{Context3D.TEXTURE_WRAP_S} or
+ * \c{Context3D.TEXTURE_WRAP_T}.
+ * \a param specifies the new int value to be set to \a pname
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::texParameteri(glEnums target, glEnums pname, int param)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" <<
+ glEnumToString(target) <<
+ ", pname:" << glEnumToString(pname) <<
+ ", param:" << glEnumToString(glEnums(param)) << ")";
+ if (!m_currentTexture) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION No current texture bound";
+ m_error = INVALID_OPERATION;
+ return;
+ } else if (!m_currentTexture->isAlive()) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION Currently bound texture is already deleted";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ glTexParameteri(GLenum(target), GLenum(pname), GLint(param));
+}
+
+/*!
+ * \internal
+ */
+int CanvasContext::getSufficientSize(glEnums internalFormat, int width, int height)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( internalFormat:" << glEnumToString(internalFormat) << " , width:" << width << ", height:" << height << ")";
+ int bytesPerPixel = 0;
+ switch (internalFormat) {
+ case UNSIGNED_BYTE:
+ bytesPerPixel = 4;
+ break;
+ case UNSIGNED_SHORT_5_6_5:
+ case UNSIGNED_SHORT_4_4_4_4:
+ case UNSIGNED_SHORT_5_5_5_1:
+ bytesPerPixel = 2;
+ break;
+ default:
+ break;
+ }
+
+ return width * height * bytesPerPixel;
+}
+
+/*!
+ * \qmlmethod FrameBuffer3D Context3D::createFramebuffer()
+ * Returns a created FrameBuffer3D object that is initialized with a framebuffer object name as
+ * if by calling \c{glGenFramebuffers()}.
+ */
+/*!
+ * \internal
+ */
+CanvasFrameBuffer *CanvasContext::createFramebuffer()
+{
+ CanvasFrameBuffer *framebuffer = new CanvasFrameBuffer(this);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << ":" << framebuffer;
+
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return framebuffer;
+}
+
+/*!
+ * \qmlmethod void Context3D::bindFramebuffer(glEnums target, FrameBuffer3D framebuffer)
+ * Binds the given \a framebuffer object to the given \a target.
+ * \a target must be \c{Context3D.FRAMEBUFFER}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bindFramebuffer(glEnums target, CanvasFrameBuffer* framebuffer)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", framebuffer:" << framebuffer << ")";
+
+ if (target != FRAMEBUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_ENUM framebuffer bind target, must be FRAMEBUFFER";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (framebuffer) {
+ m_currentFramebuffer = framebuffer;
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id());
+ } else {
+ m_currentFramebuffer = 0;
+ glBindFramebuffer(GL_FRAMEBUFFER, m_canvas->drawFBOHandle());
+ }
+}
+
+/*!
+ * \qmlmethod Context3D::glEnums Context3D::checkFramebufferStatus(glEnums target)
+ * Returns the completeness status of the framebuffer object.
+ * \a target must be \c{Context3D.FRAMEBUFFER}.
+ *
+ */
+/*!
+ * \internal
+ */
+CanvasContext::glEnums CanvasContext::checkFramebufferStatus(glEnums target)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ")";
+ if (target != FRAMEBUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_ENUM framebuffer bind target, must be FRAMEBUFFER";
+ m_error = INVALID_ENUM;
+ return FRAMEBUFFER_UNSUPPORTED;
+ }
+
+ if (m_currentFramebuffer) {
+ return glEnums(glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ } else {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_OPERATION no current framebuffer bound";
+ m_error = INVALID_OPERATION;
+ return FRAMEBUFFER_UNSUPPORTED;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::framebufferRenderbuffer(glEnums target, glEnums attachment, glEnums renderbuffertarget, RenderBuffer3D renderbuffer)
+ * Attaches the given \a renderbuffer object to the \a attachment point of the current framebuffer
+ * object.
+ * \a target must be \c{Context3D.FRAMEBUFFER}. \a renderbuffertarget must
+ * be \c{Context3D.RENDERBUFFER}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::framebufferRenderbuffer(glEnums target, glEnums attachment,
+ glEnums renderbuffertarget,
+ CanvasRenderBuffer *renderbuffer)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << "attachment:" << glEnumToString(attachment) << "renderbuffertarget:" << glEnumToString(renderbuffertarget) << ", renderbuffer:" << renderbuffer << ")";
+
+ if (target != FRAMEBUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_ENUM framebuffer bind target, must be FRAMEBUFFER";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (!m_currentFramebuffer) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_OPERATION no current framebuffer bound";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ if (attachment != COLOR_ATTACHMENT0 && attachment != DEPTH_ATTACHMENT
+ && attachment != STENCIL_ATTACHMENT) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_OPERATION attachment must be one of COLOR_ATTACHMENT0, DEPTH_ATTACHMENT or STENCIL_ATTACHMENT";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ if (renderbuffer && renderbuffertarget != RENDERBUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_OPERATION renderbuffertarget must be RENDERBUFFER for non null renderbuffers";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ GLuint renderbufferId = renderbuffer ? renderbuffer->id() : 0;
+
+ glFramebufferRenderbuffer(GLenum(target), GLenum(attachment), GLenum(renderbuffertarget),
+ renderbufferId);
+}
+
+/*!
+ * \qmlmethod void Context3D::framebufferTexture2D(glEnums target, glEnums attachment, glEnums textarget, Texture3D texture, int level)
+ * Attaches the given \a renderbuffer object to the \a attachment point of the current framebuffer
+ * object.
+ * \a target must be \c{Context3D.FRAMEBUFFER}. \a renderbuffertarget must
+ * be \c{Context3D.RENDERBUFFER}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::framebufferTexture2D(glEnums target, glEnums attachment, glEnums textarget,
+ CanvasTexture *texture, int level)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << "attachment:" << glEnumToString(attachment) << "textarget:" << glEnumToString(textarget) << ", texture:" << texture << ", level:" << level << ")";
+
+ if (target != FRAMEBUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_ENUM framebuffer bind target, must be FRAMEBUFFER";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (!m_currentFramebuffer) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_OPERATION no current framebuffer bound";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ if (attachment != COLOR_ATTACHMENT0 && attachment != DEPTH_ATTACHMENT
+ && attachment != STENCIL_ATTACHMENT) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_OPERATION attachment must be one of COLOR_ATTACHMENT0, DEPTH_ATTACHMENT or STENCIL_ATTACHMENT";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ if (texture) {
+ // TODO: If texture is not zero, then texture must either name an existing texture object with an target of textarget, or texture must name an existing cube map texture and textarget must be one of: TEXTURE_CUBE_MAP_POSITIVE_X, TEXTURE_CUBE_MAP_- POSITIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_- Z, TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_Y, or TEXTURE_CUBE_MAP_NEGATIVE_Z. Otherwise, INVALID_OPERATION is gener- ated.
+
+ if (textarget != TEXTURE_2D
+ && textarget != TEXTURE_CUBE_MAP_POSITIVE_X
+ && textarget != TEXTURE_CUBE_MAP_POSITIVE_Y
+ && textarget != TEXTURE_CUBE_MAP_POSITIVE_Z
+ && textarget != TEXTURE_CUBE_MAP_NEGATIVE_X
+ && textarget != TEXTURE_CUBE_MAP_NEGATIVE_Y
+ && textarget != TEXTURE_CUBE_MAP_NEGATIVE_Z) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): textarget attachment must be one of TEXTURE_2D, TEXTURE_CUBE_MAP_POSITIVE_X, TEXTURE_CUBE_MAP_POSITIVE_Y, TEXTURE_CUBE_MAP_POSITIVE_Z, TEXTURE_CUBE_MAP_NEGATIVE_X, TEXTURE_CUBE_MAP_NEGATIVE_Y or TEXTURE_CUBE_MAP_NEGATIVE_Z";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ if (level != 0) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_VALUE level must be 0";
+ m_error = INVALID_VALUE;
+ return;
+ }
+ }
+
+ GLuint textureId = texture ? texture->textureId() : 0;
+ glFramebufferTexture2D(GLenum(target), GLenum(attachment), GLenum(textarget), textureId, level);
+}
+
+/*!
+ * \qmlmethod void Context3D::isFramebuffer(Object anyObject)
+ * Returns true if the given object is a valid FrameBuffer3D object.
+ * \a anyObject is the object that is to be verified as a valid framebuffer.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isFramebuffer(QObject *anyObject)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( anyObject:" << anyObject << ")";
+
+ if (!anyObject)
+ return false;
+
+ QString className = QString(anyObject->metaObject()->className());
+ if (className != "CanvasFrameBuffer")
+ return false;
+
+ CanvasFrameBuffer *fbo = static_cast<CanvasFrameBuffer *>(anyObject);
+ if (!fbo->isAlive())
+ return false;
+
+ return glIsFramebuffer(fbo->id());
+}
+
+/*!
+ * \qmlmethod void Context3D::deleteFramebuffer(FrameBuffer3D buffer)
+ * Deletes the given framebuffer as if by calling \c{glDeleteFramebuffers()}.
+ * Calling this method repeatedly on the same object has no side effects.
+ * \a buffer is the FrameBuffer3D to be deleted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::deleteFramebuffer(CanvasFrameBuffer *buffer)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( buffer:" << buffer << ")";
+
+ if (buffer) {
+ buffer->del();
+ } else {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_VALUE buffer handle";
+ }
+}
+
+/*!
+ * \qmlmethod RenderBuffer3D Context3D::createRenderbuffer()
+ * Returns a created RenderBuffer3D object that is initialized with a renderbuffer object name
+ * as if by calling \c{glGenRenderbuffers()}.
+ */
+/*!
+ * \internal
+ */
+CanvasRenderBuffer *CanvasContext::createRenderbuffer()
+{
+ CanvasRenderBuffer *renderbuffer = new CanvasRenderBuffer(this);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << ":" << renderbuffer;
+
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return renderbuffer;
+}
+
+/*!
+ * \qmlmethod void Context3D::bindRenderbuffer(glEnums target, RenderBuffer3D renderbuffer)
+ * Binds the given \a renderbuffer object to the given \a target.
+ * \a target must be \c{Context3D.RENDERBUFFER}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bindRenderbuffer(glEnums target, CanvasRenderBuffer *renderbuffer)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", renderbuffer:" << renderbuffer << ")";
+
+ if (target != RENDERBUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_ENUM target must be RENDERBUFFER";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (renderbuffer) {
+ m_currentRenderbuffer = renderbuffer;
+ glBindRenderbuffer(GL_FRAMEBUFFER, renderbuffer->id());
+ } else {
+ m_currentRenderbuffer = 0;
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::renderbufferStorage(glEnums target, glEnums internalformat, int width, int height)
+ * Create and initialize a data store for the \c renderbuffer object.
+ * \a target must be \c Context3D.RENDERBUFFER.
+ * \a internalformat specifies the color-renderable, depth-renderable or stencil-renderable format
+ * of the renderbuffer. Must be one of \c{Context3D.RGBA4}, \c{Context3D.RGB565}, \c{Context3D.RGB5_A1},
+ * \c{Context3D.DEPTH_COMPONENT16} or \c{Context3D.STENCIL_INDEX8}.
+ * \a width specifies the renderbuffer width in pixels.
+ * \a height specifies the renderbuffer height in pixels.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::renderbufferStorage(glEnums target, glEnums internalformat,
+ int width, int height)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << "internalformat:" << glEnumToString(internalformat) << "width:" << width << ", height:" << height << ")";
+
+ if (target != RENDERBUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_ENUM target must be RENDERBUFFER";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ glRenderbufferStorage(GLenum(target), GLenum(internalformat), width, height);
+}
+
+/*!
+ * \qmlmethod bool Context3D::isRenderbuffer(Object anyObject)
+ * Returns true if the given object is a valid RenderBuffer3D object.
+ * \a anyObject is the object that is to be verified as a valid renderbuffer.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isRenderbuffer(QObject *anyObject)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( anyObject:" << anyObject << ")";
+
+ if (!anyObject)
+ return false;
+
+ QString className = QString(anyObject->metaObject()->className());
+ if (className != "CanvasRenderBuffer")
+ return false;
+
+ CanvasRenderBuffer *rbo = static_cast<CanvasRenderBuffer *>(anyObject);
+ if (!rbo->isAlive())
+ return false;
+ return glIsRenderbuffer(rbo->id());
+}
+
+/*!
+ * \qmlmethod void Context3D::deleteRenderbuffer(RenderBuffer3D buffer)
+ * Deletes the given renderbuffer as if by calling \c{glDeleteRenderbuffers()}.
+ * Calling this method repeatedly on the same object has no side effects.
+ * \a buffer is the RenderBuffer3D to be deleted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::deleteRenderbuffer(CanvasRenderBuffer *renderbuffer)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( renderbuffer:" << renderbuffer << ")";
+
+ if (renderbuffer) {
+ renderbuffer->del();
+ } else {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << "(): INVALID_VALUE renderbuffer handle";
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::sampleCoverage(float value, bool invert)
+ * Sets the multisample coverage parameters.
+ * \a value specifies the floating-point sample coverage value. The value is clamped to the range
+ * \c{[0, 1]} with initial value of \c{1.0}.
+ * \a invert specifies if coverage masks should be inverted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::sampleCoverage(float value, bool invert)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( value:" << value << ", invert:" << invert << ")";
+ glSampleCoverage(value, invert);
+}
+
+/*!
+ * \qmlmethod Program3D Context3D::createProgram()
+ * Returns a created Program3D object that is initialized with a program object name as if by
+ * calling \c{glCreateProgram()}.
+ */
+/*!
+ * \internal
+ */
+CanvasProgram *CanvasContext::createProgram()
+{
+ CanvasProgram *program = new CanvasProgram(this);
+ if (m_logAllCalls) qDebug() << "createProgram():" << program;
+
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return program;
+}
+
+/*!
+ * \qmlmethod bool Context3D::isProgram(Object anyObject)
+ * Returns true if the given object is a valid Program3D object.
+ * \a anyObject is the object that is to be verified as a valid program.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isProgram(QObject *anyObject)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( anyObject:" << anyObject << ")";
+
+ if (!anyObject)
+ return false;
+
+ QString className = QString(anyObject->metaObject()->className());
+ if (className != "CanvasProgram")
+ return false;
+
+ CanvasProgram *program = static_cast<CanvasProgram *>(anyObject);
+ return program->isAlive();
+}
+
+/*!
+ * \qmlmethod void Context3D::deleteProgram(Program3D program)
+ * Deletes the given program as if by calling \c{glDeleteProgram()}.
+ * Calling this method repeatedly on the same object has no side effects.
+ * \a program is the Program3D to be deleted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::deleteProgram(CanvasProgram *program)
+{
+ if (m_logAllCalls) qDebug() << "deleteProgram( program:" << program << ")";
+
+ if (program) {
+ program->del();
+ } else {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "deleteProgram(): INVALID_VALUE program handle:" << program;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::attachShader(Program3D program, Shader3D shader)
+ * Deletes the given program as if by calling \c{glDeleteProgram()}.
+ * Calling this method repeatedly on the same object has no side effects.
+ * \a program is the Program3D to be deleted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::attachShader(CanvasProgram *program, CanvasShader *shader)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << program << ", " << shader << ")";
+ if (!program || !shader || !program->isAlive())
+ return;
+
+ program->qOGLProgram()->addShader(shader->qOGLShader());
+}
+
+/*!
+ * \qmlmethod void Context3D::detachShader(Program3D program, Shader3D shader)
+ * Detaches given shader object from given program object.
+ * \a program specifies the program object from which to detach the shader.
+ * \a shader specifies the shader object to detach.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::detachShader(CanvasProgram *program, CanvasShader *shader)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << program << ", " << shader << ")";
+ if (!program || !shader || !program->isAlive())
+ return;
+
+ program->qOGLProgram()->removeShader(shader->qOGLShader());
+}
+
+/*!
+ * \qmlmethod void Context3D::linkProgram(Program3D program)
+ * Links the given program object.
+ * \a program specifies the program to be linked.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::linkProgram(CanvasProgram *program)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << program << ")";
+ if (!program || !program->isAlive())
+ return;
+
+ program->qOGLProgram()->link();
+}
+
+/*!
+ * \qmlmethod void Context3D::lineWidth(float width)
+ * Specifies the width of rasterized lines.
+ * \a width specifies the width to be used when rasterizing lines. Initial value is \c{1.0}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::lineWidth(float width)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(width:" << width << ")";
+ glLineWidth(width);
+}
+
+/*!
+ * \qmlmethod void Context3D::polygonOffset(float factor, float units)
+ * Sets scale and units used to calculate depth values.
+ * \a factor specifies the scale factor that is used to create a variable depth offset for each
+ * polygon. Initial value is \c{0.0}.
+ * \a units gets multiplied by an implementation-specific value to create a constant depth offset.
+ * Initial value is \c{0.0}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::polygonOffset(float factor, float units)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(factor:" << factor << ", units:" << units << ")";
+ glPolygonOffset(factor, units);
+}
+
+/*!
+ * \qmlmethod void Context3D::pixelStorei(glEnums pname, int param)
+ * Set the pixel storage modes.
+ * \a pname specifies the name of the parameter to be set. \c Context3D.PACK_ALIGNMENT affects the
+ * packing of pixel data into memory. \c Context3D.UNPACK_ALIGNMENT affects the unpacking of pixel
+ * data from memory.
+ * \a param specifies the value that \a pname is set to.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::pixelStorei(glEnums pname, int param)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(pname:" << glEnumToString(pname) << " param:" << param << ")";
+
+ switch (pname) {
+ case UNPACK_FLIP_Y_WEBGL:
+ qDebug() << "Context3D::" << __FUNCTION__ << "(pname:" << glEnumToString(pname) << " param:" << param << ") NOT IMPLEMENTED!";
+ break;
+ case UNPACK_PREMULTIPLY_ALPHA_WEBGL:
+ qDebug() << "Context3D::" << __FUNCTION__ << "(pname:" << glEnumToString(pname) << " param:" << param << ") NOT IMPLEMENTED!";
+ break;
+ case UNPACK_COLORSPACE_CONVERSION_WEBGL:
+ qDebug() << "Context3D::" << __FUNCTION__ << "(pname:" << glEnumToString(pname) << " param:" << param << ") NOT IMPLEMENTED!";
+ break;
+ default:
+ glPixelStorei(GLenum(pname), param);
+ break;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::hint(glEnums target, glEnums mode)
+ * Set implementation-specific hints.
+ * \a target \c Context3D.GENERATE_MIPMAP_HINT is accepted.
+ * \a mode \c{Context3D.FASTEST}, \c{Context3D.NICEST}, and \c{Context3D.DONT_CARE} are accepted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::hint(glEnums target, glEnums mode)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << " mode:" << glEnumToString(mode) << ")";
+ glHint(GLenum(target), GLenum(mode));
+}
+
+/*!
+ * \qmlmethod void Context3D::enable(glEnums cap)
+ * Enable server side GL capabilities.
+ * \a cap specifies a constant indicating a GL capability.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::enable(glEnums cap)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(flag" << glEnumToString(cap) << ")";
+ glEnable(cap);
+}
+
+/*!
+ * \qmlmethod bool Context3D::isEnabled(glEnums cap)
+ * Returns whether a capability is enabled.
+ * \a cap specifies a constant indicating a GL capability.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isEnabled(glEnums cap)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(flag:" << glEnumToString(cap) << ")";
+ return glIsEnabled(cap);
+}
+
+/*!
+ * \qmlmethod void Context3D::disable(glEnums cap)
+ * Disable server side GL capabilities.
+ * \a cap specifies a constant indicating a GL capability.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::disable(glEnums cap)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(flag:" << glEnumToString(cap) << ")";
+ glDisable(cap);
+}
+
+/*!
+ * \qmlmethod void Context3D::blendColor(float red, float green, float blue, float alpha)
+ * Set the blend color.
+ * \a red, \a green, \a blue and \a alpha specify the components of \c{Context3D.BLEND_COLOR}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::blendColor(float red, float green, float blue, float alpha)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(red:" << red << ", green:" << green << ", blue:" << blue << ", alpha:" << alpha << ")";
+ glBlendColor(red, green, blue, alpha);
+}
+
+/*!
+ * \qmlmethod void Context3D::blendEquation(glEnums mode)
+ * Sets the equation used for both the RGB blend equation and the alpha blend equation
+ * \a mode specifies how source and destination colors are to be combined. Must be
+ * \c{Context3D.FUNC_ADD}, \c{Context3D.FUNC_SUBTRACT} or \c{Context3D.FUNC_REVERSE_SUBTRACT}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::blendEquation(glEnums mode)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(mode:" << glEnumToString(mode) << ")";
+ glBlendEquation(GLenum(mode));
+}
+
+/*!
+ * \qmlmethod void Context3D::blendEquationSeparate(glEnums modeRGB, glEnums modeAlpha)
+ * Set the RGB blend equation and the alpha blend equation separately.
+ * \a modeRGB specifies how the RGB components of the source and destination colors are to be
+ * combined. Must be \c{Context3D.FUNC_ADD}, \c{Context3D.FUNC_SUBTRACT} or
+ * \c{Context3D.FUNC_REVERSE_SUBTRACT}.
+ * \a modeAlpha specifies how the alpha component of the source and destination colors are to be
+ * combined. Must be \c{Context3D.FUNC_ADD}, \c{Context3D.FUNC_SUBTRACT}, or
+ * \c{Context3D.FUNC_REVERSE_SUBTRACT}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::blendEquationSeparate(glEnums modeRGB, glEnums modeAlpha)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(modeRGB:" << glEnumToString(modeRGB) <<
+ ", modeAlpha:" << glEnumToString(modeAlpha) << ")";
+ glBlendEquationSeparate(GLenum(modeRGB), GLenum(modeAlpha));
+}
+
+/*!
+ * \qmlmethod void Context3D::blendFunc(glEnums sfactor, glEnums dfactor)
+ * Sets the pixel arithmetic.
+ * \a sfactor specifies how the RGBA source blending factors are computed. Must be
+ * \c{Context3D.ZERO}, \c{Context3D.ONE}, \c{Context3D.SRC_COLOR}, \c{Context3D.ONE_MINUS_SRC_COLOR},
+ * \c{Context3D.DST_COLOR}, \c{Context3D.ONE_MINUS_DST_COLOR}, \c{Context3D.SRC_ALPHA},
+ * \c{Context3D.ONE_MINUS_SRC_ALPHA}, \c{Context3D.DST_ALPHA}, \c{Context3D.ONE_MINUS_DST_ALPHA},
+ * \c{Context3D.CONSTANT_COLOR}, \c{Context3D.ONE_MINUS_CONSTANT_COLOR}, \c{Context3D.CONSTANT_ALPHA},
+ * \c{Context3D.ONE_MINUS_CONSTANT_ALPHA} or \c{Context3D.SRC_ALPHA_SATURATE}. Initial value is
+ * \c{Context3D.ONE}.
+ * \a dfactor Specifies how the RGBA destination blending factors are computed. Must be
+ * \c{Context3D.ZERO}, \c{Context3D.ONE}, \c{Context3D.SRC_COLOR}, \c{Context3D.ONE_MINUS_SRC_COLOR},
+ * \c{Context3D.DST_COLOR}, \c{Context3D.ONE_MINUS_DST_COLOR}, \c{Context3D.SRC_ALPHA},
+ * \c{Context3D.ONE_MINUS_SRC_ALPHA}, \c{Context3D.DST_ALPHA}, \c{Context3D.ONE_MINUS_DST_ALPHA},
+ * \c{Context3D.CONSTANT_COLOR}, \c{Context3D.ONE_MINUS_CONSTANT_COLOR}, \c{Context3D.CONSTANT_ALPHA} or
+ * \c{Context3D.ONE_MINUS_CONSTANT_ALPHA}. Initial value is \c{Context3D.ZERO}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::blendFunc(glEnums sfactor, glEnums dfactor)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(sfactor:" << glEnumToString(sfactor) <<
+ ", dfactor:" << glEnumToString(dfactor) << ")";
+
+ if (((sfactor == CONSTANT_COLOR || sfactor == ONE_MINUS_CONSTANT_COLOR)
+ && (dfactor == CONSTANT_ALPHA || dfactor == ONE_MINUS_CONSTANT_ALPHA))
+ || ((dfactor == CONSTANT_COLOR || dfactor == ONE_MINUS_CONSTANT_COLOR)
+ && (sfactor == CONSTANT_ALPHA || sfactor == ONE_MINUS_CONSTANT_ALPHA))) {
+ m_error = INVALID_OPERATION;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_OPERATION illegal combination";
+ return;
+ }
+
+ glBlendFunc(GLenum(sfactor), GLenum(dfactor));
+}
+
+/*!
+ * \qmlmethod void Context3D::blendFuncSeparate(glEnums srcRGB, glEnums dstRGB, glEnums srcAlpha, glEnums dstAlpha)
+ * Sets the pixel arithmetic for RGB and alpha components separately.
+ * \a srcRGB specifies how the RGB source blending factors are computed. Must be \c{Context3D.ZERO},
+ * \c{Context3D.ONE}, \c{Context3D.SRC_COLOR}, \c{Context3D.ONE_MINUS_SRC_COLOR}, \c{Context3D.DST_COLOR},
+ * \c{Context3D.ONE_MINUS_DST_COLOR}, \c{Context3D.SRC_ALPHA}, \c{Context3D.ONE_MINUS_SRC_ALPHA},
+ * \c{Context3D.DST_ALPHA}, \c{Context3D.ONE_MINUS_DST_ALPHA}, \c{Context3D.CONSTANT_COLOR},
+ * \c{Context3D.ONE_MINUS_CONSTANT_COLOR}, \c{Context3D.CONSTANT_ALPHA},
+ * \c{Context3D.ONE_MINUS_CONSTANT_ALPHA} or \c{Context3D.SRC_ALPHA_SATURATE}. Initial value is
+ * \c{Context3D.ONE}.
+ * \a dstRGB Specifies how the RGB destination blending factors are computed. Must be
+ * \c{Context3D.ZERO}, \c{Context3D.ONE}, \c{Context3D.SRC_COLOR}, \c{Context3D.ONE_MINUS_SRC_COLOR},
+ * \c{Context3D.DST_COLOR}, \c{Context3D.ONE_MINUS_DST_COLOR}, \c{Context3D.SRC_ALPHA},
+ * \c{Context3D.ONE_MINUS_SRC_ALPHA}, \c{Context3D.DST_ALPHA}, \c{Context3D.ONE_MINUS_DST_ALPHA},
+ * \c{Context3D.CONSTANT_COLOR}, \c{Context3D.ONE_MINUS_CONSTANT_COLOR}, \c{Context3D.CONSTANT_ALPHA} or
+ * \c{Context3D.ONE_MINUS_CONSTANT_ALPHA}. Initial value is \c{Context3D.ZERO}.
+ * \a srcAlpha specifies how the alpha source blending factors are computed. Must be
+ * \c{Context3D.ZERO}, \c{Context3D.ONE}, \c{Context3D.SRC_COLOR}, \c{Context3D.ONE_MINUS_SRC_COLOR},
+ * \c{Context3D.DST_COLOR}, \c{Context3D.ONE_MINUS_DST_COLOR}, \c{Context3D.SRC_ALPHA},
+ * \c{Context3D.ONE_MINUS_SRC_ALPHA}, \c{Context3D.DST_ALPHA}, \c{Context3D.ONE_MINUS_DST_ALPHA},
+ * \c{Context3D.CONSTANT_COLOR}, \c{Context3D.ONE_MINUS_CONSTANT_COLOR}, \c{Context3D.CONSTANT_ALPHA},
+ * \c{Context3D.ONE_MINUS_CONSTANT_ALPHA} or \c{Context3D.SRC_ALPHA_SATURATE}. Initial value is
+ * \c{Context3D.ONE}.
+ * \a dstAlpha Specifies how the alpha destination blending factors are computed. Must be
+ * \c{Context3D.ZERO}, \c{Context3D.ONE}, \c{Context3D.SRC_COLOR}, \c{Context3D.ONE_MINUS_SRC_COLOR},
+ * \c{Context3D.DST_COLOR}, \c{Context3D.ONE_MINUS_DST_COLOR}, \c{Context3D.SRC_ALPHA},
+ * \c{Context3D.ONE_MINUS_SRC_ALPHA}, \c{Context3D.DST_ALPHA}, \c{Context3D.ONE_MINUS_DST_ALPHA},
+ * \c{Context3D.CONSTANT_COLOR}, \c{Context3D.ONE_MINUS_CONSTANT_COLOR}, \c{Context3D.CONSTANT_ALPHA} or
+ * \c{Context3D.ONE_MINUS_CONSTANT_ALPHA}. Initial value is \c{Context3D.ZERO}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::blendFuncSeparate(glEnums srcRGB, glEnums dstRGB, glEnums srcAlpha,
+ glEnums dstAlpha)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(srcRGB:" << glEnumToString(srcRGB) <<
+ ", dstRGB:" << glEnumToString(dstRGB) <<
+ ", srcAlpha:" << glEnumToString(srcAlpha) <<
+ ", dstAlpha:" << glEnumToString(dstAlpha) << ")";
+
+ if (((srcRGB == CONSTANT_COLOR || srcRGB == ONE_MINUS_CONSTANT_COLOR )
+ && (dstRGB == CONSTANT_ALPHA || dstRGB == ONE_MINUS_CONSTANT_ALPHA ))
+ || ((dstRGB == CONSTANT_COLOR || dstRGB == ONE_MINUS_CONSTANT_COLOR )
+ && (srcRGB == CONSTANT_ALPHA || srcRGB == ONE_MINUS_CONSTANT_ALPHA ))) {
+ m_error = INVALID_OPERATION;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_OPERATION illegal combination";
+ return;
+ }
+
+ glBlendFuncSeparate(GLenum(srcRGB), GLenum(dstRGB), GLenum(srcAlpha), GLenum(dstAlpha));
+}
+
+/*!
+ * \qmlmethod variant Context3D::getProgramParameter(Program3D program, glEnums paramName)
+ * Return the value for the passed \a paramName given the passed \a program. The type returned is
+ * the natural type for the requested paramName.
+ * \a paramName must be \c{Context3D.DELETE_STATUS}, \c{Context3D.LINK_STATUS},
+ * \c{Context3D.VALIDATE_STATUS}, \c{Context3D.ATTACHED_SHADERS}, \c{Context3D.ACTIVE_ATTRIBUTES} or
+ * \c{Context3D.ACTIVE_UNIFORMS}.
+ */
+/*!
+ * \internal
+ */
+QVariant CanvasContext::getProgramParameter(CanvasProgram *program, glEnums paramName)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(program:" << program << ", paramName:" << glEnumToString(paramName) << ")";
+
+ if (!program || !program->isAlive())
+ return 0;
+
+ switch(paramName) {
+ case DELETE_STATUS:
+ // Intentional flow through
+ case LINK_STATUS:
+ // Intentional flow through
+ case VALIDATE_STATUS: {
+ GLint value = 0;
+ glGetProgramiv(program->qOGLProgram()->programId(), GLenum(paramName), &value);
+ if (m_logAllCalls) qDebug() << " getProgramParameter returns " << value;
+ return QVariant::fromValue(value == GL_TRUE);
+ }
+ case ATTACHED_SHADERS:
+ // Intentional flow through
+ case ACTIVE_ATTRIBUTES:
+ // Intentional flow through
+ case ACTIVE_UNIFORMS: {
+ GLint value = 0;
+ glGetProgramiv(program->qOGLProgram()->programId(), GLenum(paramName), &value);
+ if (m_logAllCalls) qDebug() << " getProgramParameter returns " << value;
+ return QVariant::fromValue(value);
+ }
+ default: {
+ // TODO: Implement rest of the parameters
+ m_error = INVALID_ENUM;
+ qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_ENUM illegal parameter name ";
+ return QVariant::fromValue(0);
+ }
+ }
+}
+
+/*!
+ * \qmlmethod Shader3D Context3D::createShader(glEnums type)
+ * Creates a shader of \a type. Must be either \c Context3D.VERTEX_SHADER or
+ * \c{Context3D.FRAGMENT_SHADER}.
+ */
+/*!
+ * \internal
+ */
+CanvasShader *CanvasContext::createShader(glEnums type)
+{
+ switch (type) {
+ case VERTEX_SHADER:
+ if (m_logAllCalls) qDebug() << "Context3D::createShader(VERTEX_SHADER)";
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return new CanvasShader(QOpenGLShader::Vertex, this);
+ case FRAGMENT_SHADER:
+ if (m_logAllCalls) qDebug() << "Context3D::createShader(FRAGMENT_SHADER)";
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return new CanvasShader(QOpenGLShader::Fragment, this);
+ default:
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM unknown shader type:" << glEnumToString(type);
+ m_error = INVALID_ENUM;
+ return 0;
+ }
+}
+
+/*!
+ * \qmlmethod bool Context3D::isShader(Object anyObject)
+ * Returns true if the given object is a valid Shader3D object.
+ * \a anyObject is the object that is to be verified as a valid shader.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isShader(QObject *anyObject)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( anyObject:" << anyObject << ")";
+
+ if (!anyObject)
+ return false;
+
+ QString className = QString(anyObject->metaObject()->className());
+ if (className != "CanvasShader")
+ return false;
+
+ CanvasShader *shader = static_cast<CanvasShader *>(anyObject);
+ return shader->isAlive();
+}
+
+/*!
+ * \qmlmethod void Context3D::deleteShader(Shader3D shader)
+ * Deletes the given shader as if by calling \c{glDeleteShader()}.
+ * Calling this method repeatedly on the same object has no side effects.
+ * \a shader is the Shader3D to be deleted.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::deleteShader(CanvasShader *shader)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( shader:" << shader << ")";
+
+ if (shader) {
+ shader->del();
+ } else {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ <<": invalid shader handle:" << shader;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::shaderSource(Shader3D shader, string shaderSource)
+ * Replaces the shader source code in the given shader object.
+ * \a shader specifies the shader object whose source code is to be replaced.
+ * \a shaderSource specifies the source code to be loaded in to the shader.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::shaderSource(CanvasShader *shader, const QString &shaderSource)
+{
+#if defined(QT_OPENGL_ES_2)
+ QString modSource = shaderSource;
+#else
+ QString modSource = "#version 120 \n#define precision \n"+ shaderSource;
+#endif
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( shader:" << shader << ", shaderSource"<< ")" << endl << modSource << endl;
+ if (!shader) {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ <<": invalid shader handle:" << shader;
+ return;
+ }
+ shader->setSourceCode(modSource);
+}
+
+
+/*!
+ * \qmlmethod string Context3D::getShaderSource(Shader3D shader)
+ * Returns the source code string from the \a shader object.
+ */
+/*!
+ * \internal
+ */
+QString CanvasContext::getShaderSource(CanvasShader *shader)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( shader:" << shader << ")";
+ if (!shader) {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ <<": invalid shader handle:" << shader;
+ return m_emptyString;
+ }
+
+ // Returning a copy, V4VM takes ownership
+ return QString(shader->qOGLShader()->sourceCode());
+}
+
+/*!
+ * \qmlmethod void Context3D::compileShader(Shader3D shader)
+ * Compiles the given \a shader object.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::compileShader(CanvasShader *shader)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( shader:" << shader << ")";
+ if (!shader) {
+ m_error = INVALID_VALUE;
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ <<": invalid shader handle:" << shader;
+ return;
+ }
+ shader->qOGLShader()->compileSourceCode(shader->sourceCode());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform1i(UniformLocation location, int x)
+ * Sets the single integer value given in \a x to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform1i(CanvasUniformLocation *location, int x)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ")";
+ if (!location)
+ return;
+
+ glUniform1i(location->id(), x);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform1iv(UniformLocation location, Int32Array array)
+ * Sets the integer array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform1iv(CanvasUniformLocation *location, CanvasInt32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform1iv(location->id(), array->length(), (int *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform1f(UniformLocation location, float x)
+ * Sets the single float value given in \a x to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform1f(CanvasUniformLocation *location, float x)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ")";
+ if (!location)
+ return;
+
+ glUniform1f(location->id(), x);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform1fv(UniformLocation location, Float32Array array)
+ * Sets the float array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform1fv(CanvasUniformLocation *location, CanvasFloat32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform1fv(location->id(), array->length(), (float *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform2f(UniformLocation location, float x, float y)
+ * Sets the two float values given in \a x and \a y to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform2f(CanvasUniformLocation *location, float x, float y)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ", y:" << y << ")";
+ if (!location)
+ return;
+
+ glUniform2f(location->id(), x, y);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform2fv(UniformLocation location, Float32Array array)
+ * Sets the float array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform2fv(CanvasUniformLocation *location, CanvasFloat32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform2fv(location->id(), array->length() / 2, (float *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform2i(UniformLocation location, int x, int y)
+ * Sets the two integer values given in \a x and \a y to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform2i(CanvasUniformLocation *location, int x, int y)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ", y:" << y << ")";
+ if (!location)
+ return;
+
+ glUniform2i(location->id(), x, y);
+
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform2iv(UniformLocation location, Int32Array array)
+ * Sets the integer array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform2iv(CanvasUniformLocation *location, CanvasInt32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform2iv(location->id(), array->length() / 2, (int *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform3f(UniformLocation location, float x, float y, float z)
+ * Sets the three float values given in \a x , \a y and \a z to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform3f(CanvasUniformLocation *location, float x, float y, float z)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ", y:" << y << ", z:" << z << ")";
+ if (!location)
+ return;
+
+ glUniform3f(location->id(), x, y, z);
+
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform3fv(UniformLocation location, Float32Array array)
+ * Sets the float array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform3fv(CanvasUniformLocation *location, CanvasFloat32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform3fv(location->id(), array->length() / 3, (float *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform3i(UniformLocation location, int x, int y, int z)
+ * Sets the three integer values given in \a x , \a y and \a z to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform3i(CanvasUniformLocation *location, int x, int y, int z)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ", y:" << y << ", z:" << z << ")";
+ if (!location)
+ return;
+
+ glUniform3i(location->id(), x, y, z);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform3iv(UniformLocation location, Int32Array array)
+ * Sets the integer array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform3iv(CanvasUniformLocation *location, CanvasInt32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform3iv(location->id(), array->length() / 3, (int *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform4f(UniformLocation location, float x, float y, float z, float w)
+ * Sets the four float values given in \a x , \a y , \a z and \a w to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform4f(CanvasUniformLocation *location, float x, float y, float z, float w)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ", y:" << y << ", z:" << z << ", w:" << w << ")";
+ if (!location)
+ return;
+
+ glUniform4f(location->id(), x, y, z, w);
+
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform4fv(UniformLocation location, Float32Array array)
+ * Sets the float array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform4fv(CanvasUniformLocation *location, CanvasFloat32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform4fv(location->id(), array->length() / 4, (float *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform4i(UniformLocation location, int x, int y, int z, int w)
+ * Sets the four integer values given in \a x , \a y , \a z and \a w to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform4i(CanvasUniformLocation *location, int x, int y, int z, int w)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", x:" << x << ", y:" << y << ", z:" << z << ", w:" << w << ")";
+ if (!location)
+ return;
+
+ glUniform4i(location->id(), x, y, z, w);
+
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform4iv(UniformLocation location, Int32Array array)
+ * Sets the integer array given in \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform4iv(CanvasUniformLocation *location, CanvasInt32Array *array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ if (!location || !array)
+ return;
+
+ glUniform4iv(location->id(), array->length() / 4, (int *)array->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform1fva(UniformLocation location, list<variant> array)
+ * Sets the float array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform1fva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ float *arrayData = new float[array.length()];
+ ArrayUtils::fillFloatArrayFromVariantList(array, arrayData);
+ glUniform1fv(location->id(), array.count(), arrayData);
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform2fva(UniformLocation location, list<variant> array)
+ * Sets the float array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform2fva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ float *arrayData = new float[array.length()];
+ ArrayUtils::fillFloatArrayFromVariantList(array, arrayData);
+ glUniform2fv(location->id(), array.count() / 2, arrayData);
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform3fva(UniformLocation location, list<variant> array)
+ * Sets the float array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform3fva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ float *arrayData = new float[array.length()];
+ ArrayUtils::fillFloatArrayFromVariantList(array, arrayData);
+ glUniform3fv(location->id(), array.count() / 3, arrayData);
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform4fva(UniformLocation location, list<variant> array)
+ * Sets the float array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform4fva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ float *arrayData = new float[array.count()];
+ ArrayUtils::fillFloatArrayFromVariantList(array, arrayData);
+ glUniform4fv(location->id(), array.count() / 4, arrayData);
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform1iva(UniformLocation location, list<variant> array)
+ * Sets the integer array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform1iva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ int *arrayData = new int[array.length()];
+ ArrayUtils::fillIntArrayFromVariantList(array, arrayData);
+ glUniform1iv(location->id(), array.count(), arrayData);
+ delete arrayData;
+
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform2iva(UniformLocation location, list<variant> array)
+ * Sets the integer array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform2iva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ int *arrayData = new int[array.length()];
+ ArrayUtils::fillIntArrayFromVariantList(array, arrayData);
+ glUniform2iv(location->id(), array.count() / 2, arrayData);
+ delete arrayData;
+
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform3iva(UniformLocation location, list<variant> array)
+ * Sets the integer array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform3iva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ int *arrayData = new int[array.length()];
+ ArrayUtils::fillIntArrayFromVariantList(array, arrayData);
+ glUniform3iv(location->id(), array.count() / 3, arrayData);
+ delete arrayData;
+
+}
+
+/*!
+ * \qmlmethod void Context3D::uniform4iva(UniformLocation location, list<variant> array)
+ * Sets the integer array given as JavasScript \a array to the given uniform \a location.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniform4iva(CanvasUniformLocation *location, QVariantList array)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( location:" << location << ", array:" << array << ")";
+ int *arrayData = new int[array.length()];
+ ArrayUtils::fillIntArrayFromVariantList(array, arrayData);
+ glUniform4iv(location->id(), array.length() / 4, arrayData);
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib1f(int indx, float x)
+ * Sets the single float value given in \a x to the generic vertex attribute index specified
+ * by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib1f(unsigned int indx, float x)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", x:" << x << ")";
+ glVertexAttrib1f(indx, x);
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib1fv(int indx, Float32Array array)
+ * Sets the float array given in \a array to the generic vertex attribute index
+ * specified by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib1fv(unsigned int indx, CanvasFloat32Array *values)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", values:" << values << ")";
+ glVertexAttrib1fv(indx, (float *)values->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib2f(int indx, float x, float y)
+ * Sets the two float values given in \a x and \a y to the generic vertex attribute index
+ * specified by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib2f(unsigned int indx, float x, float y)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", x:" << x << ", y:" << y << ")";
+ glVertexAttrib2f(indx, x, y);
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib2fv(int indx, Float32Array array)
+ * Sets the float array given in \a array to the generic vertex attribute index
+ * specified by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib2fv(unsigned int indx, CanvasFloat32Array *values)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", values:" << values << ")";
+ glVertexAttrib2fv(indx, (float *)values->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib3f(int indx, float x, float y, float z)
+ * Sets the three float values given in \a x , \a y and \a z to the generic vertex attribute index
+ * specified by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib3f(unsigned int indx, float x, float y, float z)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", x:" << x << ", y:" << y << ", z:" << z << ")";
+ glVertexAttrib3f(indx, x, y, z);
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib3fv(int indx, Float32Array array)
+ * Sets the float array given in \a array to the generic vertex attribute index
+ * specified by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib3fv(unsigned int indx, CanvasFloat32Array *values)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", values:" << values << ")";
+ glVertexAttrib3fv(indx, (float *)values->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib4f(int indx, float x, float y, float z, float w)
+ * Sets the four float values given in \a x , \a y , \a z and \a w to the generic vertex attribute
+ * index specified by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib4f(unsigned int indx, float x, float y, float z, float w)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", x:" << x << ", y:" << y << ", z:" << z << ", w:" << w << ")";
+ glVertexAttrib4f(indx, x, y, z, w);
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttrib4fv(int indx, Float32Array array)
+ * Sets the float array given in \a array to the generic vertex attribute index
+ * specified by \a indx.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttrib4fv(unsigned int indx, CanvasFloat32Array *values)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__<< "( indx:" << indx << ", values:" << values << ")";
+ glVertexAttrib4fv(indx, (float *)values->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod int Context3D::getShaderParameter(Shader3D shader, glEnums pname)
+ * Returns the value of the passed \a pname for the given \a shader.
+ * \a pname must be one of \c{Context3D.SHADER_TYPE}, \c Context3D.DELETE_STATUS and
+ * \c{Context3D.COMPILE_STATUS}.
+ */
+/*!
+ * \internal
+ */
+int CanvasContext::getShaderParameter(CanvasShader *shader, glEnums pname)
+{
+ if (m_logAllCalls) qDebug() << "getShaderParameter(" << shader << ", "<< glEnumToString(pname) << ")";
+ if (!shader)
+ return 0;
+
+ switch (pname) {
+ case SHADER_TYPE: {
+ GLint shaderType = 0;
+ glGetShaderiv( shader->qOGLShader()->shaderId(), GL_SHADER_TYPE, &shaderType);
+ return shaderType;
+ }
+ case DELETE_STATUS: {
+ bool isDeleted = !shader->isAlive();
+ if (m_logAllCalls) qDebug() << " getShaderParameter returns " << isDeleted;
+ return (isDeleted ? GL_TRUE : GL_FALSE);
+ }
+ case COMPILE_STATUS: {
+ bool isCompiled = shader->qOGLShader()->isCompiled();
+ if (m_logAllCalls) qDebug() << " getShaderParameter returns " << isCompiled;
+ return (isCompiled ? GL_TRUE : GL_FALSE);
+ }
+ default: {
+ qDebug() << "getShaderParameter() : UNSUPPORTED parameter name " << glEnumToString(pname);
+ return 0;
+ }
+ }
+}
+
+/*!
+ * \qmlmethod Buffer3D Context3D::createBuffer()
+ * Creates a Buffer3D object and initializes it with a buffer object name as if \c glGenBuffers()
+ * was called.
+ */
+/*!
+ * \internal
+ */
+CanvasBuffer *CanvasContext::createBuffer()
+{
+ CanvasBuffer *newBuffer = new CanvasBuffer(this);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << ":" << newBuffer;
+
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return newBuffer;
+}
+
+/*!
+ * \qmlmethod UniformLocation Context3D::getUniformLocation(Program3D program, string name)
+ * Returns UniformLocation object that represents the location of a specific uniform variable
+ * with the given \a name within the given \a program object.
+ * Returns \c null if name doesn't correspond to a uniform variable.
+ */
+/*!
+ * \internal
+ */
+CanvasUniformLocation *CanvasContext::getUniformLocation(CanvasProgram *program, const QString &name)
+{
+ if (!program) {
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(program:" << program << ", name:" << name << "):-1";
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID Program3D reference " << program;
+ return 0;
+ }
+
+ int index = program->qOGLProgram()->uniformLocation(name);
+ if (index < 0) {
+ //if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID name " << name;
+ return 0;
+ }
+
+ CanvasUniformLocation *location = new CanvasUniformLocation(index, this);
+ location->setName(name);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" <<program<< ", " <<name << "):" << location;
+
+ // Returning a pointer to QObject that has parent set
+ // -> V4VM should respect this and ownership should remain with this class
+ return location;
+}
+
+/*!
+ * \qmlmethod int Context3D::getAttribLocation(Program3D program, string name)
+ * Returns location of the given attribute variable \a name in the given \a program.
+ */
+/*!
+ * \internal
+ */
+int CanvasContext::getAttribLocation(CanvasProgram *program, const QString &name)
+{
+ if (!program) {
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" <<program<< ", " <<name << "):-1";
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID Program3D reference " << program;
+ return -1;
+ } else {
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" <<program<< ", " <<name << "):" << program->qOGLProgram()->attributeLocation(name);
+ }
+
+ return program->qOGLProgram()->attributeLocation(name);
+}
+
+/*!
+ * \qmlmethod void Context3D::bindAttribLocation(Program3D program, int index, string name)
+ * Binds the attribute \a index with the attribute variable \a name in the given \a program.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bindAttribLocation(CanvasProgram *program, int index, const QString &name)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" <<program<< ", " << index << ", " << name << ")";
+ if (!program) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID Program3D reference " << program;
+ return;
+ }
+
+ program->qOGLProgram()->bindAttributeLocation(name, index);
+}
+
+/*!
+ * \qmlmethod void Context3D::enableVertexAttribArray(int index)
+ * Enables the vertex attribute array at \a index.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::enableVertexAttribArray(int index)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << index << ")";
+ glEnableVertexAttribArray(index);
+}
+
+/*!
+ * \qmlmethod void Context3D::disableVertexAttribArray(int index)
+ * Disables the vertex attribute array at \a index.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::disableVertexAttribArray(int index)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << index << ")";
+ glDisableVertexAttribArray(index);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniformMatrix2fv(UniformLocation uniformLocation, bool transpose, Float32Array value)
+ * Converts the float array given in \a value to a 2x2 matrix and sets it to the given
+ * uniform at \a uniformLocation. Applies \a transpose if set to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniformMatrix2fv(CanvasUniformLocation *uniformLocation, bool transpose,
+ CanvasFloat32Array *value)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << uniformLocation << ", " << transpose << ", Float32Array value:" << value <<")";
+ if (!m_currentProgram || !uniformLocation || !value)
+ return;
+ if (m_logAllCalls) qDebug() << " numMatrices:" << (value->length() / 4);
+
+ int location = uniformLocation->id();
+ float *arrayData = (float *)value->rawDataCptr();
+ int numMatrices = value->length() / 4;
+
+ glUniformMatrix2fv(location, numMatrices, transpose, arrayData);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniformMatrix3fv(UniformLocation uniformLocation, bool transpose, Float32Array value)
+ * Converts the float array given in \a value to a 3x3 matrix and sets it to the given
+ * uniform at \a uniformLocation. Applies \a transpose if set to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniformMatrix3fv(CanvasUniformLocation *uniformLocation, bool transpose,
+ CanvasFloat32Array *value)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << uniformLocation << ", " << transpose << ", Float32Array value:" << value <<")";
+ if (!m_currentProgram || !uniformLocation || !value)
+ return;
+ if (m_logAllCalls) qDebug() << " numMatrices:" << (value->length() / 9);
+
+ int location = uniformLocation->id();
+ float *arrayData = (float *) value->rawDataCptr();
+ int numMatrices = value->length() / 9;
+
+ glUniformMatrix3fv(location, numMatrices, transpose, arrayData);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniformMatrix4fv(UniformLocation uniformLocation, bool transpose, Float32Array value)
+ * Converts the float array given in \a value to a 4x4 matrix and sets it to the given
+ * uniform at \a uniformLocation. Applies \a transpose if set to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniformMatrix4fv(CanvasUniformLocation *uniformLocation, bool transpose,
+ CanvasFloat32Array *value)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(" << uniformLocation << ", " << transpose << ", Float32Array value:" << value << ")";
+ if (!m_currentProgram || !uniformLocation || !value)
+ return;
+
+ if (m_logAllCalls) qDebug() << " numMatrices:" << (value->length() / 16);
+ int location = uniformLocation->id();
+ float *arrayData = (float *)value->rawDataCptr();
+ int numMatrices = value->length() / 16;
+
+ glUniformMatrix4fv(location, numMatrices, transpose, arrayData);
+}
+
+/*!
+ * \qmlmethod void Context3D::uniformMatrix4fva(UniformLocation uniformLocation, bool transpose, list<variant> value)
+ * Converts the float array given in \a value to a 4x4 matrix and sets it to the given
+ * uniform at \a uniformLocation. Applies \a transpose if set to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniformMatrix4fva(CanvasUniformLocation *uniformLocation, bool transpose,
+ QVariantList value)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(uniformLocation" << uniformLocation << ", transpose:" << transpose << ", QVariantList value:" << value <<", numMatrices:" << (value.count() /16) << ")";
+ if (!m_currentProgram || !uniformLocation)
+ return;
+
+ int location = uniformLocation->id();
+ int size = value.count();
+ float *arrayData = new float[size];
+ int numMatrices = size / 16;
+
+ ArrayUtils::fillFloatArrayFromVariantList(value, arrayData);
+
+ glUniformMatrix4fv(location, numMatrices, transpose, arrayData);
+
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::uniformMatrix3fva(UniformLocation uniformLocation, bool transpose, list<variant> value)
+ * Converts the float array given in \a value to a 3x3 matrix and sets it to the given
+ * uniform at \a uniformLocation. Applies \a transpose if set to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniformMatrix3fva(CanvasUniformLocation *uniformLocation, bool transpose,
+ QVariantList value)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(uniformLocation" << uniformLocation << ", transpose:" << transpose << ", QVariantList value:" << value <<", numMatrices:" << (value.count() /9) << ")";
+ if (!m_currentProgram || !uniformLocation)
+ return;
+
+ int location = uniformLocation->id();
+ int size = value.count();
+ float *arrayData = new float[size];
+ int numMatrices = size / 9;
+
+ ArrayUtils::fillFloatArrayFromVariantList(value, arrayData);
+
+ glUniformMatrix3fv(location, numMatrices, transpose, arrayData);
+
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::uniformMatrix2fva(UniformLocation uniformLocation, bool transpose, list<variant> value)
+ * Converts the float array given in \a value to a 2x2 matrix and sets it to the given
+ * uniform at \a uniformLocation. Applies \a transpose if set to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::uniformMatrix2fva(CanvasUniformLocation *uniformLocation, bool transpose,
+ QVariantList value)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(uniformLocation" << uniformLocation << ", transpose:" << transpose << ", QVariantList value:" << value <<", numMatrices:" << (value.count() /4) << ")";
+
+ if (!m_currentProgram || !uniformLocation)
+ return;
+
+ int location = uniformLocation->id();
+ int size = value.count();
+ float *arrayData = new float[size];
+ int numMatrices = size / 4;
+
+ ArrayUtils::fillFloatArrayFromVariantList(value, arrayData);
+
+ glUniformMatrix2fv(location, numMatrices, transpose, arrayData);
+
+ delete arrayData;
+}
+
+/*!
+ * \qmlmethod void Context3D::vertexAttribPointer(int indx, int size, glEnums type, bool normalized, int stride, long offset)
+ * Sets the currently bound array buffer to the vertex attribute at the index passed at \a indx.
+ * \a size is the number of components per attribute. \a stride specifies the byte offset between
+ * consecutive vertex attributes. \a offset specifies the byte offset to the first vertex attribute
+ * in the array. If int values should be normalized, set \a normalized to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::vertexAttribPointer(int indx, int size, glEnums type,
+ bool normalized, int stride, long offset)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( indx:" << indx << ", size: " << size << ", type:" << glEnumToString(type) << ", normalized:" << normalized << ", stride:" << stride << ", offset:" << offset << ")";
+
+ // TODO: Fix offset
+ glVertexAttribPointer(indx, size, GLenum(type), normalized, stride, (GLvoid *)offset);
+}
+
+
+/*!
+ * \qmlmethod void Context3D::bufferData(glEnums target, long size, glEnums usage)
+ * Sets the size of the \a target buffer to \a size. Target buffer must be either
+ * \c Context3D.ARRAY_BUFFER or \c{Context3D.ELEMENT_ARRAY_BUFFER}. \a usage sets the usage pattern
+ * of the data, and must be one of \c{Context3D.STREAM_DRAW}, \c{Context3D.STATIC_DRAW}, or
+ * \c{Context3D.DYNAMIC_DRAW}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bufferData(glEnums target, long size, glEnums usage)
+{
+ // TODO: Sort this out, it doesn't follow any reason or rhyme...
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", size:" << size << ", usage:" << glEnumToString(usage) << ")";
+
+ CanvasTypedArray *tempArray;
+ switch (target) {
+ case ARRAY_BUFFER:
+ if (!m_currentArrayBuffer) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION called with no ARRAY_BUFFER bound";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ tempArray = createTypedArray(FLOAT, size);
+ break;
+ case ELEMENT_ARRAY_BUFFER:
+ if (!m_currentElementArrayBuffer) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION called with no ELEMENT_ARRAY_BUFFER bound";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ tempArray = createTypedArray(UNSIGNED_SHORT, size);
+ break;
+ default:
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM unknown target";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ glBufferData(GLenum(target), size, (GLvoid *)tempArray->rawDataCptr(), GLenum(usage));
+ delete tempArray;
+}
+
+/*!
+ * \qmlmethod TypedArray Context3D::createTypedArray(glEnums dataType, long size)
+ * Returns a new TypedArray of the given \a dataType with the given \a size. Type must be one of
+ * \c{Context3D.BYTE}, \c{Context3D.UNSIGNED_BYTE}, \c{Context3D.SHORT},
+ * \c{Context3D.UNSIGNED_SHORT}, \c{Context3D.INT}, \c{Context3D.UNSIGNED_INT},
+ * or \c{Context3D.FLOAT}.
+ */
+/*!
+ * \internal
+ */
+CanvasTypedArray *CanvasContext::createTypedArray(glEnums dataType, long size)
+{
+ switch (dataType) {
+ case BYTE:
+ return new CanvasInt8Array(size, this);
+ case UNSIGNED_BYTE:
+ return new CanvasUint8Array(size, this);
+ case SHORT:
+ return new CanvasInt16Array(size, this);
+ case UNSIGNED_SHORT:
+ return new CanvasUint16Array(size, this);
+ case INT:
+ return new CanvasInt32Array(size, this);
+ case UNSIGNED_INT:
+ return new CanvasUint32Array(size, this);
+ case FLOAT:
+ return new CanvasFloat32Array(size, this);
+ default:
+ return 0;
+ }
+}
+
+/*!
+ * \qmlmethod void Context3D::bufferData(glEnums target, TypedArray typedArray, glEnums usage)
+ * Writes the data held in \a typedArray to the \a target buffer. Target buffer must be either
+ * \c Context3D.ARRAY_BUFFER or \c{Context3D.ELEMENT_ARRAY_BUFFER}. \a usage sets the usage pattern
+ * of the data, and must be one of \c{Context3D.STREAM_DRAW}, \c{Context3D.STATIC_DRAW}, or
+ * \c{Context3D.DYNAMIC_DRAW}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bufferData(glEnums target, CanvasTypedArray *typedArray, glEnums usage)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", typedArray:" << typedArray << ", usage:" << glEnumToString(usage) << ")";
+
+ if (!typedArray) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_VALUE called with null data";
+ m_error = INVALID_VALUE;
+ return;
+ }
+
+ if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM target must be either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ glBufferData(GLenum(target), typedArray->byteLength(), (GLvoid *)typedArray->rawDataCptr(),
+ GLenum(usage));
+}
+
+/*!
+ * \qmlmethod void Context3D::bufferData(glEnums target, ArrayBuffer data, glEnums usage)
+ * Writes the \a data to the \a target buffer. Target buffer must be either
+ * \c Context3D.ARRAY_BUFFER or \c{Context3D.ELEMENT_ARRAY_BUFFER}. \a usage sets the usage pattern
+ * of the data, and must be one of \c{Context3D.STREAM_DRAW}, \c{Context3D.STATIC_DRAW}, or
+ * \c{Context3D.DYNAMIC_DRAW}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bufferData(glEnums target, CanvasArrayBuffer &data, glEnums usage)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", data: , usage:" << glEnumToString(usage) << ")";
+
+ if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM target must be either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ glBufferData(GLenum(target), data.byteLength(), (GLvoid*)data.rawData(), GLenum(usage));
+}
+
+/*!
+ * \qmlmethod void Context3D::bufferSubData(glEnums target, int offset, TypedArray typedArray)
+ * Writes data starting from \a offset held in \a typedArray to the \a target buffer. Target
+ * buffer must be either \c Context3D.ARRAY_BUFFER or \c{Context3D.ELEMENT_ARRAY_BUFFER}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bufferSubData(glEnums target, int offset, CanvasTypedArray *typedArray)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", offset:"<< offset << ", typedArray:" << typedArray << ")";
+
+ if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM target must be either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (!typedArray) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": INVALID_VALUE called with null data";
+ m_error = INVALID_VALUE;
+ return;
+ }
+
+ glBufferSubData(GLenum(target), offset, typedArray->byteLength(),
+ (GLvoid*)typedArray->rawDataCptr());
+}
+
+/*!
+ * \qmlmethod void Context3D::bufferSubData(glEnums target, int offset, ArrayBuffer data)
+ * Writes \a data starting from \a offset to the \a target buffer. Target
+ * buffer must be either \c Context3D.ARRAY_BUFFER or \c{Context3D.ELEMENT_ARRAY_BUFFER}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bufferSubData(glEnums target, int offset, CanvasArrayBuffer &data)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", offset:"<< offset << ", data.byteLength:" << data.byteLength() << ")";
+
+ if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM target must be either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ glBufferSubData(GLenum(target), offset, data.byteLength(), (GLvoid*)data.rawData());
+}
+
+/*!
+ * \qmlmethod variant Context3D::getBufferParameter(glEnums target, glEnums pname)
+ * Returns the value for the passed \a pname of the \a target. Target
+ * must be either \c Context3D.ARRAY_BUFFER or \c{Context3D.ELEMENT_ARRAY_BUFFER}. pname must be
+ * either \c Context3D.BUFFER_SIZE or \c{Context3D.BUFFER_USAGE}.
+ */
+/*!
+ * \internal
+ */
+QVariant CanvasContext::getBufferParameter(glEnums target, glEnums pname)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(target:" << glEnumToString(target) << ", pname" << glEnumToString(pname) << ")";
+
+ if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM target must be either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.";
+ m_error = INVALID_ENUM;
+ return 0;
+ }
+
+ switch (pname) {
+ case BUFFER_SIZE:
+ case BUFFER_USAGE:
+ GLint data;
+ glGetBufferParameteriv(GLenum(target), GLenum(pname), &data);
+
+ // TODO: What happens here regarding ownership?
+ return QVariant(data);
+ default:
+ if (m_logAllErrors) qDebug() << "getBufferParameter() : UNKNOWN pname";
+ m_error = INVALID_ENUM;
+ return 0;
+ }
+
+ return 0;
+}
+
+/*!
+ * \qmlmethod bool Context3D::isBuffer(Object anyObject)
+ * Returns \c true if the given \a anyObect is a valid Buffer3D object and \c false otherwise.
+ */
+/*!
+ * \internal
+ */
+bool CanvasContext::isBuffer(QObject *anyObject)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( anyObject:" << anyObject << ")";
+ if (!anyObject)
+ return false;
+
+ QString className = QString(anyObject->metaObject()->className());
+ if (className != "CanvasBuffer")
+ return false;
+
+ CanvasBuffer *buffer = static_cast<CanvasBuffer *>(anyObject);
+ if (!buffer->isAlive())
+ return false;
+
+ return glIsBuffer(buffer->id());
+}
+
+/*!
+ * \qmlmethod void Context3D::deleteBuffer(Buffer3D buffer)
+ * Deletes the \a buffer. Has no effect if the Buffer3D object has been deleted already.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::deleteBuffer(CanvasBuffer *buffer)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(buffer:" << buffer << ")";
+ if (!buffer) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ": Called with null buffer target";
+ return;
+ }
+
+ buffer->del();
+}
+
+/*!
+ * \qmlmethod glEnums Context3D::getError()
+ * Returns the error value, if any.
+ */
+/*!
+ * \internal
+ */
+CanvasContext::glEnums CanvasContext::getError()
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__;
+ glEnums retVal = m_error;
+ m_error = NO_ERROR;
+ if (retVal == NO_ERROR)
+ retVal = glEnums(glGetError());
+ return retVal;
+}
+
+/*!
+ * \qmlmethod variant Context3D::getParameter(glEnums pname)
+ * Returns the value for the given \a pname. pname must be one of \c{Context3D.RED_BITS},
+ * \c{Context3D.GREEN_BITS}, \c{Context3D.BLUE_BITS}, \c{Context3D.ALPHA_BITS},
+ * \c{Context3D.DEPTH_BITS}, \c{Context3D.STENCIL_BITS}, \c{Context3D.MAX_TEXTURE_IMAGE_UNITS},
+ * \c{Context3D.MAX_VERTEX_TEXTURE_IMAGE_UNITS}, \c{Context3D.MAX_TEXTURE_SIZE},
+ * \c{Context3D.MAX_CUBE_MAP_TEXTURE_SIZE}, \c{Context3D.MAX_VERTEX_UNIFORM_VECTORS}
+ * (not supported in OpenGL ES2), \c{Context3D.RENDERER}, \c{Context3D.SHADING_LANGUAGE_VERSION},
+ * \c{Context3D.VENDOR}, \c{Context3D.VERSION}, \c{Context3D.UNMASKED_VENDOR_WEBGL}, or
+ * \c{Context3D.UNMASKED_RENDERER_WEBGL}.
+ */
+/*!
+ * \internal
+ */
+QVariant CanvasContext::getParameter(glEnums pname)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( pname:" << glEnumToString(pname) << ")";
+ GLint value;
+
+ switch (pname) {
+ // INTEGER PARAMETERS
+ case RED_BITS:
+ // Intentional flow through
+ case GREEN_BITS:
+ // Intentional flow through
+ case BLUE_BITS:
+ // Intentional flow through
+ case ALPHA_BITS:
+ // Intentional flow through
+ case DEPTH_BITS:
+ // Intentional flow through
+ case STENCIL_BITS:
+ // Intentional flow through
+ case MAX_TEXTURE_IMAGE_UNITS:
+ // Intentional flow through
+ case MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+ // Intentional flow through
+ case MAX_TEXTURE_SIZE:
+ // Intentional flow through
+ case MAX_CUBE_MAP_TEXTURE_SIZE: {
+ glGetIntegerv(pname, &value);
+ return QVariant::fromValue(value);
+ }
+#if !defined(QT_OPENGL_ES_2)
+ case MAX_VERTEX_UNIFORM_VECTORS: {
+ glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &value);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "():" << value;
+ return QVariant::fromValue(value);
+ }
+#endif
+ // STRING PARAMETERS
+ case RENDERER:
+ // Intentional flow through
+ case SHADING_LANGUAGE_VERSION:
+ // Intentional flow through
+ case VENDOR:
+ // Intentional flow through
+ case VERSION: {
+ const GLubyte *text = glGetString(pname);
+ QString qtext = QString::fromLatin1((const char *)text);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "():" << qtext;
+ return qtext;
+ break;
+ }
+ case UNMASKED_VENDOR_WEBGL: {
+ const GLubyte *text = glGetString(GL_VENDOR);
+ QString qtext = QString::fromLatin1((const char *)text);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "():" << qtext;
+ return qtext;
+ }
+ case UNMASKED_RENDERER_WEBGL: {
+ const GLubyte *text = glGetString(GL_VENDOR);
+ QString qtext = QString::fromLatin1((const char *)text);
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "():" << qtext;
+ return qtext;
+ }
+ default: {
+ qDebug() << "Context3D::" << __FUNCTION__ << "(): UNIMPLEMENTED PARAMETER NAME" << glEnumToString(pname);
+ return QVariant::fromValue(0);
+ }
+ }
+
+ // TODO: Check if this handles ownership correctly
+ return QVariant::fromValue(QString("NOT SUPPORTED YET"));
+}
+
+/*!
+ * \qmlmethod string Context3D::getShaderInfoLog(Shader3D shader)
+ * Returns the info log string of the given \a shader.
+ */
+/*!
+ * \internal
+ */
+QString CanvasContext::getShaderInfoLog(CanvasShader *shader) const
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( shader:" << shader<< ")";
+ if (!shader)
+ return QString();
+
+ // Returning a copy, V4VM takes ownership
+ return shader->qOGLShader()->log();
+}
+
+/*!
+ * \qmlmethod string Context3D::getProgramInfoLog(Program3D program)
+ * Returns the info log string of the given \a program.
+ */
+/*!
+ * \internal
+ */
+QString CanvasContext::getProgramInfoLog(CanvasProgram *program) const
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( program:" << program<< ")";
+ if (!program)
+ return QString();
+
+ // Returning a copy, V4VM takes ownership
+ return program->qOGLProgram()->log();
+}
+
+/*!
+ * \qmlmethod void Context3D::bindBuffer(glEnums target, Buffer3D buffer)
+ * Binds the given \a buffer to the given \a target. Target must be either
+ * \c Context3D.ARRAY_BUFFER or \c{Context3D.ELEMENT_ARRAY_BUFFER}. If the \a buffer given is
+ * \c{null}, the current buffer bound to the target is unbound.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::bindBuffer(glEnums target, CanvasBuffer *buffer)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "( target:" << glEnumToString(target) << ", buffer:" <<buffer<< ")";
+
+ if (target != ARRAY_BUFFER && target != ELEMENT_ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM target must be either ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER.";
+ m_error = INVALID_ENUM;
+ return;
+ }
+
+ if (buffer) {
+ if (target == ARRAY_BUFFER) {
+ if (buffer->target() == CanvasBuffer::UNINITIALIZED)
+ buffer->setTarget(CanvasBuffer::ARRAY_BUFFER);
+ if (buffer->target() != CanvasBuffer::ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION can't bind ELEMENT_ARRAY_BUFFER as ARRAY_BUFFER";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ m_currentArrayBuffer = buffer;
+ glBindBuffer(GLenum(target), buffer->id());
+ } else {
+ if (buffer->target() == CanvasBuffer::UNINITIALIZED)
+ buffer->setTarget(CanvasBuffer::ELEMENT_ARRAY_BUFFER);
+ if (buffer->target() != CanvasBuffer::ELEMENT_ARRAY_BUFFER) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION can't bind ARRAY_BUFFER as ELEMENT_ARRAY_BUFFER";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+ m_currentElementArrayBuffer = buffer;
+ glBindBuffer(GLenum(target), buffer->id());
+ }
+ } else {
+ glBindBuffer(GLenum(target), 0);
+ }
+
+}
+
+// TODO: Is this function useful? We don't offer a way to query the status.
+/*!
+ * \qmlmethod void Context3D::validateProgram(Program3D program)
+ * Validates the given \a program. The validation status is stored into the state of the shader
+ * program container in \a program.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::validateProgram(CanvasProgram *program)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(program:" << program << ")";
+ if (program)
+ program->validateProgram();
+}
+
+/*!
+ * \qmlmethod void Context3D::useProgram(Program3D program)
+ * Installs the given \a program as a part of the current rendering state.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::useProgram(CanvasProgram *program)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(program:" << program << ")";
+ // TODO: Check if this is ok
+ m_currentProgram = program;
+ if (!program || !program->qOGLProgram()->isLinked())
+ return;
+ program->qOGLProgram()->bind();
+}
+
+/*!
+ * \qmlmethod void Context3D::clear(glEnums flags)
+ * Clears the given \a flags.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::clear(glEnums flags)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(flags:" << glEnumToString(flags) << ")";
+ glClear(flags);
+}
+
+/*!
+ * \qmlmethod void Context3D::cullFace(glEnums mode)
+ * Sets the culling to \a mode. Must be one of \c{Context3D.FRONT}, \c{Context3D.BACK},
+ * or \c{Context3D.FRONT_AND_BACK}. Defaults to \c{Context3D.BACK}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::cullFace(glEnums mode)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(mode:" << glEnumToString(mode) << ")";
+ glCullFace(mode);
+}
+
+/*!
+ * \qmlmethod void Context3D::frontFace(glEnums mode)
+ * Sets the front face drawing to \a mode. Must be either \c Context3D.CW
+ * or \c{Context3D.CCW}. Defaults to \c{Context3D.CCW}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::frontFace(glEnums mode)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(mode:" << glEnumToString(mode) << ")";
+ glFrontFace(mode);
+}
+
+/*!
+ * \qmlmethod void Context3D::depthMask(bool flag)
+ * Enables or disables the depth mask based on \a flag. Defaults to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::depthMask(bool flag)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(flag:" << flag << ")";
+ if (flag)
+ glDepthMask(GL_TRUE);
+ else
+ glDepthMask(GL_FALSE);
+}
+
+// TODO: Why are all the enums for this commented out?
+/*!
+ * \qmlmethod void Context3D::depthFunc(glEnums func)
+ * Sets the depth function to \a func. Must be one of \c{Context3D.NEVER}, \c{Context3D.LESS},
+ * \c{Context3D.EQUAL}, \c{Context3D.LEQUAL}, \c{Context3D.GREATER}, \c{Context3D.NOTEQUAL},
+ * \c{Context3D.GEQUAL}, or \c{Context3D.ALWAYS}. Defaults to \c{Context3D.LESS}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::depthFunc(glEnums func)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(func:" << glEnumToString(func) << ")";
+ glDepthFunc(func);
+}
+
+/*!
+ * \qmlmethod void Context3D::depthRange(float zNear, float zFar)
+ * Sets the depth range between \a zNear and \a zFar. Values are clamped to \c{[0, 1]}. \a zNear
+ * must be less or equal to \a zFar. zNear Range defaults to \c{[0, 1]}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::depthRange(float zNear, float zFar)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(zNear:" << zNear << ", zFar:" << zFar << ")";
+ glDepthRangef(GLclampf(zNear), GLclampf(zFar));
+}
+
+/*!
+ * \qmlmethod void Context3D::clearStencil(int stencil)
+ * Sets the clear value for the stencil buffer to \a stencil. Defaults to \c{0}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::clearStencil(int stencil)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(stencil:" << stencil << ")";
+ glClearStencil(stencil);
+}
+
+/*!
+ * \qmlmethod void Context3D::colorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha)
+ * Enables or disables the writing of colors to the frame buffer based on \a maskRed, \a maskGreen,
+ * \a maskBlue and \a maskAlpha. All default to \c{true}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::colorMask(bool maskRed, bool maskGreen, bool maskBlue, bool maskAlpha)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(maskRed:" << maskRed << ", maskGreen:" << maskGreen << ", maskBlue:" << maskBlue << ", maskAlpha:" << maskAlpha << ")";
+ glColorMask(maskRed, maskGreen, maskBlue, maskAlpha);
+}
+
+/*!
+ * \qmlmethod void Context3D::clearDepth(float depth)
+ * Sets the clear value for the depth buffer to \a depth. Must be between \c{[0, 1]}. Defaults
+ * to \c{1}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::clearDepth(float depth)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(depth:" << depth << ")";
+ glClearDepthf(depth);
+}
+
+/*!
+ * \qmlmethod void Context3D::clearColor(float red, float green, float blue, float alpha)
+ * Sets the clear values for the color buffers with \a red, \a green, \a blue and \a alpha. Values
+ * must be between \c{[0, 1]}. All default to \c{0}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::clearColor(float red, float green, float blue, float alpha)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(red:" << red << ", green:" << green << ", blue:" << blue << ", alpha:" << alpha << ")";
+ glClearColor(red, green, blue, alpha);
+}
+
+/*!
+ * \qmlmethod Context3D::viewport(int x, int y, int width, int height)
+ * Defines the affine transformation from normalized x and y device coordinates to window
+ * coordinates within the drawing buffer.
+ * \a x defines the left edge of the viewport.
+ * \a y defines the bottom edge of the viewport.
+ * \a width defines the width of the viewport.
+ * \a height defines the height of the viewport.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::viewport(int x, int y, int width, int height)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(x:" << x << ", y:" << y << ", width:" << width << ", height:" << height << ")";
+ glViewport(x, y, width, height);
+ m_glViewportRect.setX(x);
+ m_glViewportRect.setY(y);
+ m_glViewportRect.setWidth(width);
+ m_glViewportRect.setHeight(height);
+}
+
+/*!
+ * \qmlmethod void Context3D::drawArrays(glEnums mode, int first, int count)
+ * Renders the geometric primitives held in the currently bound array buffer starting from \a first
+ * up to \a count using \a mode for drawing. Mode must be one of \c{Context3D.POINTS},
+ * \c{Context3D.LINES}, \c{Context3D.LINE_LOOP}, \c{Context3D.LINE_STRIP}, \c{Context3D.TRIANGLES},
+ * \c{Context3D.TRIANGLE_STRIP}, or \c{Context3D.TRIANGLE_FAN}.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::drawArrays(glEnums mode, int first, int count)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(mode:" << glEnumToString(mode) << ", first:" << first << ", count:" << count << ")";
+ glDrawArrays(mode, first, count);
+}
+
+/*!
+ * \qmlmethod void Context3D::drawElements(glEnums mode, int count, glEnums type, long offset)
+ * Renders the number of geometric elements given in \a count held in the currently bound element
+ * array buffer using \a mode for drawing. Mode must be one of \c{Context3D.POINTS},
+ * \c{Context3D.LINES}, \c{Context3D.LINE_LOOP}, \c{Context3D.LINE_STRIP}, \c{Context3D.TRIANGLES},
+ * \c{Context3D.TRIANGLE_STRIP}, or \c{Context3D.TRIANGLE_FAN}. \a type specifies the element type
+ * and must be either \c Context3D.UNSIGNED_BYTE or \c{Context3D.UNSIGNED_SHORT}. \a offset
+ * specifies the location where indices are stored.
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::drawElements(glEnums mode, int count, glEnums type, long offset)
+{
+ if (m_logAllCalls) qDebug() << "Context3D::" << __FUNCTION__ << "(mode:" << glEnumToString(mode) << ", count:" << count << ", type:" << glEnumToString(type) << ", offset:" << offset << ")";
+ glDrawElements(GLenum(mode), count, GLenum(type), (GLvoid*)offset);
+}
+
+/*!
+ * \qmlmethod void Context3D::readPixels(int x, int y, long width, long height, glEnums format, glEnums type, ArrayBufferView pixels)
+ * Returns the pixel data in the rectangle specified by \a x, \a y, \a width and \a height of the
+ * frame buffer in \a pixels using \a format (must be \c{Context3D.RGBA}) and \a type
+ * (must be \c{Context3D.UNSIGNED_BYTE}).
+ */
+/*!
+ * \internal
+ */
+void CanvasContext::readPixels(int x, int y, long width, long height, glEnums format, glEnums type,
+ CanvasArrayBufferView *pixels)
+{
+ if (format != RGBA) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM format must be RGBA.";
+ m_error = INVALID_ENUM;
+ return;
+ }
+ if (type != UNSIGNED_BYTE) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_ENUM type must be UNSIGNED_BYTE.";
+ m_error = INVALID_ENUM;
+ return;
+ }
+ if (!pixels) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_VALUE pixels was null.";
+ m_error = INVALID_VALUE;
+ return;
+ }
+
+ CanvasUint8Array *array = dynamic_cast<CanvasUint8Array *>(pixels);
+ if (!array) {
+ if (m_logAllErrors) qDebug() << "Context3D::" << __FUNCTION__ << ":INVALID_OPERATION pixels must be Uint8Array.";
+ m_error = INVALID_OPERATION;
+ return;
+ }
+
+ glReadPixels(x, y, width, height, format, type, pixels->rawDataCptr());
+}
diff --git a/src/context3d_p.h b/src/context3d_p.h
new file mode 100644
index 0000000..9649cc6
--- /dev/null
+++ b/src/context3d_p.h
@@ -0,0 +1,1190 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CONTEXT3D_P_H
+#define CONTEXT3D_P_H
+
+#include "canvas3dcommon_p.h"
+#include "contextattributes_p.h"
+
+#include <QtGui/QOpenGLFunctions>
+#include <QString>
+#include <QRect>
+#include <QSize>
+#include <QVariantList>
+#include <QtQuick/QQuickItem>
+
+#ifdef NO_ERROR // may de defined in winerror.h
+#undef NO_ERROR
+#endif
+
+#define ENUM_AS_PROPERTY(A) Q_PROPERTY(CanvasContext::glEnums A READ A ## _read); inline CanvasContext::glEnums A ## _read() { return CanvasContext::A; }
+
+class Canvas;
+class CanvasTexture;
+class CanvasShader;
+class CanvasFrameBuffer;
+class CanvasRenderBuffer;
+class CanvasProgram;
+class CanvasBuffer;
+class CanvasUniformLocation;
+class CanvasTextureImage;
+class CanvasArrayBufferView;
+class CanvasArrayBuffer;
+class CanvasFloat32Array;
+class CanvasInt32Array;
+class CanvasTypedArray;
+class CanvasShaderPrecisionFormat;
+class EnumToStringMap;
+
+class QT_CANVAS3D_EXPORT CanvasContext : public QObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CanvasContext)
+
+ Q_ENUMS(glEnums)
+
+ Q_PROPERTY(Canvas *canvas READ canvas NOTIFY canvasChanged)
+ Q_PROPERTY(bool logAllCalls READ logAllCalls WRITE setLogAllCalls NOTIFY logAllCallsChanged)
+ Q_PROPERTY(bool logAllErrors READ logAllErrors WRITE setLogAllErrors NOTIFY logAllErrorsChanged)
+
+public:
+ enum glEnums {
+ /* ClearBufferMask */
+ DEPTH_BUFFER_BIT = 0x00000100,
+ STENCIL_BUFFER_BIT = 0x00000400,
+ COLOR_BUFFER_BIT = 0x00004000,
+
+ // EXTRA
+ DEPTH_AND_COLOR_BUFFER_BIT = 0x00004100,
+ DEPTH_AND_STENCIL_AND_COLOR_BUFFER_BIT = 0x00004500,
+
+ /* BeginMode */
+ POINTS = 0x0000,
+ LINES = 0x0001,
+ LINE_LOOP = 0x0002,
+ LINE_STRIP = 0x0003,
+ TRIANGLES = 0x0004,
+ TRIANGLE_STRIP = 0x0005,
+ TRIANGLE_FAN = 0x0006,
+
+ /* AlphaFunction (not supported in ES20) */
+ /* NEVER */
+ /* LESS */
+ /* EQUAL */
+ /* LEQUAL */
+ /* GREATER */
+ /* NOTEQUAL */
+ /* GEQUAL */
+ /* ALWAYS */
+
+ /* BlendingFactorDest */
+ ZERO = 0,
+ ONE = 1,
+ SRC_COLOR = 0x0300,
+ ONE_MINUS_SRC_COLOR = 0x0301,
+ SRC_ALPHA = 0x0302,
+ ONE_MINUS_SRC_ALPHA = 0x0303,
+ DST_ALPHA = 0x0304,
+ ONE_MINUS_DST_ALPHA = 0x0305,
+
+ /* BlendingFactorSrc */
+ /* ZERO */
+ /* ONE */
+ DST_COLOR = 0x0306,
+ ONE_MINUS_DST_COLOR = 0x0307,
+ SRC_ALPHA_SATURATE = 0x0308,
+ /* SRC_ALPHA */
+ /* ONE_MINUS_SRC_ALPHA */
+ /* DST_ALPHA */
+ /* ONE_MINUS_DST_ALPHA */
+
+ /* BlendEquationSeparate */
+ FUNC_ADD = 0x8006,
+ BLEND_EQUATION = 0x8009,
+ BLEND_EQUATION_RGB = 0x8009, /* same as BLEND_EQUATION */
+ BLEND_EQUATION_ALPHA = 0x883D,
+
+ /* BlendSubtract */
+ FUNC_SUBTRACT = 0x800A,
+ FUNC_REVERSE_SUBTRACT = 0x800B,
+
+ /* Separate Blend Functions */
+ BLEND_DST_RGB = 0x80C8,
+ BLEND_SRC_RGB = 0x80C9,
+ BLEND_DST_ALPHA = 0x80CA,
+ BLEND_SRC_ALPHA = 0x80CB,
+ CONSTANT_COLOR = 0x8001,
+ ONE_MINUS_CONSTANT_COLOR = 0x8002,
+ CONSTANT_ALPHA = 0x8003,
+ ONE_MINUS_CONSTANT_ALPHA = 0x8004,
+ BLEND_COLOR = 0x8005,
+
+ /* Buffer Objects */
+ ARRAY_BUFFER = 0x8892,
+ ELEMENT_ARRAY_BUFFER = 0x8893,
+ ARRAY_BUFFER_BINDING = 0x8894,
+ ELEMENT_ARRAY_BUFFER_BINDING = 0x8895,
+
+ STREAM_DRAW = 0x88E0,
+ STATIC_DRAW = 0x88E4,
+ DYNAMIC_DRAW = 0x88E8,
+
+ BUFFER_SIZE = 0x8764,
+ BUFFER_USAGE = 0x8765,
+
+ CURRENT_VERTEX_ATTRIB = 0x8626,
+
+ /* CullFaceMode */
+ FRONT = 0x0404,
+ BACK = 0x0405,
+ FRONT_AND_BACK = 0x0408,
+
+ /* DepthFunction */
+ /* NEVER */
+ /* LESS */
+ /* EQUAL */
+ /* LEQUAL */
+ /* GREATER */
+ /* NOTEQUAL */
+ /* GEQUAL */
+ /* ALWAYS */
+
+ /* EnableCap */
+ /* TEXTURE_2D */
+ CULL_FACE = 0x0B44,
+ BLEND = 0x0BE2,
+ DITHER = 0x0BD0,
+ STENCIL_TEST = 0x0B90,
+ DEPTH_TEST = 0x0B71,
+ SCISSOR_TEST = 0x0C11,
+ POLYGON_OFFSET_FILL = 0x8037,
+ SAMPLE_ALPHA_TO_COVERAGE = 0x809E,
+ SAMPLE_COVERAGE = 0x80A0,
+
+ /* Error Codes */
+ NO_ERROR = 0,
+ INVALID_ENUM = 0x0500,
+ INVALID_VALUE = 0x0501,
+ INVALID_OPERATION = 0x0502,
+ OUT_OF_MEMORY = 0x0505,
+
+ /* FrontFaceDirection */
+ CW = 0x0900,
+ CCW = 0x0901,
+
+ /* GetPName */
+ LINE_WIDTH = 0x0B21,
+ ALIASED_POINT_SIZE_RANGE = 0x846D,
+ ALIASED_LINE_WIDTH_RANGE = 0x846E,
+ CULL_FACE_MODE = 0x0B45,
+ FRONT_FACE = 0x0B46,
+ DEPTH_RANGE = 0x0B70,
+ DEPTH_WRITEMASK = 0x0B72,
+ DEPTH_CLEAR_VALUE = 0x0B73,
+ DEPTH_FUNC = 0x0B74,
+ STENCIL_CLEAR_VALUE = 0x0B91,
+ STENCIL_FUNC = 0x0B92,
+ STENCIL_FAIL = 0x0B94,
+ STENCIL_PASS_DEPTH_FAIL = 0x0B95,
+ STENCIL_PASS_DEPTH_PASS = 0x0B96,
+ STENCIL_REF = 0x0B97,
+ STENCIL_VALUE_MASK = 0x0B93,
+ STENCIL_WRITEMASK = 0x0B98,
+ STENCIL_BACK_FUNC = 0x8800,
+ STENCIL_BACK_FAIL = 0x8801,
+ STENCIL_BACK_PASS_DEPTH_FAIL = 0x8802,
+ STENCIL_BACK_PASS_DEPTH_PASS = 0x8803,
+ STENCIL_BACK_REF = 0x8CA3,
+ STENCIL_BACK_VALUE_MASK = 0x8CA4,
+ STENCIL_BACK_WRITEMASK = 0x8CA5,
+ VIEWPORT = 0x0BA2,
+ SCISSOR_BOX = 0x0C10,
+ /* SCISSOR_TEST */
+ COLOR_CLEAR_VALUE = 0x0C22,
+ COLOR_WRITEMASK = 0x0C23,
+ UNPACK_ALIGNMENT = 0x0CF5,
+ PACK_ALIGNMENT = 0x0D05,
+ MAX_TEXTURE_SIZE = 0x0D33,
+ MAX_VIEWPORT_DIMS = 0x0D3A,
+ SUBPIXEL_BITS = 0x0D50,
+ RED_BITS = 0x0D52,
+ GREEN_BITS = 0x0D53,
+ BLUE_BITS = 0x0D54,
+ ALPHA_BITS = 0x0D55,
+ DEPTH_BITS = 0x0D56,
+ STENCIL_BITS = 0x0D57,
+ POLYGON_OFFSET_UNITS = 0x2A00,
+ /* POLYGON_OFFSET_FILL */
+ POLYGON_OFFSET_FACTOR = 0x8038,
+ TEXTURE_BINDING_2D = 0x8069,
+ SAMPLE_BUFFERS = 0x80A8,
+ SAMPLES = 0x80A9,
+ SAMPLE_COVERAGE_VALUE = 0x80AA,
+ SAMPLE_COVERAGE_INVERT = 0x80AB,
+
+ /* GetTextureParameter */
+ /* TEXTURE_MAG_FILTER */
+ /* TEXTURE_MIN_FILTER */
+ /* TEXTURE_WRAP_S */
+ /* TEXTURE_WRAP_T */
+
+ COMPRESSED_TEXTURE_FORMATS = 0x86A3,
+
+ /* HintMode */
+ DONT_CARE = 0x1100,
+ FASTEST = 0x1101,
+ NICEST = 0x1102,
+
+ /* HintTarget */
+ GENERATE_MIPMAP_HINT = 0x8192,
+
+ /* DataType */
+ BYTE = 0x1400,
+ UNSIGNED_BYTE = 0x1401,
+ SHORT = 0x1402,
+ UNSIGNED_SHORT = 0x1403,
+ INT = 0x1404,
+ UNSIGNED_INT = 0x1405,
+ FLOAT = 0x1406,
+
+ /* PixelFormat */
+ DEPTH_COMPONENT = 0x1902,
+ ALPHA = 0x1906,
+ RGB = 0x1907,
+ RGBA = 0x1908,
+ LUMINANCE = 0x1909,
+ LUMINANCE_ALPHA = 0x190A,
+
+ /* PixelType */
+ /* UNSIGNED_BYTE */
+ UNSIGNED_SHORT_4_4_4_4 = 0x8033,
+ UNSIGNED_SHORT_5_5_5_1 = 0x8034,
+ UNSIGNED_SHORT_5_6_5 = 0x8363,
+
+ /* Shaders */
+ FRAGMENT_SHADER = 0x8B30,
+ VERTEX_SHADER = 0x8B31,
+ MAX_VERTEX_ATTRIBS = 0x8869,
+ MAX_VERTEX_UNIFORM_VECTORS = 0x8DFB,
+ MAX_VARYING_VECTORS = 0x8DFC,
+ MAX_COMBINED_TEXTURE_IMAGE_UNITS = 0x8B4D,
+ MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0x8B4C,
+ MAX_TEXTURE_IMAGE_UNITS = 0x8872,
+ MAX_FRAGMENT_UNIFORM_VECTORS = 0x8DFD,
+ SHADER_TYPE = 0x8B4F,
+ DELETE_STATUS = 0x8B80,
+ LINK_STATUS = 0x8B82,
+ VALIDATE_STATUS = 0x8B83,
+ ATTACHED_SHADERS = 0x8B85,
+ ACTIVE_UNIFORMS = 0x8B86,
+ ACTIVE_ATTRIBUTES = 0x8B89,
+ SHADING_LANGUAGE_VERSION = 0x8B8C,
+ CURRENT_PROGRAM = 0x8B8D,
+
+ /* StencilFunction */
+ NEVER = 0x0200,
+ LESS = 0x0201,
+ EQUAL = 0x0202,
+ LEQUAL = 0x0203,
+ GREATER = 0x0204,
+ NOTEQUAL = 0x0205,
+ GEQUAL = 0x0206,
+ ALWAYS = 0x0207,
+
+ /* StencilOp */
+ /* ZERO */
+ KEEP = 0x1E00,
+ REPLACE = 0x1E01,
+ INCR = 0x1E02,
+ DECR = 0x1E03,
+ INVERT = 0x150A,
+ INCR_WRAP = 0x8507,
+ DECR_WRAP = 0x8508,
+
+ /* StringName */
+ VENDOR = 0x1F00,
+ RENDERER = 0x1F01,
+ VERSION = 0x1F02,
+
+ /* TextureMagFilter */
+ NEAREST = 0x2600,
+ LINEAR = 0x2601,
+
+ /* TextureMinFilter */
+ /* NEAREST */
+ /* LINEAR */
+ NEAREST_MIPMAP_NEAREST = 0x2700,
+ LINEAR_MIPMAP_NEAREST = 0x2701,
+ NEAREST_MIPMAP_LINEAR = 0x2702,
+ LINEAR_MIPMAP_LINEAR = 0x2703,
+
+ /* TextureParameterName */
+ TEXTURE_MAG_FILTER = 0x2800,
+ TEXTURE_MIN_FILTER = 0x2801,
+ TEXTURE_WRAP_S = 0x2802,
+ TEXTURE_WRAP_T = 0x2803,
+
+ /* TextureTarget */
+ TEXTURE_2D = 0x0DE1,
+ TEXTURE = 0x1702,
+
+ TEXTURE_CUBE_MAP = 0x8513,
+ TEXTURE_BINDING_CUBE_MAP = 0x8514,
+ TEXTURE_CUBE_MAP_POSITIVE_X = 0x8515,
+ TEXTURE_CUBE_MAP_NEGATIVE_X = 0x8516,
+ TEXTURE_CUBE_MAP_POSITIVE_Y = 0x8517,
+ TEXTURE_CUBE_MAP_NEGATIVE_Y = 0x8518,
+ TEXTURE_CUBE_MAP_POSITIVE_Z = 0x8519,
+ TEXTURE_CUBE_MAP_NEGATIVE_Z = 0x851A,
+ MAX_CUBE_MAP_TEXTURE_SIZE = 0x851C,
+
+ /* TextureUnit */
+ TEXTURE0 = 0x84C0,
+ TEXTURE1 = 0x84C1,
+ TEXTURE2 = 0x84C2,
+ TEXTURE3 = 0x84C3,
+ TEXTURE4 = 0x84C4,
+ TEXTURE5 = 0x84C5,
+ TEXTURE6 = 0x84C6,
+ TEXTURE7 = 0x84C7,
+ TEXTURE8 = 0x84C8,
+ TEXTURE9 = 0x84C9,
+ TEXTURE10 = 0x84CA,
+ TEXTURE11 = 0x84CB,
+ TEXTURE12 = 0x84CC,
+ TEXTURE13 = 0x84CD,
+ TEXTURE14 = 0x84CE,
+ TEXTURE15 = 0x84CF,
+ TEXTURE16 = 0x84D0,
+ TEXTURE17 = 0x84D1,
+ TEXTURE18 = 0x84D2,
+ TEXTURE19 = 0x84D3,
+ TEXTURE20 = 0x84D4,
+ TEXTURE21 = 0x84D5,
+ TEXTURE22 = 0x84D6,
+ TEXTURE23 = 0x84D7,
+ TEXTURE24 = 0x84D8,
+ TEXTURE25 = 0x84D9,
+ TEXTURE26 = 0x84DA,
+ TEXTURE27 = 0x84DB,
+ TEXTURE28 = 0x84DC,
+ TEXTURE29 = 0x84DD,
+ TEXTURE30 = 0x84DE,
+ TEXTURE31 = 0x84DF,
+ ACTIVE_TEXTURE = 0x84E0,
+
+ /* TextureWrapMode */
+ REPEAT = 0x2901,
+ CLAMP_TO_EDGE = 0x812F,
+ MIRRORED_REPEAT = 0x8370,
+
+ /* Uniform Types */
+ FLOAT_VEC2 = 0x8B50,
+ FLOAT_VEC3 = 0x8B51,
+ FLOAT_VEC4 = 0x8B52,
+ INT_VEC2 = 0x8B53,
+ INT_VEC3 = 0x8B54,
+ INT_VEC4 = 0x8B55,
+ BOOL = 0x8B56,
+ BOOL_VEC2 = 0x8B57,
+ BOOL_VEC3 = 0x8B58,
+ BOOL_VEC4 = 0x8B59,
+ FLOAT_MAT2 = 0x8B5A,
+ FLOAT_MAT3 = 0x8B5B,
+ FLOAT_MAT4 = 0x8B5C,
+ SAMPLER_2D = 0x8B5E,
+ SAMPLER_CUBE = 0x8B60,
+
+ /* Vertex Arrays */
+ VERTEX_ATTRIB_ARRAY_ENABLED = 0x8622,
+ VERTEX_ATTRIB_ARRAY_SIZE = 0x8623,
+ VERTEX_ATTRIB_ARRAY_STRIDE = 0x8624,
+ VERTEX_ATTRIB_ARRAY_TYPE = 0x8625,
+ VERTEX_ATTRIB_ARRAY_NORMALIZED = 0x886A,
+ VERTEX_ATTRIB_ARRAY_POINTER = 0x8645,
+ VERTEX_ATTRIB_ARRAY_BUFFER_BINDING = 0x889F,
+
+ /* Shader Source */
+ COMPILE_STATUS = 0x8B81,
+
+ /* Shader Precision-Specified Types */
+ LOW_FLOAT = 0x8DF0,
+ MEDIUM_FLOAT = 0x8DF1,
+ HIGH_FLOAT = 0x8DF2,
+ LOW_INT = 0x8DF3,
+ MEDIUM_INT = 0x8DF4,
+ HIGH_INT = 0x8DF5,
+
+ /* Framebuffer Object. */
+ FRAMEBUFFER = 0x8D40,
+ RENDERBUFFER = 0x8D41,
+
+ RGBA4 = 0x8056,
+ RGB5_A1 = 0x8057,
+ RGB565 = 0x8D62,
+ DEPTH_COMPONENT16 = 0x81A5,
+ STENCIL_INDEX = 0x1901,
+ STENCIL_INDEX8 = 0x8D48,
+ DEPTH_STENCIL = 0x84F9,
+
+ RENDERBUFFER_WIDTH = 0x8D42,
+ RENDERBUFFER_HEIGHT = 0x8D43,
+ RENDERBUFFER_INTERNAL_FORMAT = 0x8D44,
+ RENDERBUFFER_RED_SIZE = 0x8D50,
+ RENDERBUFFER_GREEN_SIZE = 0x8D51,
+ RENDERBUFFER_BLUE_SIZE = 0x8D52,
+ RENDERBUFFER_ALPHA_SIZE = 0x8D53,
+ RENDERBUFFER_DEPTH_SIZE = 0x8D54,
+ RENDERBUFFER_STENCIL_SIZE = 0x8D55,
+
+ FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE = 0x8CD0,
+ FRAMEBUFFER_ATTACHMENT_OBJECT_NAME = 0x8CD1,
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL = 0x8CD2,
+ FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE = 0x8CD3,
+
+ COLOR_ATTACHMENT0 = 0x8CE0,
+ DEPTH_ATTACHMENT = 0x8D00,
+ STENCIL_ATTACHMENT = 0x8D20,
+ DEPTH_STENCIL_ATTACHMENT = 0x821A,
+
+ NONE = 0,
+
+ FRAMEBUFFER_COMPLETE = 0x8CD5,
+ FRAMEBUFFER_INCOMPLETE_ATTACHMENT = 0x8CD6,
+ FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT = 0x8CD7,
+ FRAMEBUFFER_INCOMPLETE_DIMENSIONS = 0x8CD9,
+ FRAMEBUFFER_UNSUPPORTED = 0x8CDD,
+
+ FRAMEBUFFER_BINDING = 0x8CA6,
+ RENDERBUFFER_BINDING = 0x8CA7,
+ MAX_RENDERBUFFER_SIZE = 0x84E8,
+
+ INVALID_FRAMEBUFFER_OPERATION = 0x0506,
+
+ /* WebGL-specific enums */
+ UNPACK_FLIP_Y_WEBGL = 0x9240,
+ UNPACK_PREMULTIPLY_ALPHA_WEBGL = 0x9241,
+ CONTEXT_LOST_WEBGL = 0x9242,
+ UNPACK_COLORSPACE_CONVERSION_WEBGL = 0x9243,
+ BROWSER_DEFAULT_WEBGL = 0x9244,
+
+ /* WEBGL_debug_renderer_info */
+ UNMASKED_VENDOR_WEBGL = 0x9245,
+ UNMASKED_RENDERER_WEBGL = 0x9246
+ };
+
+ /* ClearBufferMask */
+ ENUM_AS_PROPERTY(DEPTH_BUFFER_BIT)
+ ENUM_AS_PROPERTY(STENCIL_BUFFER_BIT)
+ ENUM_AS_PROPERTY(COLOR_BUFFER_BIT)
+
+ /* BeginMode */
+ ENUM_AS_PROPERTY(POINTS)
+ ENUM_AS_PROPERTY(LINES)
+ ENUM_AS_PROPERTY(LINE_LOOP)
+ ENUM_AS_PROPERTY(LINE_STRIP)
+ ENUM_AS_PROPERTY(TRIANGLES)
+ ENUM_AS_PROPERTY(TRIANGLE_STRIP)
+ ENUM_AS_PROPERTY(TRIANGLE_FAN)
+
+ /* AlphaFunction (not supported in ES20) */
+ /* NEVER */
+ /* LESS */
+ /* EQUAL */
+ /* LEQUAL */
+ /* GREATER */
+ /* NOTEQUAL */
+ /* GEQUAL */
+ /* ALWAYS */
+
+ /* BlendingFactorDest */
+ ENUM_AS_PROPERTY(ZERO)
+ ENUM_AS_PROPERTY(ONE)
+ ENUM_AS_PROPERTY(SRC_COLOR)
+ ENUM_AS_PROPERTY(ONE_MINUS_SRC_COLOR)
+ ENUM_AS_PROPERTY(SRC_ALPHA)
+ ENUM_AS_PROPERTY(ONE_MINUS_SRC_ALPHA)
+ ENUM_AS_PROPERTY(DST_ALPHA)
+ ENUM_AS_PROPERTY(ONE_MINUS_DST_ALPHA)
+
+ /* BlendingFactorSrc */
+ /* ZERO */
+ /* ONE */
+ ENUM_AS_PROPERTY(DST_COLOR)
+ ENUM_AS_PROPERTY(ONE_MINUS_DST_COLOR)
+ ENUM_AS_PROPERTY(SRC_ALPHA_SATURATE)
+ /* SRC_ALPHA */
+ /* ONE_MINUS_SRC_ALPHA */
+ /* DST_ALPHA */
+ /* ONE_MINUS_DST_ALPHA */
+
+ /* BlendEquationSeparate */
+ ENUM_AS_PROPERTY(FUNC_ADD)
+ ENUM_AS_PROPERTY(BLEND_EQUATION)
+ ENUM_AS_PROPERTY(BLEND_EQUATION_RGB) /* same as BLEND_EQUATION */
+ ENUM_AS_PROPERTY(BLEND_EQUATION_ALPHA)
+
+ /* BlendSubtract */
+ ENUM_AS_PROPERTY(FUNC_SUBTRACT)
+ ENUM_AS_PROPERTY(FUNC_REVERSE_SUBTRACT)
+
+ /* Separate Blend Functions */
+ ENUM_AS_PROPERTY(BLEND_DST_RGB)
+ ENUM_AS_PROPERTY(BLEND_SRC_RGB)
+ ENUM_AS_PROPERTY(BLEND_DST_ALPHA)
+ ENUM_AS_PROPERTY(BLEND_SRC_ALPHA)
+ ENUM_AS_PROPERTY(CONSTANT_COLOR)
+ ENUM_AS_PROPERTY(ONE_MINUS_CONSTANT_COLOR)
+ ENUM_AS_PROPERTY(CONSTANT_ALPHA)
+ ENUM_AS_PROPERTY(ONE_MINUS_CONSTANT_ALPHA)
+ ENUM_AS_PROPERTY(BLEND_COLOR)
+
+ /* Buffer Objects */
+ ENUM_AS_PROPERTY(ARRAY_BUFFER)
+ ENUM_AS_PROPERTY(ELEMENT_ARRAY_BUFFER)
+ ENUM_AS_PROPERTY(ARRAY_BUFFER_BINDING)
+ ENUM_AS_PROPERTY(ELEMENT_ARRAY_BUFFER_BINDING)
+
+ ENUM_AS_PROPERTY(STREAM_DRAW)
+ ENUM_AS_PROPERTY(STATIC_DRAW)
+ ENUM_AS_PROPERTY(DYNAMIC_DRAW)
+
+ ENUM_AS_PROPERTY(BUFFER_SIZE)
+ ENUM_AS_PROPERTY(BUFFER_USAGE)
+
+ ENUM_AS_PROPERTY(CURRENT_VERTEX_ATTRIB)
+
+ /* CullFaceMode */
+ ENUM_AS_PROPERTY(FRONT)
+ ENUM_AS_PROPERTY(BACK)
+ ENUM_AS_PROPERTY(FRONT_AND_BACK)
+
+ /* DepthFunction */
+ /* NEVER */
+ /* LESS */
+ /* EQUAL */
+ /* LEQUAL */
+ /* GREATER */
+ /* NOTEQUAL */
+ /* GEQUAL */
+ /* ALWAYS */
+
+ /* EnableCap */
+ /* TEXTURE_2D */
+ ENUM_AS_PROPERTY(CULL_FACE)
+ ENUM_AS_PROPERTY(BLEND)
+ ENUM_AS_PROPERTY(DITHER)
+ ENUM_AS_PROPERTY(STENCIL_TEST)
+ ENUM_AS_PROPERTY(DEPTH_TEST)
+ ENUM_AS_PROPERTY(SCISSOR_TEST)
+ ENUM_AS_PROPERTY(POLYGON_OFFSET_FILL)
+ ENUM_AS_PROPERTY(SAMPLE_ALPHA_TO_COVERAGE)
+ ENUM_AS_PROPERTY(SAMPLE_COVERAGE)
+
+ /* ErrorCode */
+ ENUM_AS_PROPERTY(NO_ERROR)
+ ENUM_AS_PROPERTY(INVALID_ENUM)
+ ENUM_AS_PROPERTY(INVALID_VALUE)
+ ENUM_AS_PROPERTY(INVALID_OPERATION)
+ ENUM_AS_PROPERTY(OUT_OF_MEMORY)
+
+ /* FrontFaceDirection */
+ ENUM_AS_PROPERTY(CW)
+ ENUM_AS_PROPERTY(CCW)
+
+ /* GetPName */
+ ENUM_AS_PROPERTY(LINE_WIDTH)
+ ENUM_AS_PROPERTY(ALIASED_POINT_SIZE_RANGE)
+ ENUM_AS_PROPERTY(ALIASED_LINE_WIDTH_RANGE)
+ ENUM_AS_PROPERTY(CULL_FACE_MODE)
+ ENUM_AS_PROPERTY(FRONT_FACE)
+ ENUM_AS_PROPERTY(DEPTH_RANGE)
+ ENUM_AS_PROPERTY(DEPTH_WRITEMASK)
+ ENUM_AS_PROPERTY(DEPTH_CLEAR_VALUE)
+ ENUM_AS_PROPERTY(DEPTH_FUNC)
+ ENUM_AS_PROPERTY(STENCIL_CLEAR_VALUE)
+ ENUM_AS_PROPERTY(STENCIL_FUNC)
+ ENUM_AS_PROPERTY(STENCIL_FAIL)
+ ENUM_AS_PROPERTY(STENCIL_PASS_DEPTH_FAIL)
+ ENUM_AS_PROPERTY(STENCIL_PASS_DEPTH_PASS)
+ ENUM_AS_PROPERTY(STENCIL_REF)
+ ENUM_AS_PROPERTY(STENCIL_VALUE_MASK)
+ ENUM_AS_PROPERTY(STENCIL_WRITEMASK)
+ ENUM_AS_PROPERTY(STENCIL_BACK_FUNC)
+ ENUM_AS_PROPERTY(STENCIL_BACK_FAIL)
+ ENUM_AS_PROPERTY(STENCIL_BACK_PASS_DEPTH_FAIL)
+ ENUM_AS_PROPERTY(STENCIL_BACK_PASS_DEPTH_PASS)
+ ENUM_AS_PROPERTY(STENCIL_BACK_REF)
+ ENUM_AS_PROPERTY(STENCIL_BACK_VALUE_MASK)
+ ENUM_AS_PROPERTY(STENCIL_BACK_WRITEMASK)
+ ENUM_AS_PROPERTY(VIEWPORT)
+ ENUM_AS_PROPERTY(SCISSOR_BOX)
+ /* SCISSOR_TEST */
+ ENUM_AS_PROPERTY(COLOR_CLEAR_VALUE)
+ ENUM_AS_PROPERTY(COLOR_WRITEMASK)
+ ENUM_AS_PROPERTY(UNPACK_ALIGNMENT)
+ ENUM_AS_PROPERTY(PACK_ALIGNMENT)
+ ENUM_AS_PROPERTY(MAX_TEXTURE_SIZE)
+ ENUM_AS_PROPERTY(MAX_VIEWPORT_DIMS)
+ ENUM_AS_PROPERTY(SUBPIXEL_BITS)
+ ENUM_AS_PROPERTY(RED_BITS)
+ ENUM_AS_PROPERTY(GREEN_BITS)
+ ENUM_AS_PROPERTY(BLUE_BITS)
+ ENUM_AS_PROPERTY(ALPHA_BITS)
+ ENUM_AS_PROPERTY(DEPTH_BITS)
+ ENUM_AS_PROPERTY(STENCIL_BITS)
+ ENUM_AS_PROPERTY(POLYGON_OFFSET_UNITS)
+ /* POLYGON_OFFSET_FILL */
+ ENUM_AS_PROPERTY(POLYGON_OFFSET_FACTOR)
+ ENUM_AS_PROPERTY(TEXTURE_BINDING_2D)
+ ENUM_AS_PROPERTY(SAMPLE_BUFFERS)
+ ENUM_AS_PROPERTY(SAMPLES)
+ ENUM_AS_PROPERTY(SAMPLE_COVERAGE_VALUE)
+ ENUM_AS_PROPERTY(SAMPLE_COVERAGE_INVERT)
+
+ /* GetTextureParameter */
+ /* TEXTURE_MAG_FILTER */
+ /* TEXTURE_MIN_FILTER */
+ /* TEXTURE_WRAP_S */
+ /* TEXTURE_WRAP_T */
+
+ ENUM_AS_PROPERTY(COMPRESSED_TEXTURE_FORMATS)
+
+ /* HintMode */
+ ENUM_AS_PROPERTY(DONT_CARE)
+ ENUM_AS_PROPERTY(FASTEST)
+ ENUM_AS_PROPERTY(NICEST)
+
+ /* HintTarget */
+ ENUM_AS_PROPERTY(GENERATE_MIPMAP_HINT)
+
+ /* DataType */
+ ENUM_AS_PROPERTY(BYTE)
+ ENUM_AS_PROPERTY(UNSIGNED_BYTE)
+ ENUM_AS_PROPERTY(SHORT)
+ ENUM_AS_PROPERTY(UNSIGNED_SHORT)
+ ENUM_AS_PROPERTY(INT)
+ ENUM_AS_PROPERTY(UNSIGNED_INT)
+ ENUM_AS_PROPERTY(FLOAT)
+
+ /* PixelFormat */
+ ENUM_AS_PROPERTY(DEPTH_COMPONENT)
+ ENUM_AS_PROPERTY(ALPHA)
+ ENUM_AS_PROPERTY(RGB)
+ ENUM_AS_PROPERTY(RGBA)
+ ENUM_AS_PROPERTY(LUMINANCE)
+ ENUM_AS_PROPERTY(LUMINANCE_ALPHA)
+
+ /* PixelType */
+ /* UNSIGNED_BYTE */
+ ENUM_AS_PROPERTY(UNSIGNED_SHORT_4_4_4_4)
+ ENUM_AS_PROPERTY(UNSIGNED_SHORT_5_5_5_1)
+ ENUM_AS_PROPERTY(UNSIGNED_SHORT_5_6_5)
+
+ /* Shaders */
+ ENUM_AS_PROPERTY(FRAGMENT_SHADER)
+ ENUM_AS_PROPERTY(VERTEX_SHADER)
+ ENUM_AS_PROPERTY(MAX_VERTEX_ATTRIBS)
+ ENUM_AS_PROPERTY(MAX_VERTEX_UNIFORM_VECTORS)
+ ENUM_AS_PROPERTY(MAX_VARYING_VECTORS)
+ ENUM_AS_PROPERTY(MAX_COMBINED_TEXTURE_IMAGE_UNITS)
+ ENUM_AS_PROPERTY(MAX_VERTEX_TEXTURE_IMAGE_UNITS)
+ ENUM_AS_PROPERTY(MAX_TEXTURE_IMAGE_UNITS)
+ ENUM_AS_PROPERTY(MAX_FRAGMENT_UNIFORM_VECTORS)
+ ENUM_AS_PROPERTY(SHADER_TYPE)
+ ENUM_AS_PROPERTY(DELETE_STATUS)
+ ENUM_AS_PROPERTY(LINK_STATUS)
+ ENUM_AS_PROPERTY(VALIDATE_STATUS)
+ ENUM_AS_PROPERTY(ATTACHED_SHADERS)
+ ENUM_AS_PROPERTY(ACTIVE_UNIFORMS)
+ ENUM_AS_PROPERTY(ACTIVE_ATTRIBUTES)
+ ENUM_AS_PROPERTY(SHADING_LANGUAGE_VERSION)
+ ENUM_AS_PROPERTY(CURRENT_PROGRAM)
+
+ /* StencilFunction */
+ ENUM_AS_PROPERTY(NEVER)
+ ENUM_AS_PROPERTY(LESS)
+ ENUM_AS_PROPERTY(EQUAL)
+ ENUM_AS_PROPERTY(LEQUAL)
+ ENUM_AS_PROPERTY(GREATER)
+ ENUM_AS_PROPERTY(NOTEQUAL)
+ ENUM_AS_PROPERTY(GEQUAL)
+ ENUM_AS_PROPERTY(ALWAYS)
+
+ /* StencilOp */
+ /* ZERO */
+ ENUM_AS_PROPERTY(KEEP)
+ ENUM_AS_PROPERTY(REPLACE)
+ ENUM_AS_PROPERTY(INCR)
+ ENUM_AS_PROPERTY(DECR)
+ ENUM_AS_PROPERTY(INVERT)
+ ENUM_AS_PROPERTY(INCR_WRAP)
+ ENUM_AS_PROPERTY(DECR_WRAP)
+
+ /* StringName */
+ ENUM_AS_PROPERTY(VENDOR)
+ ENUM_AS_PROPERTY(RENDERER)
+ ENUM_AS_PROPERTY(VERSION)
+
+ /* TextureMagFilter */
+ ENUM_AS_PROPERTY(NEAREST)
+ ENUM_AS_PROPERTY(LINEAR)
+
+ /* TextureMinFilter */
+ /* NEAREST */
+ /* LINEAR */
+ ENUM_AS_PROPERTY(NEAREST_MIPMAP_NEAREST)
+ ENUM_AS_PROPERTY(LINEAR_MIPMAP_NEAREST)
+ ENUM_AS_PROPERTY(NEAREST_MIPMAP_LINEAR)
+ ENUM_AS_PROPERTY(LINEAR_MIPMAP_LINEAR)
+
+ /* TextureParameterName */
+ ENUM_AS_PROPERTY(TEXTURE_MAG_FILTER)
+ ENUM_AS_PROPERTY(TEXTURE_MIN_FILTER)
+ ENUM_AS_PROPERTY(TEXTURE_WRAP_S)
+ ENUM_AS_PROPERTY(TEXTURE_WRAP_T)
+
+ /* TextureTarget */
+ ENUM_AS_PROPERTY(TEXTURE_2D)
+ ENUM_AS_PROPERTY(TEXTURE)
+
+ ENUM_AS_PROPERTY(TEXTURE_CUBE_MAP)
+ ENUM_AS_PROPERTY(TEXTURE_BINDING_CUBE_MAP)
+ ENUM_AS_PROPERTY(TEXTURE_CUBE_MAP_POSITIVE_X)
+ ENUM_AS_PROPERTY(TEXTURE_CUBE_MAP_NEGATIVE_X)
+ ENUM_AS_PROPERTY(TEXTURE_CUBE_MAP_POSITIVE_Y)
+ ENUM_AS_PROPERTY(TEXTURE_CUBE_MAP_NEGATIVE_Y)
+ ENUM_AS_PROPERTY(TEXTURE_CUBE_MAP_POSITIVE_Z)
+ ENUM_AS_PROPERTY(TEXTURE_CUBE_MAP_NEGATIVE_Z)
+ ENUM_AS_PROPERTY(MAX_CUBE_MAP_TEXTURE_SIZE)
+
+ /* TextureUnit */
+ ENUM_AS_PROPERTY(TEXTURE0)
+ ENUM_AS_PROPERTY(TEXTURE1)
+ ENUM_AS_PROPERTY(TEXTURE2)
+ ENUM_AS_PROPERTY(TEXTURE3)
+ ENUM_AS_PROPERTY(TEXTURE4)
+ ENUM_AS_PROPERTY(TEXTURE5)
+ ENUM_AS_PROPERTY(TEXTURE6)
+ ENUM_AS_PROPERTY(TEXTURE7)
+ ENUM_AS_PROPERTY(TEXTURE8)
+ ENUM_AS_PROPERTY(TEXTURE9)
+ ENUM_AS_PROPERTY(TEXTURE10)
+ ENUM_AS_PROPERTY(TEXTURE11)
+ ENUM_AS_PROPERTY(TEXTURE12)
+ ENUM_AS_PROPERTY(TEXTURE13)
+ ENUM_AS_PROPERTY(TEXTURE14)
+ ENUM_AS_PROPERTY(TEXTURE15)
+ ENUM_AS_PROPERTY(TEXTURE16)
+ ENUM_AS_PROPERTY(TEXTURE17)
+ ENUM_AS_PROPERTY(TEXTURE18)
+ ENUM_AS_PROPERTY(TEXTURE19)
+ ENUM_AS_PROPERTY(TEXTURE20)
+ ENUM_AS_PROPERTY(TEXTURE21)
+ ENUM_AS_PROPERTY(TEXTURE22)
+ ENUM_AS_PROPERTY(TEXTURE23)
+ ENUM_AS_PROPERTY(TEXTURE24)
+ ENUM_AS_PROPERTY(TEXTURE25)
+ ENUM_AS_PROPERTY(TEXTURE26)
+ ENUM_AS_PROPERTY(TEXTURE27)
+ ENUM_AS_PROPERTY(TEXTURE28)
+ ENUM_AS_PROPERTY(TEXTURE29)
+ ENUM_AS_PROPERTY(TEXTURE30)
+ ENUM_AS_PROPERTY(TEXTURE31)
+ ENUM_AS_PROPERTY(ACTIVE_TEXTURE)
+
+ /* TextureWrapMode */
+ ENUM_AS_PROPERTY(REPEAT)
+ ENUM_AS_PROPERTY(CLAMP_TO_EDGE)
+ ENUM_AS_PROPERTY(MIRRORED_REPEAT)
+
+ /* Uniform Types */
+ ENUM_AS_PROPERTY(FLOAT_VEC2)
+ ENUM_AS_PROPERTY(FLOAT_VEC3)
+ ENUM_AS_PROPERTY(FLOAT_VEC4)
+ ENUM_AS_PROPERTY(INT_VEC2)
+ ENUM_AS_PROPERTY(INT_VEC3)
+ ENUM_AS_PROPERTY(INT_VEC4)
+ ENUM_AS_PROPERTY(BOOL)
+ ENUM_AS_PROPERTY(BOOL_VEC2)
+ ENUM_AS_PROPERTY(BOOL_VEC3)
+ ENUM_AS_PROPERTY(BOOL_VEC4)
+ ENUM_AS_PROPERTY(FLOAT_MAT2)
+ ENUM_AS_PROPERTY(FLOAT_MAT3)
+ ENUM_AS_PROPERTY(FLOAT_MAT4)
+ ENUM_AS_PROPERTY(SAMPLER_2D)
+ ENUM_AS_PROPERTY(SAMPLER_CUBE)
+
+ /* Vertex Arrays */
+ ENUM_AS_PROPERTY(VERTEX_ATTRIB_ARRAY_ENABLED)
+ ENUM_AS_PROPERTY(VERTEX_ATTRIB_ARRAY_SIZE)
+ ENUM_AS_PROPERTY(VERTEX_ATTRIB_ARRAY_STRIDE)
+ ENUM_AS_PROPERTY(VERTEX_ATTRIB_ARRAY_TYPE)
+ ENUM_AS_PROPERTY(VERTEX_ATTRIB_ARRAY_NORMALIZED)
+ ENUM_AS_PROPERTY(VERTEX_ATTRIB_ARRAY_POINTER)
+ ENUM_AS_PROPERTY(VERTEX_ATTRIB_ARRAY_BUFFER_BINDING)
+
+ /* Shader Source */
+ ENUM_AS_PROPERTY(COMPILE_STATUS)
+
+ /* Shader Precision-Specified Types */
+ ENUM_AS_PROPERTY(LOW_FLOAT)
+ ENUM_AS_PROPERTY(MEDIUM_FLOAT)
+ ENUM_AS_PROPERTY(HIGH_FLOAT)
+ ENUM_AS_PROPERTY(LOW_INT)
+ ENUM_AS_PROPERTY(MEDIUM_INT)
+ ENUM_AS_PROPERTY(HIGH_INT)
+
+ /* Framebuffer Object. */
+ ENUM_AS_PROPERTY(FRAMEBUFFER)
+ ENUM_AS_PROPERTY(RENDERBUFFER)
+
+ ENUM_AS_PROPERTY(RGBA4)
+ ENUM_AS_PROPERTY(RGB5_A1)
+ ENUM_AS_PROPERTY(RGB565)
+ ENUM_AS_PROPERTY(DEPTH_COMPONENT16)
+ ENUM_AS_PROPERTY(STENCIL_INDEX)
+ ENUM_AS_PROPERTY(STENCIL_INDEX8)
+ ENUM_AS_PROPERTY(DEPTH_STENCIL)
+
+ ENUM_AS_PROPERTY(RENDERBUFFER_WIDTH)
+ ENUM_AS_PROPERTY(RENDERBUFFER_HEIGHT)
+ ENUM_AS_PROPERTY(RENDERBUFFER_INTERNAL_FORMAT)
+ ENUM_AS_PROPERTY(RENDERBUFFER_RED_SIZE)
+ ENUM_AS_PROPERTY(RENDERBUFFER_GREEN_SIZE)
+ ENUM_AS_PROPERTY(RENDERBUFFER_BLUE_SIZE)
+ ENUM_AS_PROPERTY(RENDERBUFFER_ALPHA_SIZE)
+ ENUM_AS_PROPERTY(RENDERBUFFER_DEPTH_SIZE)
+ ENUM_AS_PROPERTY(RENDERBUFFER_STENCIL_SIZE)
+
+ ENUM_AS_PROPERTY(FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE)
+ ENUM_AS_PROPERTY(FRAMEBUFFER_ATTACHMENT_OBJECT_NAME)
+ ENUM_AS_PROPERTY(FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL)
+ ENUM_AS_PROPERTY(FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE)
+
+ ENUM_AS_PROPERTY(COLOR_ATTACHMENT0)
+ ENUM_AS_PROPERTY(DEPTH_ATTACHMENT)
+ ENUM_AS_PROPERTY(STENCIL_ATTACHMENT)
+ ENUM_AS_PROPERTY(DEPTH_STENCIL_ATTACHMENT)
+
+ ENUM_AS_PROPERTY(NONE)
+
+ ENUM_AS_PROPERTY(FRAMEBUFFER_COMPLETE)
+ ENUM_AS_PROPERTY(FRAMEBUFFER_INCOMPLETE_ATTACHMENT)
+ ENUM_AS_PROPERTY(FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT)
+ ENUM_AS_PROPERTY(FRAMEBUFFER_INCOMPLETE_DIMENSIONS)
+ ENUM_AS_PROPERTY(FRAMEBUFFER_UNSUPPORTED)
+
+ ENUM_AS_PROPERTY(FRAMEBUFFER_BINDING)
+ ENUM_AS_PROPERTY(RENDERBUFFER_BINDING)
+ ENUM_AS_PROPERTY(MAX_RENDERBUFFER_SIZE)
+
+ ENUM_AS_PROPERTY(INVALID_FRAMEBUFFER_OPERATION)
+
+ /* WebGL-specific enums */
+ ENUM_AS_PROPERTY(UNPACK_FLIP_Y_WEBGL)
+ ENUM_AS_PROPERTY(UNPACK_PREMULTIPLY_ALPHA_WEBGL)
+ ENUM_AS_PROPERTY(CONTEXT_LOST_WEBGL)
+ ENUM_AS_PROPERTY(UNPACK_COLORSPACE_CONVERSION_WEBGL)
+ ENUM_AS_PROPERTY(BROWSER_DEFAULT_WEBGL)
+
+ CanvasContext(QOpenGLContext *context, int width, int height, QObject *parent = 0);
+ ~CanvasContext();
+
+ void setCanvas(Canvas *canvas);
+ Canvas *canvas();
+
+ Q_INVOKABLE QVariantList getSupportedExtensions();
+ Q_INVOKABLE QVariant getExtension(const QString &name);
+
+ Q_INVOKABLE bool isContextLost();
+ void setContextAttributes(const CanvasContextAttributes &attribs);
+ Q_INVOKABLE CanvasContextAttributes *getContextAttributes();
+
+ Q_INVOKABLE CanvasShaderPrecisionFormat *getShaderPrecisionFormat(glEnums shadertype,
+ glEnums precisiontype);
+
+ Q_INVOKABLE void flush();
+ Q_INVOKABLE void finish();
+
+ Q_INVOKABLE CanvasTexture *createTexture();
+ Q_INVOKABLE void deleteTexture(CanvasTexture *texture);
+ Q_INVOKABLE void activeTexture(glEnums texture);
+ Q_INVOKABLE void bindTexture(glEnums target, CanvasTexture *texture);
+ Q_INVOKABLE void generateMipmap(glEnums target);
+ Q_INVOKABLE bool isTexture(QObject *texture);
+ Q_INVOKABLE void compressedTexImage2D(glEnums target, int level, glEnums internalformat,
+ int width, int height, int border,
+ CanvasTypedArray *pixels);
+ Q_INVOKABLE void compressedTexSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ int width, int height,
+ glEnums format,
+ CanvasTypedArray *pixels);
+
+ Q_INVOKABLE void copyTexImage2D(glEnums target, int level,
+ glEnums internalformat,
+ int x, int y, int width, int height,
+ int border);
+ Q_INVOKABLE void copyTexSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ int x, int y,
+ int width, int height);
+ Q_INVOKABLE void texImage2D(glEnums target, int level, glEnums internalformat,
+ int width, int height, int border,
+ glEnums format, glEnums type,
+ CanvasTypedArray *pixels);
+ Q_INVOKABLE void texSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ int width, int height,
+ glEnums format, glEnums type,
+ CanvasTypedArray *pixels);
+ Q_INVOKABLE void texImage2D(glEnums target, int level, glEnums internalformat,
+ glEnums format, glEnums type, CanvasTextureImage *image);
+ Q_INVOKABLE void texSubImage2D(glEnums target, int level,
+ int xoffset, int yoffset,
+ glEnums format, glEnums type, CanvasTextureImage *image);
+ Q_INVOKABLE void texParameterf(glEnums target, glEnums pname, float param);
+ Q_INVOKABLE void texParameteri(glEnums target, glEnums pname, int param);
+
+ Q_INVOKABLE CanvasFrameBuffer *createFramebuffer();
+ Q_INVOKABLE void bindFramebuffer(glEnums target, CanvasFrameBuffer* framebuffer);
+ Q_INVOKABLE glEnums checkFramebufferStatus(glEnums target);
+ Q_INVOKABLE void framebufferRenderbuffer(glEnums target, glEnums attachment,
+ glEnums renderbuffertarget,
+ CanvasRenderBuffer *renderbuffer);
+ Q_INVOKABLE void framebufferTexture2D(glEnums target, glEnums attachment, glEnums textarget,
+ CanvasTexture *texture, int level);
+ Q_INVOKABLE bool isFramebuffer(QObject *anyObject);
+ Q_INVOKABLE void deleteFramebuffer(CanvasFrameBuffer *buffer);
+
+ Q_INVOKABLE CanvasRenderBuffer *createRenderbuffer();
+ Q_INVOKABLE void bindRenderbuffer(glEnums target, CanvasRenderBuffer *renderbuffer);
+ Q_INVOKABLE void renderbufferStorage(glEnums target, glEnums internalformat, int width,
+ int height);
+ Q_INVOKABLE bool isRenderbuffer(QObject *anyObject);
+ Q_INVOKABLE void deleteRenderbuffer(CanvasRenderBuffer *renderbuffer);
+
+ Q_INVOKABLE void sampleCoverage(float value, bool invert);
+
+ Q_INVOKABLE CanvasShader *createShader(glEnums type);
+ Q_INVOKABLE bool isShader(QObject *anyObject);
+ Q_INVOKABLE void deleteShader(CanvasShader *shader);
+ Q_INVOKABLE void shaderSource(CanvasShader *shader, const QString &shaderSource);
+ Q_INVOKABLE QString getShaderSource(CanvasShader *shader);
+ Q_INVOKABLE void compileShader(CanvasShader *shader);
+ Q_INVOKABLE void uniform1f(CanvasUniformLocation *location, float x);
+ Q_INVOKABLE void uniform1i(CanvasUniformLocation *location, int x);
+ Q_INVOKABLE void uniform2f(CanvasUniformLocation *location, float x, float y);
+ Q_INVOKABLE void uniform2i(CanvasUniformLocation *location, int x, int y);
+ Q_INVOKABLE void uniform3f(CanvasUniformLocation *location, float x, float y, float z);
+ Q_INVOKABLE void uniform3i(CanvasUniformLocation *location, int x, int y, int z);
+ Q_INVOKABLE void uniform4f(CanvasUniformLocation *location, float x, float y, float z, float w);
+ Q_INVOKABLE void uniform4i(CanvasUniformLocation *location, int x, int y, int z, int w);
+ Q_INVOKABLE void uniform1fv(CanvasUniformLocation *location, CanvasFloat32Array *array);
+ Q_INVOKABLE void uniform1iv(CanvasUniformLocation *location, CanvasInt32Array *array);
+ Q_INVOKABLE void uniform2fv(CanvasUniformLocation *location, CanvasFloat32Array *array);
+ Q_INVOKABLE void uniform2iv(CanvasUniformLocation *location, CanvasInt32Array *array);
+ Q_INVOKABLE void uniform3fv(CanvasUniformLocation *location, CanvasFloat32Array *array);
+ Q_INVOKABLE void uniform3iv(CanvasUniformLocation *location, CanvasInt32Array *array);
+ Q_INVOKABLE void uniform4fv(CanvasUniformLocation *location, CanvasFloat32Array *array);
+ Q_INVOKABLE void uniform4iv(CanvasUniformLocation *location, CanvasInt32Array *array);
+
+ Q_INVOKABLE void uniform1fva(CanvasUniformLocation *location, QVariantList array);
+ Q_INVOKABLE void uniform2fva(CanvasUniformLocation *location, QVariantList array);
+ Q_INVOKABLE void uniform3fva(CanvasUniformLocation *location, QVariantList array);
+ Q_INVOKABLE void uniform4fva(CanvasUniformLocation *location, QVariantList array);
+ Q_INVOKABLE void uniform1iva(CanvasUniformLocation *location, QVariantList array);
+ Q_INVOKABLE void uniform2iva(CanvasUniformLocation *location, QVariantList array);
+ Q_INVOKABLE void uniform3iva(CanvasUniformLocation *location, QVariantList array);
+ Q_INVOKABLE void uniform4iva(CanvasUniformLocation *location, QVariantList array);
+
+ Q_INVOKABLE void uniformMatrix2fv(CanvasUniformLocation *location, bool transpose,
+ CanvasFloat32Array *value);
+ Q_INVOKABLE void uniformMatrix3fv(CanvasUniformLocation *location, bool transpose,
+ CanvasFloat32Array *value);
+ Q_INVOKABLE void uniformMatrix4fv(CanvasUniformLocation *location, bool transpose,
+ CanvasFloat32Array *value);
+ Q_INVOKABLE void uniformMatrix2fva(CanvasUniformLocation *location, bool transpose,
+ QVariantList value);
+ Q_INVOKABLE void uniformMatrix3fva(CanvasUniformLocation *location, bool transpose,
+ QVariantList value);
+ Q_INVOKABLE void uniformMatrix4fva(CanvasUniformLocation *uniformLocation, bool transpose,
+ QVariantList value);
+
+ // TODO: Q_INVOKABLE void uniform1iv(UniformLocation *location, sequence<long> v);
+ Q_INVOKABLE CanvasProgram *createProgram();
+ Q_INVOKABLE void attachShader(CanvasProgram *program, CanvasShader *shader);
+ Q_INVOKABLE void detachShader(CanvasProgram *program, CanvasShader *shader);
+ Q_INVOKABLE void linkProgram(CanvasProgram *program);
+ Q_INVOKABLE void useProgram(CanvasProgram *program);
+ Q_INVOKABLE void validateProgram(CanvasProgram *program);
+ Q_INVOKABLE CanvasUniformLocation *getUniformLocation(CanvasProgram *program,
+ const QString &name);
+ Q_INVOKABLE int getAttribLocation(CanvasProgram *program, const QString &name);
+ Q_INVOKABLE void bindAttribLocation(CanvasProgram *program, int index, const QString &name);
+ Q_INVOKABLE QString getProgramInfoLog(CanvasProgram *program) const;
+ Q_INVOKABLE bool isProgram(QObject *anyObject);
+ Q_INVOKABLE void deleteProgram(CanvasProgram *program);
+
+ Q_INVOKABLE void disableVertexAttribArray(int index);
+ Q_INVOKABLE void enableVertexAttribArray(int index);
+ Q_INVOKABLE void vertexAttribPointer(int indx, int size, glEnums type,
+ bool normalized, int stride, long offset);
+ Q_INVOKABLE void vertexAttrib1f(unsigned int indx, float x);
+ Q_INVOKABLE void vertexAttrib1fv(unsigned int indx, CanvasFloat32Array *values);
+ Q_INVOKABLE void vertexAttrib2f(unsigned int indx, float x, float y);
+ Q_INVOKABLE void vertexAttrib2fv(unsigned int indx, CanvasFloat32Array *values);
+ Q_INVOKABLE void vertexAttrib3f(unsigned int indx, float x, float y, float z);
+ Q_INVOKABLE void vertexAttrib3fv(unsigned int indx, CanvasFloat32Array *values);
+ Q_INVOKABLE void vertexAttrib4f(unsigned int indx, float x, float y, float z, float w);
+ Q_INVOKABLE void vertexAttrib4fv(unsigned int indx, CanvasFloat32Array *values);
+
+ Q_INVOKABLE int getShaderParameter(CanvasShader *shader, glEnums paramName);
+ Q_INVOKABLE QVariant getProgramParameter(CanvasProgram *program, glEnums paramName);
+ Q_INVOKABLE QString getShaderInfoLog(CanvasShader *shader) const;
+
+ /* Buffer object methods */
+ Q_INVOKABLE CanvasBuffer *createBuffer();
+ Q_INVOKABLE void bindBuffer(glEnums target, CanvasBuffer *buffer);
+ Q_INVOKABLE void bufferData(glEnums target, long size, glEnums hint);
+ Q_INVOKABLE void bufferData(glEnums target, CanvasTypedArray *data, glEnums hint);
+ Q_INVOKABLE void bufferData(glEnums target, CanvasArrayBuffer &data, glEnums hint);
+ Q_INVOKABLE void bufferSubData(glEnums target, int offset, CanvasTypedArray *data);
+ Q_INVOKABLE void bufferSubData(glEnums target, int offset, CanvasArrayBuffer &data);
+
+ Q_INVOKABLE QVariant getBufferParameter(glEnums target, glEnums pname);
+ Q_INVOKABLE bool isBuffer(QObject *anyObject);
+ Q_INVOKABLE void deleteBuffer(CanvasBuffer *buffer);
+
+ Q_INVOKABLE glEnums getError();
+
+ Q_INVOKABLE void cullFace(glEnums mode);
+ Q_INVOKABLE void frontFace(glEnums mode);
+
+ Q_INVOKABLE void lineWidth(float width);
+ Q_INVOKABLE void pixelStorei(glEnums pname, int param);
+ Q_INVOKABLE void polygonOffset(float factor, float units);
+ Q_INVOKABLE void hint(glEnums target, glEnums mode);
+ Q_INVOKABLE void enable(glEnums cap);
+ Q_INVOKABLE bool isEnabled(glEnums cap);
+ Q_INVOKABLE void disable(glEnums cap);
+
+ Q_INVOKABLE QVariant getParameter(glEnums pname);
+
+ Q_INVOKABLE void clear(glEnums flags);
+ Q_INVOKABLE void depthMask(bool flag);
+ Q_INVOKABLE void depthFunc(glEnums func);
+ Q_INVOKABLE void depthRange(float zNear, float zFar);
+ Q_INVOKABLE void clearDepth(float depth);
+ Q_INVOKABLE void clearColor(float red, float green, float blue, float alpha);
+ Q_INVOKABLE void clearStencil(int s);
+ Q_INVOKABLE void colorMask(bool red, bool green, bool blue, bool alpha);
+
+ Q_INVOKABLE void blendColor(float red, float green, float blue, float alpha);
+ Q_INVOKABLE void blendEquation(glEnums mode);
+ Q_INVOKABLE void blendEquationSeparate(glEnums modeRGB, glEnums modeAlpha);
+ Q_INVOKABLE void blendFunc(glEnums sfactor, glEnums dfactor);
+ Q_INVOKABLE void blendFuncSeparate(glEnums srcRGB, glEnums dstRGB, glEnums srcAlpha,
+ glEnums dstAlpha);
+
+ Q_INVOKABLE void drawArrays(glEnums type, int first, int count);
+ Q_INVOKABLE void drawElements(glEnums mode, int count, glEnums type, long offset);
+
+ Q_INVOKABLE void viewport(int x, int y, int width, int height);
+
+ Q_INVOKABLE void scissor(int x, int y, int width, int height);
+
+ Q_INVOKABLE void readPixels(int x, int y, long width, long height, glEnums format,
+ glEnums type, CanvasArrayBufferView *pixels);
+
+ QString glEnumToString(glEnums value) const;
+ float devicePixelRatio();
+ void setDevicePixelRatio(float ratio);
+ CanvasTypedArray *createTypedArray(glEnums dataType, long size);
+ int getSufficientSize(glEnums internalFormat, int width, int height);
+
+ QRect glViewportRect() const;
+ GLuint currentFramebuffer();
+
+ void setLogAllCalls(bool logCalls);
+ bool logAllCalls() const;
+ void setLogAllErrors(bool logErrors);
+ bool logAllErrors() const;
+
+signals:
+ //void viewportChanged(const QRect &viewport); // TODO: unused
+ //void viewportWidthChanged(int width); // TODO: unused
+ //void viewportHeightChanged(int height); // TODO: unused
+ void canvasChanged(Canvas *canvas);
+ void logAllCallsChanged(bool logCalls);
+ void logAllErrorsChanged(bool logErrors);
+
+private:
+
+ bool m_logAllCalls;
+ bool m_logAllErrors;
+ QRect m_glViewportRect;
+
+ qreal m_devicePixelRatio;
+ CanvasProgram *m_currentProgram;
+ CanvasBuffer *m_currentArrayBuffer;
+ CanvasBuffer *m_currentElementArrayBuffer;
+ CanvasTexture *m_currentTexture;
+ QOpenGLContext *m_context;
+ glEnums m_error;
+ CanvasFrameBuffer *m_currentFramebuffer;
+ CanvasRenderBuffer *m_currentRenderbuffer;
+ CanvasContextAttributes m_contextAttributes;
+ friend class Canvas;
+ friend class QFBOCanvas3D;
+ QString m_emptyString;
+ EnumToStringMap *m_map;
+ Canvas *m_canvas;
+};
+
+#endif // CONTEXT3D_P_H
diff --git a/src/contextattributes.cpp b/src/contextattributes.cpp
new file mode 100644
index 0000000..9f39983
--- /dev/null
+++ b/src/contextattributes.cpp
@@ -0,0 +1,282 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "contextattributes_p.h"
+
+#include <QVariantMap>
+#include <QDebug>
+
+/*!
+ * \qmltype ContextAttributes
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Attribute set for Context3D
+ *
+ * ContextAttributes is an attribute set that can be given as parameter on first call to
+ * Canvas3D object's \l{Canvas3D::getContext()}{getContext(string type, ContextAttributes options)}
+ * method call. It can also be requested from the Context3D later on to verify what exact
+ * attributes are in fact enabled/disabled in the created context.
+ *
+ * \sa Context3D, Canvas3D, {QML Canvas 3D QML Types}
+ */
+
+/*!
+ * \internal
+ */
+CanvasContextAttributes::CanvasContextAttributes(QObject *parent) :
+ QObject(parent),
+ m_alpha(false), // Should be true according to official WebGL spec. But ignored for now.
+ m_depth(false),
+ m_stencil(false),
+ m_antialias(false),
+ m_premultipliedAlpha(false),
+ m_preserveDrawingBuffer(false),
+ m_preferLowPowerToHighPerformance(false),
+ m_failIfMajorPerformanceCaveat(false)
+{
+}
+
+/*!
+ * \internal
+ */
+CanvasContextAttributes::~CanvasContextAttributes()
+{
+}
+
+/*!
+ * \internal
+ */
+void CanvasContextAttributes::setFrom(const QVariantMap &options)
+{
+ for (QVariantMap::const_iterator iter = options.begin(); iter != options.end(); ++iter) {
+ if (iter.key() == "alpha")
+ setAlpha(iter.value().toBool());
+ else if (iter.key() == "depth")
+ setDepth(iter.value().toBool());
+ else if (iter.key() == "stencil")
+ setStencil(iter.value().toBool());
+ else if (iter.key() == "antialias")
+ setAntialias(iter.value().toBool());
+ else if (iter.key() == "premultipliedAlpha")
+ setPremultipliedAlpha(iter.value().toBool());
+ else if (iter.key() == "preserveDrawingBuffer")
+ setPreserveDrawingBuffer(iter.value().toBool());
+ else if (iter.key() == "preferLowPowerToHighPerformance")
+ setPreferLowPowerToHighPerformance(iter.value().toBool());
+ else if (iter.key() == "failIfMajorPerformanceCaveat")
+ setFailIfMajorPerformanceCaveat(iter.value().toBool());
+ }
+}
+
+/*!
+ * \internal
+ */
+void CanvasContextAttributes::setFrom(const CanvasContextAttributes &source)
+{
+ m_alpha = source.alpha();
+ m_depth = source.depth();
+ m_stencil = source.stencil();
+ m_antialias = source.antialias();
+ m_premultipliedAlpha = source.premultipliedAlpha();
+ m_preserveDrawingBuffer = source.preserveDrawingBuffer();
+ m_preferLowPowerToHighPerformance = source.preferLowPowerToHighPerformance();
+ m_failIfMajorPerformanceCaveat = source.failIfMajorPerformanceCaveat();
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::alpha
+ * Ignored. Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::alpha() const
+{
+ return m_alpha;
+}
+
+void CanvasContextAttributes::setAlpha(bool value)
+{
+ if (m_alpha == value)
+ return;
+
+ m_alpha = value;
+ emit alphaChanged(value);
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::depth
+ * Specifies whether a depth attachment is to be created and attached to the default render target
+ * of the Context3D.
+ * Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::depth() const
+{
+ return m_depth;
+}
+
+void CanvasContextAttributes::setDepth(bool value)
+{
+ if (m_depth == value)
+ return;
+
+ m_depth = value;
+ emit depthChanged(value);
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::stencil
+ * Specifies whether a stencil attachment is to be created and attached to the default render
+ * target of the Context3D.
+ * Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::stencil() const
+{
+ return m_stencil;
+}
+
+void CanvasContextAttributes::setStencil(bool value)
+{
+ if (m_stencil == value)
+ return;
+
+ m_stencil = value;
+ emit stencilChanged(value);
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::antialias
+ * Specifies whether antialiasing buffer is created for the default render target of the Context3D.
+ * Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::antialias() const
+{
+ return m_antialias;
+}
+
+void CanvasContextAttributes::setAntialias(bool value)
+{
+ if (m_antialias == value)
+ return;
+
+ m_antialias = value;
+ emit antialiasChanged(value);
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::premultipliedAlpha
+ * Ignored. Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::premultipliedAlpha() const
+{
+ return m_premultipliedAlpha;
+}
+
+void CanvasContextAttributes::setPremultipliedAlpha(bool value)
+{
+ if (m_premultipliedAlpha == value)
+ return;
+
+ m_premultipliedAlpha = value;
+ emit premultipliedAlphaChanged(value);
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::preserveDrawingBuffer
+ * Ignored. Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::preserveDrawingBuffer() const
+{
+ return m_preserveDrawingBuffer;
+}
+
+void CanvasContextAttributes::setPreserveDrawingBuffer(bool value)
+{
+ if (m_preserveDrawingBuffer == value)
+ return;
+
+ m_preserveDrawingBuffer = value;
+ emit preserveDrawingBufferChanged(value);
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::preferLowPowerToHighPerformance
+ * Ignored. Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::preferLowPowerToHighPerformance() const
+{
+ return m_preferLowPowerToHighPerformance;
+}
+
+void CanvasContextAttributes::setPreferLowPowerToHighPerformance(bool value)
+{
+ if (m_preferLowPowerToHighPerformance == value)
+ return;
+
+ m_preferLowPowerToHighPerformance = value;
+ emit preferLowPowerToHighPerformanceChanged(value);
+}
+
+/*!
+ * \qmlproperty bool ContextAttributes::failIfMajorPerformanceCaveat
+ * Ignored. Defaults to \c{false}.
+ */
+bool CanvasContextAttributes::failIfMajorPerformanceCaveat() const
+{
+ return m_failIfMajorPerformanceCaveat;
+}
+
+void CanvasContextAttributes::setFailIfMajorPerformanceCaveat(bool value)
+{
+ if (m_failIfMajorPerformanceCaveat == value)
+ return;
+
+ m_failIfMajorPerformanceCaveat = value;
+ emit failIfMajorPerformanceCaveatChanged(value);
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasContextAttributes &attribs)
+{
+ dbg.nospace() << "ContextAttributes(\n alpha:"<< attribs.m_alpha <<
+ "\n depth:" << attribs.m_depth <<
+ "\n m_stencil:" << attribs.m_stencil <<
+ "\n antialias:"<< attribs.m_antialias <<
+ "\n premultipliedAlpha:" << attribs.m_premultipliedAlpha <<
+ "\n preserveDrawingBuffer:" << attribs.m_preserveDrawingBuffer <<
+ "\n preferLowPowerToHighPerformance:" << attribs.m_preferLowPowerToHighPerformance <<
+ "\n failIfMajorPerformanceCaveat:" << attribs.m_failIfMajorPerformanceCaveat << ")";
+ return dbg.maybeSpace();
+}
diff --git a/src/contextattributes_p.h b/src/contextattributes_p.h
new file mode 100644
index 0000000..7abc012
--- /dev/null
+++ b/src/contextattributes_p.h
@@ -0,0 +1,112 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CONTEXTATTRIBUTES_P_H
+#define CONTEXTATTRIBUTES_P_H
+
+#include <QObject>
+
+class CanvasContextAttributes : public QObject
+{
+ Q_OBJECT
+
+ Q_ENUMS(RenderingMode)
+ Q_PROPERTY(bool alpha READ alpha WRITE setAlpha NOTIFY alphaChanged)
+ Q_PROPERTY(bool depth READ depth WRITE setDepth NOTIFY depthChanged)
+ Q_PROPERTY(bool stencil READ stencil WRITE setStencil NOTIFY stencilChanged)
+ Q_PROPERTY(bool antialias READ antialias WRITE setAntialias NOTIFY antialiasChanged)
+ Q_PROPERTY(bool premultipliedAlpha READ premultipliedAlpha WRITE setPremultipliedAlpha NOTIFY premultipliedAlphaChanged)
+ Q_PROPERTY(bool preserveDrawingBuffer READ preserveDrawingBuffer WRITE setPreserveDrawingBuffer NOTIFY preserveDrawingBufferChanged)
+ Q_PROPERTY(bool preferLowPowerToHighPerformance READ preferLowPowerToHighPerformance WRITE setPreferLowPowerToHighPerformance NOTIFY preferLowPowerToHighPerformanceChanged)
+ Q_PROPERTY(bool failIfMajorPerformanceCaveat READ failIfMajorPerformanceCaveat WRITE setFailIfMajorPerformanceCaveat NOTIFY failIfMajorPerformanceCaveatChanged)
+
+public:
+ explicit CanvasContextAttributes(QObject *parent = 0);
+ virtual ~CanvasContextAttributes();
+
+ void setFrom(const QVariantMap &options);
+ void setFrom(const CanvasContextAttributes &source);
+ bool alpha() const;
+ void setAlpha(bool value);
+ bool depth() const;
+ void setDepth(bool value);
+ bool stencil() const;
+ void setStencil(bool value);
+ bool antialias() const;
+ void setAntialias(bool value);
+ bool premultipliedAlpha() const;
+ void setPremultipliedAlpha(bool value);
+ bool preserveDrawingBuffer() const;
+ void setPreserveDrawingBuffer(bool value);
+ bool preferLowPowerToHighPerformance() const;
+ void setPreferLowPowerToHighPerformance(bool value);
+ bool failIfMajorPerformanceCaveat() const;
+ void setFailIfMajorPerformanceCaveat(bool value);
+
+ friend QDebug operator<< (QDebug d, const CanvasContextAttributes &attribs);
+
+signals:
+ void alphaChanged(bool newValue);
+ void depthChanged(bool newValue);
+ void stencilChanged(bool newValue);
+ void antialiasChanged(bool newValue);
+ void premultipliedAlphaChanged(bool newValue);
+ void preserveDrawingBufferChanged(bool newValue);
+ void preferLowPowerToHighPerformanceChanged(bool newValue);
+ void failIfMajorPerformanceCaveatChanged(bool newValue);
+
+private:
+ bool m_alpha;
+ bool m_depth;
+ bool m_stencil;
+ bool m_antialias;
+ bool m_premultipliedAlpha;
+ bool m_preserveDrawingBuffer;
+ bool m_preferLowPowerToHighPerformance;
+ bool m_failIfMajorPerformanceCaveat;
+};
+
+#endif // QCONTEXTATTRIBUTES_P_H
diff --git a/src/contextextensions.cpp b/src/contextextensions.cpp
new file mode 100644
index 0000000..9ee7912
--- /dev/null
+++ b/src/contextextensions.cpp
@@ -0,0 +1,42 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "contextextensions_p.h"
+
+WEBGL_debug_renderer_info::WEBGL_debug_renderer_info(QObject *parent) :
+ QObject(parent)
+{
+}
diff --git a/src/contextextensions_p.h b/src/contextextensions_p.h
new file mode 100644
index 0000000..3006535
--- /dev/null
+++ b/src/contextextensions_p.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CONTEXTEXTENSIONS_P_H
+#define CONTEXTEXTENSIONS_P_H
+
+#include "context3d_p.h"
+#include "canvas3dcommon_p.h"
+
+class WEBGL_debug_renderer_info : public QObject
+{
+ Q_OBJECT
+
+ ENUM_AS_PROPERTY(UNMASKED_VENDOR_WEBGL)
+ ENUM_AS_PROPERTY(UNMASKED_RENDERER_WEBGL)
+
+ public:
+ explicit WEBGL_debug_renderer_info(QObject *parent = 0);
+};
+
+#endif // CONTEXTEXTENSIONS_P_H
diff --git a/src/doc/qtcanvas3d.qdocconf b/src/doc/qtcanvas3d.qdocconf
new file mode 100644
index 0000000..21e94dd
--- /dev/null
+++ b/src/doc/qtcanvas3d.qdocconf
@@ -0,0 +1,55 @@
+include($QT_INSTALL_DOCS/global/macros.qdocconf)
+include($QT_INSTALL_DOCS/global/qt-cpp-defines.qdocconf)
+include($QT_INSTALL_DOCS/global/compat.qdocconf)
+include($QT_INSTALL_DOCS/global/fileextensions.qdocconf)
+include($QT_INSTALL_DOCS/global/qt-html-templates-offline.qdocconf)
+
+project = QtCanvas3D
+description = QML 3D Canvas Reference Documentation
+version = 0.8.0
+
+exampledirs = ../../examples/canvas3d \
+ snippets
+
+imagedirs += images
+headerdirs += ..
+sourcedirs += ..
+
+examplesinstallpath = canvas3d
+
+indexes += $QT_INSTALL_DOCS/qtcore/qtcore.index \
+ $QT_INSTALL_DOCS/qtgui/qtgui.index \
+ $QT_INSTALL_DOCS/qtqml/qtqml.index \
+ $QT_INSTALL_DOCS/qtquick/qtquick.index \
+ $QT_INSTALL_DOCS/qtmultimedia/qtmultimedia.index
+
+qhp.projects = QtCanvas3D
+
+qhp.QtCanvas3D.file = qtcanvas3d.qhp
+qhp.QtCanvas3D.namespace = com.digia.qtcanvas3d.080
+qhp.QtCanvas3D.virtualFolder = qtcanvas3d
+qhp.QtCanvas3D.indexTitle = QML 3D Canvas
+qhp.QtCanvas3D.indexRoot =
+
+qhp.QtCanvas3D.filterAttributes = qtcanvas3d 0.8.0 qtrefdoc
+qhp.QtCanvas3D.customFilters.Qt.name = QtCanvas3D 0.8.0
+qhp.QtCanvas3D.customFilters.Qt.filterAttributes = qtcanvas3d 0.8.0
+qhp.QtCanvas3D.subprojects = gettingstarted examples types
+qhp.QtCanvas3D.subprojects.gettingstarted.title = Getting Started
+qhp.QtCanvas3D.subprojects.gettingstarted.indexTitle = QtCanvas3D Getting Started
+qhp.QtCanvas3D.subprojects.gettingstarted.selectors = fake:page
+qhp.QtCanvas3D.subprojects.gettingstarted.sortPages = true
+qhp.QtCanvas3D.subprojects.examples.title = Examples
+qhp.QtCanvas3D.subprojects.examples.indexTitle = QtCanvas3D Examples
+qhp.QtCanvas3D.subprojects.examples.selectors = fake:example
+qhp.QtCanvas3D.subprojects.examples.sortPages = true
+qhp.QtCanvas3D.subprojects.types.title = QML Types
+qhp.QtCanvas3D.subprojects.types.indexTitle = QtCanvas3D QML Types
+qhp.QtCanvas3D.subprojects.types.selectors = fake:qmlclass
+qhp.QtCanvas3D.subprojects.types.sortPages = true
+
+navigation.landingpage = QML 3D Canvas
+navigation.qmltypespage = QML Canvas 3D QML Types
+navigation.examplespage = QML Canvas 3D Examples
+
+buildversion = QML 3D Canvas $QT_VERSION Reference Documentation
diff --git a/src/doc/snippets/doc_src_qtcanvas3d.cpp b/src/doc/snippets/doc_src_qtcanvas3d.cpp
new file mode 100644
index 0000000..e6c820a
--- /dev/null
+++ b/src/doc/snippets/doc_src_qtcanvas3d.cpp
@@ -0,0 +1,4 @@
+//! [0]
+import QtCanvas3D 1.0
+//! [0]
+
diff --git a/src/doc/snippets/doc_src_qtcanvas3d.pro b/src/doc/snippets/doc_src_qtcanvas3d.pro
new file mode 100644
index 0000000..a3973f0
--- /dev/null
+++ b/src/doc/snippets/doc_src_qtcanvas3d.pro
@@ -0,0 +1,3 @@
+#! [0]
+QT += qtcanvas3d
+#! [0]
diff --git a/src/doc/src/qtcanvas3d-index.qdoc b/src/doc/src/qtcanvas3d-index.qdoc
new file mode 100644
index 0000000..854cdc6
--- /dev/null
+++ b/src/doc/src/qtcanvas3d-index.qdoc
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \title QtCanvas3D
+ \page index.html
+ \brief Provides functionality for 3D drawing inside Qt Quick 2.
+
+ QtCanvas3D module provides a way to make OpenGL-like 3D drawing calls from Qt Quick JavaScript.
+
+ \section1 Features
+
+ \list
+ \li Uses OpenGL or OpenGL ES2 for rendering.
+ \li Qt Quick 2 support
+ \endlist
+
+ \section1 Getting Started
+
+ To import QtCanvas3D QML types, add the following import statement to your \c .qml
+ file:
+
+ \snippet doc_src_qtcanvas3d.cpp 0
+
+ See the \l{QML Canvas 3D Getting Started}{Getting started} page for further information on
+ how to use QML 3D Canvas in your application.
+
+ \section1 References
+
+ \list
+ \li \l{QML Canvas 3D QML Types}
+ \li \l{QML Canvas 3D Examples}
+ \li \l {QML Canvas 3D Known Issues}
+ \endlist
+
+*/
diff --git a/src/doc/src/qtcanvas3d.qdoc b/src/doc/src/qtcanvas3d.qdoc
new file mode 100644
index 0000000..a34c385
--- /dev/null
+++ b/src/doc/src/qtcanvas3d.qdoc
@@ -0,0 +1,179 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \qmlmodule QtCanvas3D 1.0
+ \title QML Canvas 3D QML Types
+ \ingroup qmlmodules
+
+ \brief QML types for the QtCanvas3D API.
+
+ The QtCanvas3D functionality can be accessed via these QML types.
+
+ \section1 QML Types
+
+ \annotatedlist qtcanvas3d-qml-types
+*/
+
+/*!
+ \group qtcanvas3d-examples
+ \ingroup all-examples
+ \title QML Canvas 3D Examples
+
+ \brief Examples for the QtCanvas3D.
+
+ For some code examples, see one of the QtCanvas3D examples:
+
+ \section1 Examples
+*/
+
+/*!
+ \group qtcanvas3d-getting-started
+ \title QML Canvas 3D Getting Started
+
+ \section1 Building QtCanvas3D
+
+ To build the QtCanvas3D module from source code, set up a command prompt
+ with an environment for building Qt applications, navigate to the directory containing
+ \c {qtcanvas3d.pro}, and configure the project with qmake:
+ \code
+ qmake
+ \endcode
+
+ After running qmake, build the project with make:
+ \table
+ \header
+ \li OS \li Make command
+ \row
+ \li Linux \li make
+ \row
+ \li Windows (MinGw) \li mingw32-make
+ \row
+ \li Windows (MSVC) \li nmake
+ \row
+ \li OSX \li make
+ \endtable
+
+ The above generates the default makefiles for your configuration, which is typically
+ the release build if you are using precompiled binary Qt distribution. To build both debug
+ and release, or one specifically, use one of the following qmake lines instead.
+
+ For debug builds:
+ \code
+ qmake CONFIG+=debug
+ make
+ \endcode
+ or
+ \code
+ qmake CONFIG+=debug_and_release
+ make debug
+ \endcode
+
+ For release builds:
+ \code
+ qmake CONFIG+=release
+ make
+ \endcode
+ or
+ \code
+ qmake CONFIG+=debug_and_release
+ make release
+ \endcode
+
+ For both builds (Windows/Mac only):
+ \code
+ qmake CONFIG+="debug_and_release build_all"
+ make
+ \endcode
+
+ After building, install the module to your Qt directory:
+ \code
+ make install
+ \endcode
+
+ If you want to uninstall the module:
+ \code
+ make uninstall
+ \endcode
+
+ To build a statically linked version of the QtCanvas3D module, give the following
+ commands:
+
+ \code
+ qmake CONFIG+=static
+ make
+ make install
+ \endcode
+
+ \section1 Running examples
+
+ QtCanvas3D examples are found under the \c examples subdirectory. To build and run a
+ single example, in this case \c{interaction}, navigate to the example directory and enter the
+ following commands:
+
+ \code
+ qmake
+ make
+ ./interaction
+ \endcode
+
+ \note On some platforms, such as Windows, the executable can be generated under debug or
+ release folders, depending on your build.
+
+ \section1 A Basic Example
+
+ For a simple Canvas3D example concentrating on the QML side see the \l {Textured Cube Example},
+ or for one concentrating on the JavaScript side see the \l {Lit and Textured Cube Example}.
+
+ For all the QtCanvas3D examples, check out \l {QML Canvas 3D Examples}
+*/
+
+/*!
+ \group qtcanvas3d-known-issues
+ \title QML Canvas 3D Known Issues
+
+ \brief The known issues of QML 3D Canvas.
+
+ \list
+ \li QObject based TypedArray implementation is a temporary stop gap solution and will be removed from QtCanvas3D later on.
+ \li Texturing does not work perfectly in all of the examples.
+ \li \l{Interaction Example} and \l{JSON Models Example} crash on some Macs on startup.
+ \li Using Qt Quick Enterprise Controls buttons cause a crash on application exit
+ on Windows in certain circumstances (try \l{JSON Models Example} for reference).
+ \li Resizing window works incorrectly if viewport is updated during rendering to match
+ the window size (try \l{Framebuffer Example} for reference).
+ \endlist
+*/
diff --git a/src/enumtostringmap.cpp b/src/enumtostringmap.cpp
new file mode 100644
index 0000000..c9605f0
--- /dev/null
+++ b/src/enumtostringmap.cpp
@@ -0,0 +1,426 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "enumtostringmap_p.h"
+
+static EnumToStringMap *theInstance = 0;
+static unsigned int theInstanceCount = 0;
+
+EnumToStringMap *EnumToStringMap::newInstance()
+{
+ if (theInstance) {
+ theInstanceCount++;
+ return theInstance;
+ }
+
+ theInstance = new EnumToStringMap();
+ theInstanceCount++;
+ return theInstance;
+}
+
+void EnumToStringMap::deleteInstance()
+{
+ theInstanceCount--;
+ if (theInstanceCount <= 0) {
+ delete theInstance;
+ theInstance = 0;
+ }
+}
+
+EnumToStringMap::EnumToStringMap() :
+ m_unknown("<unknown>")
+{
+ m_map[CanvasContext::ZERO] = "ZERO/null";
+
+ m_map[CanvasContext::DEPTH_BUFFER_BIT] = "DEPTH_BUFFER_BIT";
+ m_map[CanvasContext::STENCIL_BUFFER_BIT] = "STENCIL_BUFFER_BIT";
+ m_map[CanvasContext::COLOR_BUFFER_BIT] = "COLOR_BUFFER_BIT";
+
+ m_map[(CanvasContext::DEPTH_AND_COLOR_BUFFER_BIT )] = "DEPTH_BUFFER_BIT | COLOR_BUFFER_BIT";
+ m_map[(CanvasContext::DEPTH_AND_STENCIL_AND_COLOR_BUFFER_BIT )] = "DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT";
+ m_map[CanvasContext::STENCIL_BUFFER_BIT] = "STENCIL_BUFFER_BIT";
+ m_map[CanvasContext::COLOR_BUFFER_BIT] = "COLOR_BUFFER_BIT";
+
+ m_map[CanvasContext::POINTS] = "POINTS";
+ m_map[CanvasContext::LINES] = "LINES";
+ m_map[CanvasContext::LINE_LOOP] = "LINE_LOOP";
+ m_map[CanvasContext::LINE_STRIP] = "LINE_STRIP";
+ m_map[CanvasContext::TRIANGLES] = "TRIANGLES";
+ m_map[CanvasContext::TRIANGLE_STRIP] = "TRIANGLE_STRIP";
+ m_map[CanvasContext::TRIANGLE_FAN] = "TRIANGLE_FAN";
+
+ m_map[CanvasContext::SRC_COLOR] = "SRC_COLOR";
+ m_map[CanvasContext::ONE_MINUS_SRC_COLOR] = "ONE_MINUS_SRC_COLOR";
+ m_map[CanvasContext::SRC_ALPHA] = "SRC_ALPHA";
+ m_map[CanvasContext::ONE_MINUS_SRC_ALPHA] = "ONE_MINUS_SRC_ALPHA";
+ m_map[CanvasContext::DST_ALPHA] = "DST_ALPHA";
+ m_map[CanvasContext::ONE_MINUS_DST_ALPHA] = "ONE_MINUS_DST_ALPHA";
+
+ m_map[CanvasContext::DST_COLOR] = "DST_COLOR";
+ m_map[CanvasContext::ONE_MINUS_DST_COLOR] = "ONE_MINUS_DST_COLOR";
+ m_map[CanvasContext::SRC_ALPHA_SATURATE] = "SRC_ALPHA_SATURATE";
+
+ m_map[CanvasContext::FUNC_ADD] = "FUNC_ADD";
+ m_map[CanvasContext::BLEND_EQUATION] = "BLEND_EQUATION";
+ m_map[CanvasContext::BLEND_EQUATION_RGB] = "BLEND_EQUATION_RGB";
+ m_map[CanvasContext::BLEND_EQUATION_ALPHA] = "BLEND_EQUATION_ALPHA";
+
+ m_map[CanvasContext::FUNC_SUBTRACT] = "FUNC_SUBTRACT";
+ m_map[CanvasContext::FUNC_REVERSE_SUBTRACT] = "FUNC_REVERSE_SUBTRACT";
+
+ m_map[CanvasContext::BLEND_DST_RGB] = "BLEND_DST_RGB";
+ m_map[CanvasContext::BLEND_SRC_RGB] = "BLEND_SRC_RGB";
+ m_map[CanvasContext::BLEND_DST_ALPHA] = "BLEND_DST_ALPHA";
+ m_map[CanvasContext::BLEND_SRC_ALPHA] = "BLEND_SRC_ALPHA";
+ m_map[CanvasContext::CONSTANT_COLOR] = "CONSTANT_COLOR";
+ m_map[CanvasContext::ONE_MINUS_CONSTANT_COLOR] = "ONE_MINUS_CONSTANT_COLOR";
+ m_map[CanvasContext::CONSTANT_ALPHA] = "CONSTANT_ALPHA";
+ m_map[CanvasContext::ONE_MINUS_CONSTANT_ALPHA] = "ONE_MINUS_CONSTANT_ALPHA";
+ m_map[CanvasContext::BLEND_COLOR] = "BLEND_COLOR";
+
+ m_map[CanvasContext::ARRAY_BUFFER] = "ARRAY_BUFFER";
+ m_map[CanvasContext::ELEMENT_ARRAY_BUFFER] = "ELEMENT_ARRAY_BUFFER";
+ m_map[CanvasContext::ARRAY_BUFFER_BINDING] = "ARRAY_BUFFER_BINDING";
+ m_map[CanvasContext::ELEMENT_ARRAY_BUFFER_BINDING] = "ELEMENT_ARRAY_BUFFER_BINDING";
+
+ m_map[CanvasContext::STREAM_DRAW] = "STREAM_DRAW";
+ m_map[CanvasContext::STATIC_DRAW] = "STATIC_DRAW";
+ m_map[CanvasContext::DYNAMIC_DRAW] = "DYNAMIC_DRAW";
+
+ m_map[CanvasContext::BUFFER_SIZE] = "BUFFER_SIZE";
+ m_map[CanvasContext::BUFFER_USAGE] = "BUFFER_USAGE";
+
+ m_map[CanvasContext::CURRENT_VERTEX_ATTRIB] = "CURRENT_VERTEX_ATTRIB";
+
+ m_map[CanvasContext::FRONT] = "FRONT";
+ m_map[CanvasContext::BACK] = "BACK";
+ m_map[CanvasContext::FRONT_AND_BACK] = "FRONT_AND_BACK";
+
+ m_map[CanvasContext::CULL_FACE] = "CULL_FACE";
+ m_map[CanvasContext::BLEND] = "BLEND";
+ m_map[CanvasContext::DITHER] = "DITHER";
+ m_map[CanvasContext::STENCIL_TEST] = "STENCIL_TEST";
+ m_map[CanvasContext::DEPTH_TEST] = "DEPTH_TEST";
+ m_map[CanvasContext::SCISSOR_TEST] = "SCISSOR_TEST";
+ m_map[CanvasContext::POLYGON_OFFSET_FILL] = "POLYGON_OFFSET_FILL";
+ m_map[CanvasContext::SAMPLE_ALPHA_TO_COVERAGE] = "SAMPLE_ALPHA_TO_COVERAGE";
+ m_map[CanvasContext::SAMPLE_COVERAGE] = "SAMPLE_COVERAGE";
+
+ m_map[CanvasContext::NO_ERROR] = "NO_ERROR";
+ m_map[CanvasContext::INVALID_ENUM] = "INVALID_ENUM";
+ m_map[CanvasContext::INVALID_VALUE] = "INVALID_VALUE";
+ m_map[CanvasContext::INVALID_OPERATION] = "INVALID_OPERATION";
+ m_map[CanvasContext::OUT_OF_MEMORY] = "OUT_OF_MEMORY";
+
+ m_map[CanvasContext::CW] = "CW";
+ m_map[CanvasContext::CCW] = "CCW";
+
+ m_map[CanvasContext::LINE_WIDTH] = "LINE_WIDTH";
+ m_map[CanvasContext::ALIASED_POINT_SIZE_RANGE] = "ALIASED_POINT_SIZE_RANGE";
+ m_map[CanvasContext::ALIASED_LINE_WIDTH_RANGE] = "ALIASED_LINE_WIDTH_RANGE";
+ m_map[CanvasContext::CULL_FACE_MODE] = "CULL_FACE_MODE";
+ m_map[CanvasContext::FRONT_FACE] = "FRONT_FACE";
+ m_map[CanvasContext::DEPTH_RANGE] = "DEPTH_RANGE";
+ m_map[CanvasContext::DEPTH_WRITEMASK] = "DEPTH_WRITEMASK";
+ m_map[CanvasContext::DEPTH_CLEAR_VALUE] = "DEPTH_CLEAR_VALUE";
+ m_map[CanvasContext::DEPTH_FUNC] = "DEPTH_FUNC";
+ m_map[CanvasContext::STENCIL_CLEAR_VALUE] = "STENCIL_CLEAR_VALUE";
+ m_map[CanvasContext::STENCIL_FUNC] = "STENCIL_FUNC";
+ m_map[CanvasContext::STENCIL_FAIL] = "STENCIL_FAIL";
+ m_map[CanvasContext::STENCIL_PASS_DEPTH_FAIL] = "STENCIL_PASS_DEPTH_FAIL";
+ m_map[CanvasContext::STENCIL_PASS_DEPTH_PASS] = "STENCIL_PASS_DEPTH_PASS";
+ m_map[CanvasContext::STENCIL_REF] = "STENCIL_REF";
+ m_map[CanvasContext::STENCIL_VALUE_MASK] = "STENCIL_VALUE_MASK";
+ m_map[CanvasContext::STENCIL_WRITEMASK] = "STENCIL_WRITEMASK";
+ m_map[CanvasContext::STENCIL_BACK_FUNC] = "STENCIL_BACK_FUNC";
+ m_map[CanvasContext::STENCIL_BACK_FAIL] = "STENCIL_BACK_FAIL";
+ m_map[CanvasContext::STENCIL_BACK_PASS_DEPTH_FAIL] = "STENCIL_BACK_PASS_DEPTH_FAIL";
+ m_map[CanvasContext::STENCIL_BACK_PASS_DEPTH_PASS] = "STENCIL_BACK_PASS_DEPTH_PASS";
+ m_map[CanvasContext::STENCIL_BACK_REF] = "STENCIL_BACK_REF";
+ m_map[CanvasContext::STENCIL_BACK_VALUE_MASK] = "STENCIL_BACK_VALUE_MASK";
+ m_map[CanvasContext::STENCIL_BACK_WRITEMASK] = "STENCIL_BACK_WRITEMASK";
+ m_map[CanvasContext::VIEWPORT] = "VIEWPORT";
+ m_map[CanvasContext::SCISSOR_BOX] = "SCISSOR_BOX";
+
+ m_map[CanvasContext::COLOR_CLEAR_VALUE] = "COLOR_CLEAR_VALUE";
+ m_map[CanvasContext::COLOR_WRITEMASK] = "COLOR_WRITEMASK";
+ m_map[CanvasContext::UNPACK_ALIGNMENT] = "UNPACK_ALIGNMENT";
+ m_map[CanvasContext::PACK_ALIGNMENT] = "PACK_ALIGNMENT";
+ m_map[CanvasContext::MAX_TEXTURE_SIZE] = "MAX_TEXTURE_SIZE";
+ m_map[CanvasContext::MAX_VIEWPORT_DIMS] = "MAX_VIEWPORT_DIMS";
+ m_map[CanvasContext::SUBPIXEL_BITS] = "SUBPIXEL_BITS";
+ m_map[CanvasContext::RED_BITS] = "RED_BITS";
+ m_map[CanvasContext::GREEN_BITS] = "GREEN_BITS";
+ m_map[CanvasContext::BLUE_BITS] = "BLUE_BITS";
+ m_map[CanvasContext::ALPHA_BITS] = "ALPHA_BITS";
+ m_map[CanvasContext::DEPTH_BITS] = "DEPTH_BITS";
+ m_map[CanvasContext::STENCIL_BITS] = "STENCIL_BITS";
+ m_map[CanvasContext::POLYGON_OFFSET_UNITS] = "POLYGON_OFFSET_UNITS";
+
+ m_map[CanvasContext::POLYGON_OFFSET_FACTOR] = "POLYGON_OFFSET_FACTOR";
+ m_map[CanvasContext::TEXTURE_BINDING_2D] = "TEXTURE_BINDING_2D";
+ m_map[CanvasContext::SAMPLE_BUFFERS] = "SAMPLE_BUFFERS";
+ m_map[CanvasContext::SAMPLES] = "SAMPLES";
+ m_map[CanvasContext::SAMPLE_COVERAGE_VALUE] = "SAMPLE_COVERAGE_VALUE";
+ m_map[CanvasContext::SAMPLE_COVERAGE_INVERT] = "SAMPLE_COVERAGE_INVERT";
+
+ m_map[CanvasContext::COMPRESSED_TEXTURE_FORMATS] = "COMPRESSED_TEXTURE_FORMATS";
+
+ m_map[CanvasContext::DONT_CARE] = "DONT_CARE";
+ m_map[CanvasContext::FASTEST] = "FASTEST";
+ m_map[CanvasContext::NICEST] = "NICEST";
+
+ m_map[CanvasContext::GENERATE_MIPMAP_HINT] = "GENERATE_MIPMAP_HINT";
+
+ m_map[CanvasContext::BYTE] = "BYTE";
+ m_map[CanvasContext::UNSIGNED_BYTE] = "UNSIGNED_BYTE";
+ m_map[CanvasContext::SHORT] = "SHORT";
+ m_map[CanvasContext::UNSIGNED_SHORT] = "UNSIGNED_SHORT";
+ m_map[CanvasContext::INT] = "INT";
+ m_map[CanvasContext::UNSIGNED_INT] = "UNSIGNED_INT";
+ m_map[CanvasContext::FLOAT] = "FLOAT";
+
+ m_map[CanvasContext::DEPTH_COMPONENT] = "DEPTH_COMPONENT";
+ m_map[CanvasContext::ALPHA] = "ALPHA";
+ m_map[CanvasContext::RGB] = "RGB";
+ m_map[CanvasContext::RGBA] = "RGBA";
+ m_map[CanvasContext::LUMINANCE] = "LUMINANCE";
+ m_map[CanvasContext::LUMINANCE_ALPHA] = "LUMINANCE_ALPHA";
+
+ m_map[CanvasContext::UNSIGNED_SHORT_4_4_4_4] = "UNSIGNED_SHORT_4_4_4_4";
+ m_map[CanvasContext::UNSIGNED_SHORT_5_5_5_1] = "UNSIGNED_SHORT_5_5_5_1";
+ m_map[CanvasContext::UNSIGNED_SHORT_5_6_5] = "UNSIGNED_SHORT_5_6_5";
+
+ m_map[CanvasContext::FRAGMENT_SHADER] = "FRAGMENT_SHADER";
+ m_map[CanvasContext::VERTEX_SHADER] = "VERTEX_SHADER";
+ m_map[CanvasContext::MAX_VERTEX_ATTRIBS] = "MAX_VERTEX_ATTRIBS";
+ m_map[CanvasContext::MAX_VERTEX_UNIFORM_VECTORS] = "MAX_VERTEX_UNIFORM_VECTORS";
+ m_map[CanvasContext::MAX_VARYING_VECTORS] = "MAX_VARYING_VECTORS";
+ m_map[CanvasContext::MAX_COMBINED_TEXTURE_IMAGE_UNITS] = "MAX_COMBINED_TEXTURE_IMAGE_UNITS";
+ m_map[CanvasContext::MAX_VERTEX_TEXTURE_IMAGE_UNITS] = "MAX_VERTEX_TEXTURE_IMAGE_UNITS";
+ m_map[CanvasContext::MAX_TEXTURE_IMAGE_UNITS] = "MAX_TEXTURE_IMAGE_UNITS";
+ m_map[CanvasContext::MAX_FRAGMENT_UNIFORM_VECTORS] = "MAX_FRAGMENT_UNIFORM_VECTORS";
+ m_map[CanvasContext::SHADER_TYPE] = "SHADER_TYPE";
+ m_map[CanvasContext::DELETE_STATUS] = "DELETE_STATUS";
+ m_map[CanvasContext::LINK_STATUS] = "LINK_STATUS";
+ m_map[CanvasContext::VALIDATE_STATUS] = "VALIDATE_STATUS";
+ m_map[CanvasContext::ATTACHED_SHADERS] = "ATTACHED_SHADERS";
+ m_map[CanvasContext::ACTIVE_UNIFORMS] = "ACTIVE_UNIFORMS";
+ m_map[CanvasContext::ACTIVE_ATTRIBUTES] = "ACTIVE_ATTRIBUTES";
+ m_map[CanvasContext::SHADING_LANGUAGE_VERSION] = "SHADING_LANGUAGE_VERSION";
+ m_map[CanvasContext::CURRENT_PROGRAM] = "CURRENT_PROGRAM";
+
+ m_map[CanvasContext::NEVER] = "NEVER";
+ m_map[CanvasContext::LESS] = "LESS";
+ m_map[CanvasContext::EQUAL] = "EQUAL";
+ m_map[CanvasContext::LEQUAL] = "LEQUAL";
+ m_map[CanvasContext::GREATER] = "GREATER";
+ m_map[CanvasContext::NOTEQUAL] = "NOTEQUAL";
+ m_map[CanvasContext::GEQUAL] = "GEQUAL";
+ m_map[CanvasContext::ALWAYS] = "ALWAYS";
+
+ m_map[CanvasContext::KEEP] = "KEEP";
+ m_map[CanvasContext::REPLACE] = "REPLACE";
+ m_map[CanvasContext::INCR] = "INCR";
+ m_map[CanvasContext::DECR] = "DECR";
+ m_map[CanvasContext::INVERT] = "INVERT";
+ m_map[CanvasContext::INCR_WRAP] = "INCR_WRAP";
+ m_map[CanvasContext::DECR_WRAP] = "DECR_WRAP";
+
+ m_map[CanvasContext::VENDOR] = "VENDOR";
+ m_map[CanvasContext::RENDERER] = "RENDERER";
+ m_map[CanvasContext::VERSION] = "VERSION";
+
+ m_map[CanvasContext::NEAREST] = "NEAREST";
+ m_map[CanvasContext::LINEAR] = "LINEAR";
+
+ m_map[CanvasContext::NEAREST_MIPMAP_NEAREST] = "NEAREST_MIPMAP_NEAREST";
+ m_map[CanvasContext::LINEAR_MIPMAP_NEAREST] = "LINEAR_MIPMAP_NEAREST";
+ m_map[CanvasContext::NEAREST_MIPMAP_LINEAR] = "NEAREST_MIPMAP_LINEAR";
+ m_map[CanvasContext::LINEAR_MIPMAP_LINEAR] = "LINEAR_MIPMAP_LINEAR";
+
+ m_map[CanvasContext::TEXTURE_MAG_FILTER] = "TEXTURE_MAG_FILTER";
+ m_map[CanvasContext::TEXTURE_MIN_FILTER] = "TEXTURE_MIN_FILTER";
+ m_map[CanvasContext::TEXTURE_WRAP_S] = "TEXTURE_WRAP_S";
+ m_map[CanvasContext::TEXTURE_WRAP_T] = "TEXTURE_WRAP_T";
+
+ m_map[CanvasContext::TEXTURE_2D] = "TEXTURE_2D";
+ m_map[CanvasContext::TEXTURE] = "TEXTURE";
+
+ m_map[CanvasContext::TEXTURE_CUBE_MAP] = "TEXTURE_CUBE_MAP";
+ m_map[CanvasContext::TEXTURE_BINDING_CUBE_MAP] = "TEXTURE_BINDING_CUBE_MAP";
+ m_map[CanvasContext::TEXTURE_CUBE_MAP_POSITIVE_X] = "TEXTURE_CUBE_MAP_POSITIVE_X";
+ m_map[CanvasContext::TEXTURE_CUBE_MAP_NEGATIVE_X] = "TEXTURE_CUBE_MAP_NEGATIVE_X";
+ m_map[CanvasContext::TEXTURE_CUBE_MAP_POSITIVE_Y] = "TEXTURE_CUBE_MAP_POSITIVE_Y";
+ m_map[CanvasContext::TEXTURE_CUBE_MAP_NEGATIVE_Y] = "TEXTURE_CUBE_MAP_NEGATIVE_Y";
+ m_map[CanvasContext::TEXTURE_CUBE_MAP_POSITIVE_Z] = "TEXTURE_CUBE_MAP_POSITIVE_Z";
+ m_map[CanvasContext::TEXTURE_CUBE_MAP_NEGATIVE_Z] = "TEXTURE_CUBE_MAP_NEGATIVE_Z";
+ m_map[CanvasContext::MAX_CUBE_MAP_TEXTURE_SIZE] = "MAX_CUBE_MAP_TEXTURE_SIZE";
+
+ m_map[CanvasContext::TEXTURE0] = "TEXTURE0";
+ m_map[CanvasContext::TEXTURE1] = "TEXTURE1";
+ m_map[CanvasContext::TEXTURE2] = "TEXTURE2";
+ m_map[CanvasContext::TEXTURE3] = "TEXTURE3";
+ m_map[CanvasContext::TEXTURE4] = "TEXTURE4";
+ m_map[CanvasContext::TEXTURE5] = "TEXTURE5";
+ m_map[CanvasContext::TEXTURE6] = "TEXTURE6";
+ m_map[CanvasContext::TEXTURE7] = "TEXTURE7";
+ m_map[CanvasContext::TEXTURE8] = "TEXTURE8";
+ m_map[CanvasContext::TEXTURE9] = "TEXTURE9";
+ m_map[CanvasContext::TEXTURE10] = "TEXTURE10";
+ m_map[CanvasContext::TEXTURE11] = "TEXTURE11";
+ m_map[CanvasContext::TEXTURE12] = "TEXTURE12";
+ m_map[CanvasContext::TEXTURE13] = "TEXTURE13";
+ m_map[CanvasContext::TEXTURE14] = "TEXTURE14";
+ m_map[CanvasContext::TEXTURE15] = "TEXTURE15";
+ m_map[CanvasContext::TEXTURE16] = "TEXTURE16";
+ m_map[CanvasContext::TEXTURE17] = "TEXTURE17";
+ m_map[CanvasContext::TEXTURE18] = "TEXTURE18";
+ m_map[CanvasContext::TEXTURE19] = "TEXTURE19";
+ m_map[CanvasContext::TEXTURE20] = "TEXTURE20";
+ m_map[CanvasContext::TEXTURE21] = "TEXTURE21";
+ m_map[CanvasContext::TEXTURE22] = "TEXTURE22";
+ m_map[CanvasContext::TEXTURE23] = "TEXTURE23";
+ m_map[CanvasContext::TEXTURE24] = "TEXTURE24";
+ m_map[CanvasContext::TEXTURE25] = "TEXTURE25";
+ m_map[CanvasContext::TEXTURE26] = "TEXTURE26";
+ m_map[CanvasContext::TEXTURE27] = "TEXTURE27";
+ m_map[CanvasContext::TEXTURE28] = "TEXTURE28";
+ m_map[CanvasContext::TEXTURE29] = "TEXTURE29";
+ m_map[CanvasContext::TEXTURE30] = "TEXTURE30";
+ m_map[CanvasContext::TEXTURE31] = "TEXTURE31";
+ m_map[CanvasContext::ACTIVE_TEXTURE] = "ACTIVE_TEXTURE";
+
+ m_map[CanvasContext::REPEAT] = "REPEAT";
+ m_map[CanvasContext::CLAMP_TO_EDGE] = "CLAMP_TO_EDGE";
+ m_map[CanvasContext::MIRRORED_REPEAT] = "MIRRORED_REPEAT";
+
+ m_map[CanvasContext::FLOAT_VEC2] = "FLOAT_VEC2";
+ m_map[CanvasContext::FLOAT_VEC3] = "FLOAT_VEC3";
+ m_map[CanvasContext::FLOAT_VEC4] = "FLOAT_VEC4";
+ m_map[CanvasContext::INT_VEC2] = "INT_VEC2";
+ m_map[CanvasContext::INT_VEC3] = "INT_VEC3";
+ m_map[CanvasContext::INT_VEC4] = "INT_VEC4";
+ m_map[CanvasContext::BOOL] = "BOOL";
+ m_map[CanvasContext::BOOL_VEC2] = "BOOL_VEC2";
+ m_map[CanvasContext::BOOL_VEC3] = "BOOL_VEC3";
+ m_map[CanvasContext::BOOL_VEC4] = "BOOL_VEC4";
+ m_map[CanvasContext::FLOAT_MAT2] = "FLOAT_MAT2";
+ m_map[CanvasContext::FLOAT_MAT3] = "FLOAT_MAT3";
+ m_map[CanvasContext::FLOAT_MAT4] = "FLOAT_MAT4";
+ m_map[CanvasContext::SAMPLER_2D] = "SAMPLER_2D";
+ m_map[CanvasContext::SAMPLER_CUBE] = "SAMPLER_CUBE";
+
+ m_map[CanvasContext::VERTEX_ATTRIB_ARRAY_ENABLED] = "VERTEX_ATTRIB_ARRAY_ENABLED";
+ m_map[CanvasContext::VERTEX_ATTRIB_ARRAY_SIZE] = "VERTEX_ATTRIB_ARRAY_SIZE";
+ m_map[CanvasContext::VERTEX_ATTRIB_ARRAY_STRIDE] = "VERTEX_ATTRIB_ARRAY_STRIDE";
+ m_map[CanvasContext::VERTEX_ATTRIB_ARRAY_TYPE] = "VERTEX_ATTRIB_ARRAY_TYPE";
+ m_map[CanvasContext::VERTEX_ATTRIB_ARRAY_NORMALIZED] = "VERTEX_ATTRIB_ARRAY_NORMALIZED";
+ m_map[CanvasContext::VERTEX_ATTRIB_ARRAY_POINTER] = "VERTEX_ATTRIB_ARRAY_POINTER";
+ m_map[CanvasContext::VERTEX_ATTRIB_ARRAY_BUFFER_BINDING] = "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING";
+
+ m_map[CanvasContext::COMPILE_STATUS] = "COMPILE_STATUS";
+
+ m_map[CanvasContext::LOW_FLOAT] = "LOW_FLOAT";
+ m_map[CanvasContext::MEDIUM_FLOAT] = "MEDIUM_FLOAT";
+ m_map[CanvasContext::HIGH_FLOAT] = "HIGH_FLOAT";
+ m_map[CanvasContext::LOW_INT] = "LOW_INT";
+ m_map[CanvasContext::MEDIUM_INT] = "MEDIUM_INT";
+ m_map[CanvasContext::HIGH_INT] = "HIGH_INT";
+
+ m_map[CanvasContext::FRAMEBUFFER] = "FRAMEBUFFER";
+ m_map[CanvasContext::RENDERBUFFER] = "RENDERBUFFER";
+
+ m_map[CanvasContext::RGBA4] = "RGBA4";
+ m_map[CanvasContext::RGB5_A1] = "RGB5_A1";
+ m_map[CanvasContext::RGB565] = "RGB565";
+ m_map[CanvasContext::DEPTH_COMPONENT16] = "DEPTH_COMPONENT16";
+ m_map[CanvasContext::STENCIL_INDEX] = "STENCIL_INDEX";
+ m_map[CanvasContext::STENCIL_INDEX8] = "STENCIL_INDEX8";
+ m_map[CanvasContext::DEPTH_STENCIL] = "DEPTH_STENCIL";
+
+ m_map[CanvasContext::RENDERBUFFER_WIDTH] = "RENDERBUFFER_WIDTH";
+ m_map[CanvasContext::RENDERBUFFER_HEIGHT] = "RENDERBUFFER_HEIGHT";
+ m_map[CanvasContext::RENDERBUFFER_INTERNAL_FORMAT] = "RENDERBUFFER_INTERNAL_FORMAT";
+ m_map[CanvasContext::RENDERBUFFER_RED_SIZE] = "RENDERBUFFER_RED_SIZE";
+ m_map[CanvasContext::RENDERBUFFER_GREEN_SIZE] = "RENDERBUFFER_GREEN_SIZE";
+ m_map[CanvasContext::RENDERBUFFER_BLUE_SIZE] = "RENDERBUFFER_BLUE_SIZE";
+ m_map[CanvasContext::RENDERBUFFER_ALPHA_SIZE] = "RENDERBUFFER_ALPHA_SIZE";
+ m_map[CanvasContext::RENDERBUFFER_DEPTH_SIZE] = "RENDERBUFFER_DEPTH_SIZE";
+ m_map[CanvasContext::RENDERBUFFER_STENCIL_SIZE] = "RENDERBUFFER_STENCIL_SIZE";
+
+ m_map[CanvasContext::FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE] = "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE";
+ m_map[CanvasContext::FRAMEBUFFER_ATTACHMENT_OBJECT_NAME] = "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME";
+ m_map[CanvasContext::FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL] = "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL";
+ m_map[CanvasContext::FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE] = "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE";
+
+ m_map[CanvasContext::COLOR_ATTACHMENT0] = "COLOR_ATTACHMENT0";
+ m_map[CanvasContext::DEPTH_ATTACHMENT] = "DEPTH_ATTACHMENT";
+ m_map[CanvasContext::STENCIL_ATTACHMENT] = "STENCIL_ATTACHMENT";
+ m_map[CanvasContext::DEPTH_STENCIL_ATTACHMENT] = "DEPTH_STENCIL_ATTACHMENT";
+
+ m_map[CanvasContext::FRAMEBUFFER_COMPLETE] = "FRAMEBUFFER_COMPLETE";
+ m_map[CanvasContext::FRAMEBUFFER_INCOMPLETE_ATTACHMENT] = "FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
+ m_map[CanvasContext::FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT] = "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT";
+ m_map[CanvasContext::FRAMEBUFFER_INCOMPLETE_DIMENSIONS] = "FRAMEBUFFER_INCOMPLETE_DIMENSIONS";
+ m_map[CanvasContext::FRAMEBUFFER_UNSUPPORTED] = "FRAMEBUFFER_UNSUPPORTED";
+
+ m_map[CanvasContext::FRAMEBUFFER_BINDING] = "FRAMEBUFFER_BINDING";
+ m_map[CanvasContext::RENDERBUFFER_BINDING] = "RENDERBUFFER_BINDING";
+ m_map[CanvasContext::MAX_RENDERBUFFER_SIZE] = "MAX_RENDERBUFFER_SIZE";
+
+ m_map[CanvasContext::INVALID_FRAMEBUFFER_OPERATION] = "INVALID_FRAMEBUFFER_OPERATION";
+
+ m_map[CanvasContext::UNPACK_FLIP_Y_WEBGL] = "UNPACK_FLIP_Y_WEBGL";
+ m_map[CanvasContext::UNPACK_PREMULTIPLY_ALPHA_WEBGL] = "UNPACK_PREMULTIPLY_ALPHA_WEBGL";
+ m_map[CanvasContext::CONTEXT_LOST_WEBGL] = "CONTEXT_LOST_WEBGL";
+ m_map[CanvasContext::UNPACK_COLORSPACE_CONVERSION_WEBGL] = "UNPACK_COLORSPACE_CONVERSION_WEBGL";
+ m_map[CanvasContext::BROWSER_DEFAULT_WEBGL] = "BROWSER_DEFAULT_WEBGL";
+}
+
+QString EnumToStringMap::lookUp(const CanvasContext::glEnums value) const
+{
+ if (m_map.contains(value))
+ return m_map[value];
+
+ return QString("0x0%1").arg(value, 0, 16);
+}
+
+QString EnumToStringMap::lookUp(const GLuint value) const
+{
+ return lookUp((CanvasContext::glEnums)value);
+}
+
diff --git a/src/enumtostringmap_p.h b/src/enumtostringmap_p.h
new file mode 100644
index 0000000..107a9b9
--- /dev/null
+++ b/src/enumtostringmap_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef ENUMTOSTRINGMAP_P_H
+#define ENUMTOSTRINGMAP_P_H
+
+#include "context3d_p.h"
+
+#include <QMap>
+
+class EnumToStringMap
+{
+public:
+ static EnumToStringMap *newInstance();
+ static void deleteInstance();
+ QString lookUp(const CanvasContext::glEnums value) const;
+ QString lookUp(const GLuint value) const;
+
+private:
+ EnumToStringMap();
+ QMap<CanvasContext::glEnums, QString> m_map;
+ QString m_unknown;
+};
+
+#endif // ENUMTOSTRINGMAP_P_H
diff --git a/src/float32array.cpp b/src/float32array.cpp
new file mode 100644
index 0000000..314ed66
--- /dev/null
+++ b/src/float32array.cpp
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "float32array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Float32Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of floats.
+ *
+ * An uncreatable QML type that contains a typed array of floats.
+ * Use \l Arrays::newFloat32Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasFloat32Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasFloat32Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasFloat32Array::CanvasFloat32Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Float32Array(QObject *parent)";
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat32Array::CanvasFloat32Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ setLength(length);
+ //qDebug() << "Float32Array(unsigned long length, QObject *parent)";
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * sizeof(float));
+ m_typedBuffer = (float *)m_buffer->m_rawData;
+ for (unsigned long i = 0; i < length; i++)
+ m_typedBuffer[i] = 0.0;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat32Array::CanvasFloat32Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * bytesPerElement());
+ m_typedBuffer = (float *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<float>(m_typedBuffer, array, CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ m_buffer = 0;
+ m_typedBuffer = 0;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat32Array::CanvasFloat32Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Float32Array(QVariantList *array[" << array->count() << "], parent:"<< parent <<")";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(sizeof(float) * length(), this);
+ m_typedBuffer = (float *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<float>()) {
+ m_typedBuffer[idx] = element.toFloat();
+ } else {
+ //qDebug() << "Failed conversion to float of "<<element;
+ m_typedBuffer[idx] = 0.f;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat32Array::CanvasFloat32Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Float32Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (float *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod float Float32Array::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+float CanvasFloat32Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return 0.0;
+}
+
+/*!
+ * \qmlmethod float Float32Array::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+float CanvasFloat32Array::get(unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return 0.0;
+}
+
+/*!
+ * \qmlmethod void Float32Array::set(int index, float value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasFloat32Array::set(unsigned long index, float value)
+{
+ if (index < length()) {
+ m_typedBuffer[index] = value;
+ return;
+ }
+ qDebug() << "Float32Array " << this << "invalid index " << index;
+}
+
+/*!
+ * \qmlmethod void Float32Array::set(TypedArray array, int offset)
+ * Copies the \a array to \a offset.
+ */
+/*!
+ * \internal
+ */
+void CanvasFloat32Array::set(CanvasTypedArray *array, unsigned long offset)
+{
+ delete m_buffer;
+
+ qDebug() << "Float32Array::set( TypedArray" << array << ")";
+
+ setLength(array->length() - offset);
+ m_buffer = new CanvasArrayBuffer( (length() - offset) * bytesPerElement());
+ m_typedBuffer = (float *)m_buffer->m_rawData;
+
+ // TODO: ADD OFFSET AS PARAMETER TO COPY TARGET!!!!
+ if (!ArrayUtils::copyToTarget<float>(m_typedBuffer, array, length() - offset)) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ m_buffer = 0;
+ m_typedBuffer = 0;
+ setLength(0);
+ }
+}
+
+/*!
+ * \qmlmethod void Float32Array::set(list<variant> array, int offset)
+ * Copies the \a array to \a offset.
+ */
+/*!
+ * \internal
+ */
+void CanvasFloat32Array::set(QVariantList array, unsigned long offset)
+{
+ delete m_buffer;
+
+ qDebug() << "Float32Array::set( QVariantList" << array << ")";
+
+ setLength(array.count());
+ qDebug() << "Float32Array::set(" << array << ")";
+ m_buffer = new CanvasArrayBuffer( (length() - offset) * bytesPerElement());
+ m_typedBuffer = (float *)m_buffer->m_rawData;
+
+ ArrayUtils::fillFloatArrayFromVariantList(array, m_typedBuffer);
+}
+
+
+/*
+void Float32Array::set(float *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Float32Array::subarray(long begin)
+{
+
+}
+
+TypedArray *Float32Array::subarray(long begin, long end)
+{
+
+}
+*/
+
+QDebug operator<<(QDebug dbg, const CanvasFloat32Array *array)
+{
+ if (array)
+ dbg.nospace() << "Float32Array ("<< array->m_name <<", length:" << array->length() << ")";
+ else
+ dbg.nospace() << "Float32Array (null)";
+ return dbg.maybeSpace();
+}
diff --git a/src/float32array_p.h b/src/float32array_p.h
new file mode 100644
index 0000000..d972a31
--- /dev/null
+++ b/src/float32array_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef FLOAT32ARRAY_P_H
+#define FLOAT32ARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasFloat32Array : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasFloat32Array(QObject *parent = 0);
+ explicit CanvasFloat32Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasFloat32Array(CanvasTypedArray *array, QObject *parent = 0);
+ explicit CanvasFloat32Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasFloat32Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ virtual inline int bytesPerElement() { return sizeof(float); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::FLOAT; }
+
+ Q_INVOKABLE float operator [] (unsigned long index);
+ Q_INVOKABLE float get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, float value);
+ Q_INVOKABLE void set(QVariantList array, unsigned long offset = 0);
+ Q_INVOKABLE void set(CanvasTypedArray *array, unsigned long offset = 0);
+ //Q_INVOKABLE void set(float *array, unsigned long offset);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin, long end);
+ friend QDebug operator<< (QDebug dbg, const CanvasFloat32Array *array);
+
+private:
+ float *m_typedBuffer;
+};
+
+#endif // FLOAT32ARRAY_P_H
diff --git a/src/float64array.cpp b/src/float64array.cpp
new file mode 100644
index 0000000..8ee7b1b
--- /dev/null
+++ b/src/float64array.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "float64array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Float64Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of doubles.
+ *
+ * An uncreatable QML type that contains a typed array of doubles.
+ * Use \l Arrays::newFloat64Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasFloat64Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasFloat64Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasFloat64Array::CanvasFloat64Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ setLength(0);
+ //qDebug() << "Float64Array(QObject *parent)";
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat64Array::CanvasFloat64Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Float64Array(unsigned long length, QObject *parent)";
+ setLength(length);
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(double) * length);
+ m_typedBuffer = (double *)m_buffer->m_rawData;
+ for (unsigned long i = 0; i < length; i++) {
+ m_typedBuffer[i] = 0.0;
+ }
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat64Array::CanvasFloat64Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (double *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<double>(m_typedBuffer, array, array->length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat64Array::CanvasFloat64Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Float64Array(QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(sizeof(double) * array->count(), this);
+ m_typedBuffer = (double *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<double>()) {
+ m_typedBuffer[idx] = element.toDouble();
+ } else {
+ //qDebug() << "Failed conversion to double of "<<element;
+ m_typedBuffer[idx] = 0.f;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasFloat64Array::CanvasFloat64Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Float64Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (double *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod double Float64Array::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+double CanvasFloat64Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return 0.0;
+}
+
+/*!
+ * \qmlmethod double Float64Array::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+double CanvasFloat64Array::get(unsigned long index)
+{
+ return m_typedBuffer[index];
+}
+
+/*!
+ * \qmlmethod void Float64Array::set(int index, double value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasFloat64Array::set(unsigned long index, double value)
+{
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Float64Array::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Float64Array::set(double *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Float64Array::subarray(long begin)
+{
+
+}
+
+TypedArray *Float64Array::subarray(long begin, long end)
+{
+
+}
+*/
+
diff --git a/src/float64array_p.h b/src/float64array_p.h
new file mode 100644
index 0000000..b00c150
--- /dev/null
+++ b/src/float64array_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef FLOAT64ARRAY_P_H
+#define FLOAT64ARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasFloat64Array : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasFloat64Array(QObject *parent = 0);
+ explicit CanvasFloat64Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasFloat64Array(CanvasTypedArray *array, QObject *parent = 0);
+ explicit CanvasFloat64Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasFloat64Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ virtual inline int bytesPerElement() { return sizeof(double); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::NONE; }
+
+ Q_INVOKABLE double operator [] (unsigned long index);
+ Q_INVOKABLE double get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, double value);
+ //Q_INVOKABLE void set(ArrayBufferView *array, unsigned long offset);
+ //Q_INVOKABLE void set(double *array, unsigned long offset);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin, long end);
+
+private:
+ double *m_typedBuffer;
+};
+
+#endif // FLOAT64ARRAY_P_H
diff --git a/src/framebuffer3d.cpp b/src/framebuffer3d.cpp
new file mode 100644
index 0000000..50dee95
--- /dev/null
+++ b/src/framebuffer3d.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "framebuffer3d_p.h"
+
+/*!
+ * \qmltype FrameBuffer3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains an OpenGL framebuffer.
+ *
+ * An uncreatable QML type that contains an OpenGL framebuffer object. You can get it by calling
+ * \l{Context3D::createFramebuffer()}{Context3D.createFramebuffer()} method.
+ */
+
+/*!
+ * \internal
+ */
+CanvasFrameBuffer::CanvasFrameBuffer(QObject *parent) :
+ CanvasAbstractObject(parent),
+ m_framebufferId(0)
+{
+ initializeOpenGLFunctions();
+ glGenFramebuffers(1, &m_framebufferId);
+}
+
+/*!
+ * \internal
+ */
+CanvasFrameBuffer::~CanvasFrameBuffer()
+{
+ del();
+}
+
+/*!
+ * \internal
+ */
+bool CanvasFrameBuffer::isAlive()
+{
+ return (m_framebufferId);
+}
+
+/*!
+ * \internal
+ */
+void CanvasFrameBuffer::del()
+{
+ if (m_framebufferId) {
+ glDeleteFramebuffers(1, &m_framebufferId);
+ m_framebufferId = 0;
+ }
+}
+
+/*!
+ * \internal
+ */
+GLuint CanvasFrameBuffer::id()
+{
+ return m_framebufferId;
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasFrameBuffer *buffer)
+{
+ if (buffer)
+ dbg.nospace() << "FrameBuffer3D("<< buffer->m_name <<", id:" << buffer->m_framebufferId << ")";
+ else
+ dbg.nospace() << "FrameBuffer3D("<< ((void*) buffer) <<")";
+ return dbg.maybeSpace();
+}
diff --git a/src/framebuffer3d_p.h b/src/framebuffer3d_p.h
new file mode 100644
index 0000000..2042338
--- /dev/null
+++ b/src/framebuffer3d_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef FRAMEBUFFER3D_P_H
+#define FRAMEBUFFER3D_P_H
+
+#include "abstractobject3d_p.h"
+
+#include <QOpenGLFunctions>
+#include <QDebug>
+
+class CanvasFrameBuffer : public CanvasAbstractObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasFrameBuffer(QObject *parent = 0);
+ virtual ~CanvasFrameBuffer();
+
+ bool isAlive();
+ void del();
+ GLuint id();
+
+ friend QDebug operator<< (QDebug d, const CanvasFrameBuffer *fb);
+
+private:
+ GLuint m_framebufferId;
+};
+
+#endif // FRAMEBUFFER3D_P_H
diff --git a/src/int16array.cpp b/src/int16array.cpp
new file mode 100644
index 0000000..9d76c40
--- /dev/null
+++ b/src/int16array.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "int16array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Int16Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of 16 bit ints.
+ *
+ * An uncreatable QML type that contains a typed array of 16 bit ints.
+ * Use \l Arrays::newInt16Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasInt16Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasInt16Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasInt16Array::CanvasInt16Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Int16Array(QObject *parent)";
+ setLength(0);
+}
+
+/*!
+ * \internal
+ */
+CanvasInt16Array::CanvasInt16Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Int16Array(unsigned long length, QObject *parent)";
+ setLength(length);
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(float) * CanvasTypedArray::length());
+ m_typedBuffer = (short *)m_buffer->m_rawData;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt16Array::CanvasInt16Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (short *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<short>(m_typedBuffer, array, CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt16Array::CanvasInt16Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Int16Array(const QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(sizeof(short) * CanvasTypedArray::length(), this);
+ m_typedBuffer = (short *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<short>()) {
+ m_typedBuffer[idx] = (short)(element.toInt());
+ } else {
+ //qDebug() << "Failed conversion to unsigned byte of "<<element;
+ m_typedBuffer[idx] = (short)0;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt16Array::CanvasInt16Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Int16Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (short *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod int Int16Array::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+short CanvasInt16Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return short(0);
+}
+
+
+/*!
+ * \qmlmethod int Int16Array::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+short CanvasInt16Array::get(unsigned long index)
+{
+ return m_typedBuffer[index];
+}
+
+/*!
+ * \qmlmethod void Int16Array::set(int index, int value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasInt16Array::set(unsigned long index, short value)
+{
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Int16Array::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Int16Array::set(float *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Int16Array::subarray(long begin)
+{
+
+}
+
+TypedArray *Int16Array::subarray(long begin, long end)
+{
+
+}
+*/
diff --git a/src/int16array_p.h b/src/int16array_p.h
new file mode 100644
index 0000000..077b6ac
--- /dev/null
+++ b/src/int16array_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef INT16ARRAY_P_H
+#define INT16ARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasInt16Array : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasInt16Array(QObject *parent = 0);
+ explicit CanvasInt16Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasInt16Array(CanvasTypedArray *array, QObject *parent);
+ explicit CanvasInt16Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasInt16Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ Q_INVOKABLE short operator [] (unsigned long index);
+ Q_INVOKABLE short get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, short value);
+ virtual inline int bytesPerElement() { return sizeof(short); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::SHORT; }
+
+ //Q_INVOKABLE void set(ArrayBufferView *array, unsigned long offset);
+ //Q_INVOKABLE void set(short *array, unsigned long offset);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin, long end);
+
+private:
+ short *m_typedBuffer;
+};
+
+#endif // INT16ARRAY_P_H
diff --git a/src/int32array.cpp b/src/int32array.cpp
new file mode 100644
index 0000000..da17cb3
--- /dev/null
+++ b/src/int32array.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "int32array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Int32Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of ints.
+ *
+ * An uncreatable QML type that contains a typed array of ints.
+ * Use \l Arrays::newInt32Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasInt32Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasInt32Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasInt32Array::CanvasInt32Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Int32Array(QObject *parent)";
+ setLength(0);
+}
+
+/*!
+ * \internal
+ */
+CanvasInt32Array::CanvasInt32Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Int32Array(unsigned long length, QObject *parent)";
+ setLength(length);
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(float) * CanvasTypedArray::length());
+ m_typedBuffer = (int *)m_buffer->m_rawData;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt32Array::CanvasInt32Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (int *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<int>(m_typedBuffer, array, CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt32Array::CanvasInt32Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Int32Array(const QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(sizeof(int) * CanvasTypedArray::length(), this);
+ m_typedBuffer = (int *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<int>()) {
+ m_typedBuffer[idx] = (int)(element.toInt());
+ } else {
+ //qDebug() << "Failed conversion to unsigned byte of "<<element;
+ m_typedBuffer[idx] = (int)0;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt32Array::CanvasInt32Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Int32Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (int *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod int Int32Array::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+int CanvasInt32Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return 0;
+}
+
+/*!
+ * \qmlmethod int Int32Array::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+int CanvasInt32Array::get(unsigned long index)
+{
+ return m_typedBuffer[index];
+}
+
+/*!
+ * \qmlmethod void Int32Array::set(int index, int value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasInt32Array::set(unsigned long index, int value)
+{
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Int32Array::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Int32Array::set(float *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Int32Array::subarray(long begin)
+{
+
+}
+
+TypedArray *Int32Array::subarray(long begin, long end)
+{
+
+}
+*/
+
diff --git a/src/int32array_p.h b/src/int32array_p.h
new file mode 100644
index 0000000..fd5b1ee
--- /dev/null
+++ b/src/int32array_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef INT32ARRAY_P_H
+#define INT32ARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasInt32Array : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasInt32Array(QObject *parent = 0);
+ explicit CanvasInt32Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasInt32Array(CanvasTypedArray *array, QObject *parent);
+ explicit CanvasInt32Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasInt32Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ Q_INVOKABLE int operator [] (unsigned long index);
+ Q_INVOKABLE int get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, int value);
+ virtual inline int bytesPerElement() { return sizeof(int); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::INT; }
+
+ //Q_INVOKABLE void set(TypedArray *array, unsigned long offset);
+ //Q_INVOKABLE void set(int *array, unsigned long offset);
+ //Q_INVOKABLE TypedArray *subarray(long begin);
+ //Q_INVOKABLE TypedArray *subarray(long begin, long end);
+
+private:
+ int *m_typedBuffer;
+};
+
+#endif // INT32ARRAY_P_H
diff --git a/src/int8array.cpp b/src/int8array.cpp
new file mode 100644
index 0000000..bbe5d87
--- /dev/null
+++ b/src/int8array.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "int8array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Int8Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of 8 bit ints.
+ *
+ * An uncreatable QML type that contains a typed array of 8 bit ints.
+ * Use \l Arrays::newInt8Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasInt8Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasInt8Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasInt8Array::CanvasInt8Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Int8Array(QObject *parent)";
+ setLength(0);
+}
+
+/*!
+ * \internal
+ */
+CanvasInt8Array::CanvasInt8Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Int8Array(unsigned long length, QObject *parent)";
+ setLength(length);
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(signed char) * CanvasTypedArray::length());
+ m_typedBuffer = (signed char *)m_buffer->m_rawData;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt8Array::CanvasInt8Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (signed char *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<signed char>(m_typedBuffer, array, CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt8Array::CanvasInt8Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Int8Array(const QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * sizeof(signed char), this);
+ m_typedBuffer = (signed char *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<signed char>()) {
+ m_typedBuffer[idx] = (signed char)(element.toInt());
+ } else {
+ //qDebug() << "Failed conversion to unsigned byte of "<<element;
+ m_typedBuffer[idx] = (signed char)0;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasInt8Array::CanvasInt8Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Int8Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (signed char *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod int Int8Array::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+signed char CanvasInt8Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return char(0);
+}
+
+/*!
+ * \qmlmethod int Int8Array::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+signed char CanvasInt8Array::get(unsigned long index)
+{
+ return m_typedBuffer[index];
+}
+
+/*!
+ * \qmlmethod void Int8Array::set(int index, int value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasInt8Array::set(unsigned long index, signed char value)
+{
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Int8Array::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Int8Array::set(float *array, unsigned long offset)
+{
+
+}
+
+Int8Array *Int8Array::subarray(long begin)
+{
+
+}
+
+Int8Array *Int8Array::subarray(long begin, long end)
+{
+
+}
+*/
diff --git a/src/int8array_p.h b/src/int8array_p.h
new file mode 100644
index 0000000..7d353ed
--- /dev/null
+++ b/src/int8array_p.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef INT8ARRAY_P_H
+#define INT8ARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasInt8Array : public CanvasTypedArray
+{
+ Q_OBJECT
+public:
+ explicit CanvasInt8Array(QObject *parent = 0);
+ explicit CanvasInt8Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasInt8Array(CanvasTypedArray *array, QObject *parent = 0);
+ explicit CanvasInt8Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasInt8Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ Q_INVOKABLE signed char operator [] (unsigned long index);
+ Q_INVOKABLE signed char get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, signed char value);
+ virtual inline int bytesPerElement() { return sizeof(signed char); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::BYTE; }
+
+ //Q_INVOKABLE void set(TypedArray *array, unsigned long offset);
+ //Q_INVOKABLE void set(signed char *array, unsigned long offset);
+ //Q_INVOKABLE TypedArray *subarray(long begin);
+ //Q_INVOKABLE TypedArray *subarray(long begin, long end);
+
+private:
+ signed char *m_typedBuffer;
+};
+
+#endif // INT8ARRAY_P_H
diff --git a/src/program3d.cpp b/src/program3d.cpp
new file mode 100644
index 0000000..eb5e369
--- /dev/null
+++ b/src/program3d.cpp
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "program3d_p.h"
+
+/*!
+ * \qmltype Program3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a shader program.
+ *
+ * An uncreatable QML type that contains a compiled shader program. You can get it by calling
+ * \l{Context3D::createProgram()}{Context3D.createProgram()} method.
+ */
+
+/*!
+ * \internal
+ */
+CanvasProgram::CanvasProgram(QObject *parent) :
+ CanvasAbstractObject(parent),
+ m_program(new QOpenGLShaderProgram(this))
+{
+ initializeOpenGLFunctions();
+}
+
+/*!
+ * \internal
+ */
+CanvasProgram::~CanvasProgram()
+{
+ delete m_program;
+}
+
+/*!
+ * \internal
+ */
+int CanvasProgram::uniformLocation(const QString &name)
+{
+ if (!m_program)
+ return -1;
+
+ return m_program->uniformLocation(name);
+}
+
+/*!
+ * \internal
+ */
+bool CanvasProgram::isAlive()
+{
+ return bool(m_program);
+}
+
+/*!
+ * \internal
+ */
+QOpenGLShaderProgram *CanvasProgram::qOGLProgram()
+{
+ return m_program;
+}
+
+/*!
+ * \internal
+ */
+void CanvasProgram::del()
+{
+ delete m_program;
+ m_program = 0;
+}
+
+/*!
+ * \internal
+ */
+void CanvasProgram::validateProgram()
+{
+ if (m_program)
+ return;
+ glValidateProgram(m_program->programId());
+}
+
+/*!
+ * \qmlproperty int Program3D::id()
+ * Holds the shader program id. Returns \c -1 if there is none.
+ */
+/*!
+ * \internal
+ */
+int CanvasProgram::id()
+{
+ if (!m_program)
+ return -1;
+
+ return m_program->programId();
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasProgram *program)
+{
+ if (program)
+ dbg.nospace() << "Program3D("<< program->m_name << ", id:" << program->m_program->programId() << ")";
+ else
+ dbg.nospace() << "Program3D("<< ((void*) program) <<")";
+ return dbg.maybeSpace();
+}
+
diff --git a/src/program3d_p.h b/src/program3d_p.h
new file mode 100644
index 0000000..e730df4
--- /dev/null
+++ b/src/program3d_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef PROGRAM3D_P_H
+#define PROGRAM3D_P_H
+
+#include "context3d_p.h"
+#include "abstractobject3d_p.h"
+
+#include <QtGui/QOpenGLFunctions>
+#include <QtGui/QOpenGLShaderProgram>
+#include <QDebug>
+
+class CanvasProgram : public CanvasAbstractObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+ Q_PROPERTY(int id READ id NOTIFY idChanged)
+
+public:
+ explicit CanvasProgram(QObject *parent = 0);
+ virtual ~CanvasProgram();
+
+ int uniformLocation(const QString &name);
+ void del();
+ bool isAlive();
+ void validateProgram();
+ QOpenGLShaderProgram *qOGLProgram();
+ int id();
+
+ friend QDebug operator<< (QDebug d, const CanvasProgram *program);
+
+private:
+ QOpenGLShaderProgram *m_program;
+
+signals:
+ void idChanged(int id);
+};
+
+#endif // PROGRAM3D_P_H
diff --git a/src/qcanvas3d_plugin.cpp b/src/qcanvas3d_plugin.cpp
new file mode 100644
index 0000000..c5ece02
--- /dev/null
+++ b/src/qcanvas3d_plugin.cpp
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcanvas3d_plugin.h"
+
+#include <QtQml/qqml.h>
+
+void QtCanvas3DPlugin::registerTypes(const char *uri)
+{
+ // @uri com.digia.qtcanvas3d
+ qmlRegisterSingletonType<CanvasTypedArrayFactory>(uri,
+ 1, 0,
+ "Arrays",
+ CanvasTypedArrayFactory::type_array_factory_provider);
+
+ qmlRegisterType<CanvasTextureImageLoader>(uri,
+ 1, 0,
+ "TextureImageLoader");
+ qmlRegisterType<CanvasTextureImage>(uri,
+ 1, 0,
+ "TextureImage");
+ qmlRegisterType<Canvas>(uri,
+ 1, 0,
+ "Canvas3D");
+ qmlRegisterType<CanvasContextAttributes>(uri,
+ 1, 0,
+ "ContextAttributes");
+
+ qmlRegisterUncreatableType<CanvasArrayBuffer>(uri,
+ 1, 0,
+ "ArrayBuffer",
+ QLatin1String("Trying to create uncreatable: ArrayBuffer."));
+ qmlRegisterUncreatableType<CanvasInt8Array>(uri,
+ 1, 0,
+ "Int8Array",
+ QLatin1String("Trying to create uncreatable: Int8Array, use Arrays.newInt8Array() instead."));
+ qmlRegisterUncreatableType<CanvasUint8Array>(uri,
+ 1, 0,
+ "Uint8Array",
+ QLatin1String("Trying to create uncreatable: Uint8Array, use Arrays.newUint8Array() instead."));
+ qmlRegisterUncreatableType<CanvasUint8ClampedArray>(uri,
+ 1, 0,
+ "Uint8ClampedArray",
+ QLatin1String("Trying to create uncreatable: Uint8ClampedArray, use Arrays.newUint8ClampedArray() instead."));
+ qmlRegisterUncreatableType<CanvasInt16Array>(uri,
+ 1, 0,
+ "Int16Array",
+ QLatin1String("Trying to create uncreatable: Int16Array, use Arrays.newInt16Array() instead."));
+ qmlRegisterUncreatableType<CanvasUint16Array>(uri,
+ 1, 0,
+ "Uint16Array",
+ QLatin1String("Trying to create uncreatable: Uint16Array, use Arrays.newUint16Array() instead."));
+ qmlRegisterUncreatableType<CanvasInt32Array>(uri,
+ 1, 0,
+ "Int32Array",
+ QLatin1String("Trying to create uncreatable: Int32Array, use Arrays.newInt32Array() instead."));
+ qmlRegisterUncreatableType<CanvasUint32Array>(uri,
+ 1, 0,
+ "Uint32Array",
+ QLatin1String("Trying to create uncreatable: Uint32Array, use Arrays.newUint32Array() instead."));
+ qmlRegisterUncreatableType<CanvasFloat32Array>(uri,
+ 1, 0,
+ "Float32Array",
+ QLatin1String("Trying to create uncreatable: Float32Array, use Arrays.newFloat32Array() instead."));
+ qmlRegisterUncreatableType<CanvasFloat64Array>(uri,
+ 1, 0,
+ "Float64Array",
+ QLatin1String("Trying to create uncreatable: Float64Array, use Arrays.newFloat64Array() instead."));
+ qmlRegisterUncreatableType<CanvasShaderPrecisionFormat>(uri,
+ 1, 0,
+ "ShaderPrecisionFormat",
+ QLatin1String("Trying to create uncreatable: ShaderPrecisionFormat."));
+ qmlRegisterUncreatableType<CanvasTypedArray>(uri,
+ 1, 0,
+ "TypedArray",
+ QLatin1String("Trying to create uncreatable: TypedArray."));
+ qmlRegisterUncreatableType<CanvasArrayBufferView>(uri,
+ 1, 0,
+ "ArrayBufferView",
+ QLatin1String("Trying to create uncreatable: ArrayBufferView."));
+ qmlRegisterUncreatableType<CanvasContext>(uri,
+ 1, 0,
+ "Context3D",
+ QLatin1String("Trying to create uncreatable: Context3D, use Canvas3D.getContext() instead."));
+ qmlRegisterUncreatableType<CanvasTexture>(uri,
+ 1, 0,
+ "Texture3D",
+ QLatin1String("Trying to create uncreatable: Texture3D, use Context3D.createTexture() instead."));
+ qmlRegisterUncreatableType<CanvasShader>(uri,
+ 1, 0,
+ "Shader3D",
+ QLatin1String("Trying to create uncreatable: Shader3D, use Context3D.createShader() instead."));
+ qmlRegisterUncreatableType<CanvasFrameBuffer>(uri,
+ 1, 0,
+ "FrameBuffer3D",
+ QLatin1String("Trying to create uncreatable: FrameBuffer3D, use Context3D.createFramebuffer() instead."));
+ qmlRegisterUncreatableType<CanvasRenderBuffer>(uri,
+ 1, 0,
+ "RenderBuffer3D",
+ QLatin1String("Trying to create uncreatable: RenderBuffer3D, use Context3D.createRenderbuffer() instead."));
+ qmlRegisterUncreatableType<CanvasProgram>(uri,
+ 1, 0,
+ "Program3D",
+ QLatin1String("Trying to create uncreatable: Program3D, use Context3D.createProgram() instead."));
+ qmlRegisterUncreatableType<CanvasBuffer>(uri,
+ 1, 0,
+ "Buffer3D",
+ QLatin1String("Trying to create uncreatable: Buffer3D, use Context3D.createBuffer() instead."));
+ qmlRegisterUncreatableType<CanvasUniformLocation>(uri,
+ 1, 0,
+ "UniformLocation",
+ QLatin1String("Trying to create uncreatable: UniformLocation, use Context3D.getUniformLocation() instead."));
+}
+
+
diff --git a/src/qcanvas3d_plugin.h b/src/qcanvas3d_plugin.h
new file mode 100644
index 0000000..d1ad566
--- /dev/null
+++ b/src/qcanvas3d_plugin.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCANVAS3D_PLUGIN_H
+#define QCANVAS3D_PLUGIN_H
+
+#include "canvas3d_p.h"
+#include "texture3d_p.h"
+#include "shader3d_p.h"
+#include "context3d_p.h"
+#include "program3d_p.h"
+#include "buffer3d_p.h"
+#include "uniformlocation_p.h"
+#include "teximage3d_p.h"
+#include "typedarrayfactory_p.h"
+#include "typedarray_p.h"
+#include "arraybuffer_p.h"
+#include "arraybufferview_p.h"
+#include "int8array_p.h"
+#include "uint8array_p.h"
+#include "int16array_p.h"
+#include "uint16array_p.h"
+#include "int32array_p.h"
+#include "uint32array_p.h"
+#include "float32array_p.h"
+#include "float64array_p.h"
+#include "uint8clampedarray_p.h"
+#include "contextattributes_p.h"
+#include "framebuffer3d_p.h"
+#include "renderbuffer3d_p.h"
+#include "shaderprecisionformat_p.h"
+#include "teximage3dloader_p.h"
+
+#include <QQmlExtensionPlugin>
+
+QML_DECLARE_TYPE(Canvas)
+//QML_DECLARE_TYPE(QFBOCanvas3D)
+QML_DECLARE_TYPE(CanvasContext)
+QML_DECLARE_TYPE(CanvasTexture)
+QML_DECLARE_TYPE(CanvasShader)
+QML_DECLARE_TYPE(CanvasProgram)
+QML_DECLARE_TYPE(CanvasBuffer)
+QML_DECLARE_TYPE(CanvasUniformLocation)
+QML_DECLARE_TYPE(CanvasFloat32Array)
+QML_DECLARE_TYPE(CanvasFloat64Array)
+QML_DECLARE_TYPE(CanvasInt8Array)
+QML_DECLARE_TYPE(CanvasUint8Array)
+QML_DECLARE_TYPE(CanvasUint8ClampedArray)
+QML_DECLARE_TYPE(CanvasInt16Array)
+QML_DECLARE_TYPE(CanvasUint16Array)
+QML_DECLARE_TYPE(CanvasInt32Array)
+QML_DECLARE_TYPE(CanvasUint32Array)
+QML_DECLARE_TYPE(CanvasArrayBufferView)
+QML_DECLARE_TYPE(CanvasArrayBuffer)
+QML_DECLARE_TYPE(CanvasTypedArrayFactory)
+QML_DECLARE_TYPE(CanvasTextureImage)
+QML_DECLARE_TYPE(CanvasTypedArray)
+QML_DECLARE_TYPE(CanvasContextAttributes)
+QML_DECLARE_TYPE(CanvasFrameBuffer)
+QML_DECLARE_TYPE(CanvasRenderBuffer)
+QML_DECLARE_TYPE(CanvasShaderPrecisionFormat)
+QML_DECLARE_TYPE(CanvasTextureImageLoader)
+
+class QtCanvas3DPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
+
+public:
+ void registerTypes(const char *uri);
+};
+
+#endif // QCANVAS3D_PLUGIN_H
+
diff --git a/src/qmldir b/src/qmldir
new file mode 100644
index 0000000..e1a56d6
--- /dev/null
+++ b/src/qmldir
@@ -0,0 +1,6 @@
+module QtCanvas3D
+
+plugin declarative_qtcanvas3d
+classname QtCanvas3DPlugin
+typeinfo qtcanvas3d.qmltypes
+
diff --git a/src/qtcanvas3d.qmltypes b/src/qtcanvas3d.qmltypes
new file mode 100644
index 0000000..1e77951
--- /dev/null
+++ b/src/qtcanvas3d.qmltypes
@@ -0,0 +1,2105 @@
+import QtQuick.tooling 1.1
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump QtCanvas3D 1.0 src'
+
+Module {
+ Component {
+ name: "ArrayBuffer"
+ prototype: "QObject"
+ exports: ["QArrayBuffer 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "byteLength"; type: "ulong"; isReadonly: true }
+ Signal {
+ name: "byteLengthChanged"
+ Parameter { name: "byteLength"; type: "ulong" }
+ }
+ Method { name: "byteLength"; type: "ulong" }
+ Method {
+ name: "slice"
+ type: "ArrayBuffer*"
+ Parameter { name: "begin"; type: "long" }
+ }
+ Method {
+ name: "slice"
+ type: "ArrayBuffer*"
+ Parameter { name: "begin"; type: "long" }
+ Parameter { name: "end"; type: "long" }
+ }
+ Method {
+ name: "isView"
+ type: "bool"
+ Parameter { name: "value"; type: "QObject" }
+ }
+ }
+ Component {
+ name: "ArrayBufferView"
+ prototype: "QAbstractObject3D"
+ exports: ["QArrayBufferView 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "buffer"; type: "ArrayBuffer"; isReadonly: true; isPointer: true }
+ Property { name: "byteOffset"; type: "ulong"; isReadonly: true }
+ Property { name: "byteLength"; type: "ulong"; isReadonly: true }
+ Signal {
+ name: "bufferChanged"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ }
+ Signal {
+ name: "byteOffsetChanged"
+ Parameter { name: "byteLength"; type: "ulong" }
+ }
+ Signal {
+ name: "byteLengthChanged"
+ Parameter { name: "byteLength"; type: "ulong" }
+ }
+ Method { name: "buffer"; type: "ArrayBuffer*" }
+ Method { name: "byteOffset"; type: "ulong" }
+ Method { name: "byteLength"; type: "ulong" }
+ }
+ Component {
+ name: "Float32Array"
+ prototype: "TypedArray"
+ exports: ["QFloat32Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "float"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "float" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "array"; type: "QVariantList" }
+ Parameter { name: "offset"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ Parameter { name: "offset"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ }
+ Component {
+ name: "Float64Array"
+ prototype: "TypedArray"
+ exports: ["QFloat64Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "double"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "double" }
+ }
+ }
+ Component {
+ name: "Int16Array"
+ prototype: "TypedArray"
+ exports: ["QInt16Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "short"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "short" }
+ }
+ }
+ Component {
+ name: "Int32Array"
+ prototype: "TypedArray"
+ exports: ["QInt32Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "int"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "int" }
+ }
+ }
+ Component {
+ name: "Int8Array"
+ prototype: "TypedArray"
+ exports: ["QInt8Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "signed char"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "signed char" }
+ }
+ }
+ Component {
+ name: "QAbstractObject3D"
+ prototype: "QObject"
+ Property { name: "name"; type: "string" }
+ Signal {
+ name: "nameChanged"
+ Parameter { name: "name"; type: "string" }
+ }
+ }
+ Component {
+ name: "QBuffer3D"
+ prototype: "QAbstractObject3D"
+ exports: ["Buffer3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QtCanvas3D"
+ defaultProperty: "data"
+ prototype: "QQuickItem"
+ exports: ["Canvas3D 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "devicePixelRatio"; type: "float"; isReadonly: true }
+ Property { name: "imageLoader"; type: "QTexImageLoader3D"; isPointer: true }
+ Signal { name: "needRender" }
+ Signal {
+ name: "devicePixelRatioChanged"
+ Parameter { name: "ratio"; type: "float" }
+ }
+ Signal {
+ name: "animatedChanged"
+ Parameter { name: "animated"; type: "bool" }
+ }
+ Signal {
+ name: "clearWindowOnRenderUnderChanged"
+ Parameter { name: "enable"; type: "bool" }
+ }
+ Signal {
+ name: "renderOnTopChanged"
+ Parameter { name: "renderOnTop"; type: "bool" }
+ }
+ Signal {
+ name: "imageLoaderChanged"
+ Parameter { name: "loader"; type: "QTexImageLoader3D"; isPointer: true }
+ }
+ Signal {
+ name: "textureReady"
+ Parameter { name: "id"; type: "int" }
+ Parameter { name: "size"; type: "QSize" }
+ }
+ Method { name: "ready" }
+ Method { name: "shutDown" }
+ Method { name: "renderNext" }
+ Method {
+ name: "getContext"
+ type: "QContext3D*"
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "getContext"
+ type: "QContext3D*"
+ Parameter { name: "name"; type: "string" }
+ Parameter { name: "options"; type: "QVariantMap" }
+ }
+ }
+ Component {
+ name: "QContext3D"
+ prototype: "QObject"
+ exports: ["Context3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "glEnums"
+ values: {
+ "DEPTH_BUFFER_BIT": 256,
+ "STENCIL_BUFFER_BIT": 1024,
+ "COLOR_BUFFER_BIT": 16384,
+ "DEPTH_AND_COLOR_BUFFER_BIT": 16640,
+ "DEPTH_AND_STENCIL_AND_COLOR_BUFFER_BIT": 17664,
+ "POINTS": 0,
+ "LINES": 1,
+ "LINE_LOOP": 2,
+ "LINE_STRIP": 3,
+ "TRIANGLES": 4,
+ "TRIANGLE_STRIP": 5,
+ "TRIANGLE_FAN": 6,
+ "ZERO": 0,
+ "ONE": 1,
+ "SRC_COLOR": 768,
+ "ONE_MINUS_SRC_COLOR": 769,
+ "SRC_ALPHA": 770,
+ "ONE_MINUS_SRC_ALPHA": 771,
+ "DST_ALPHA": 772,
+ "ONE_MINUS_DST_ALPHA": 773,
+ "DST_COLOR": 774,
+ "ONE_MINUS_DST_COLOR": 775,
+ "SRC_ALPHA_SATURATE": 776,
+ "FUNC_ADD": 32774,
+ "BLEND_EQUATION": 32777,
+ "BLEND_EQUATION_RGB": 32777,
+ "BLEND_EQUATION_ALPHA": 34877,
+ "FUNC_SUBTRACT": 32778,
+ "FUNC_REVERSE_SUBTRACT": 32779,
+ "BLEND_DST_RGB": 32968,
+ "BLEND_SRC_RGB": 32969,
+ "BLEND_DST_ALPHA": 32970,
+ "BLEND_SRC_ALPHA": 32971,
+ "CONSTANT_COLOR": 32769,
+ "ONE_MINUS_CONSTANT_COLOR": 32770,
+ "CONSTANT_ALPHA": 32771,
+ "ONE_MINUS_CONSTANT_ALPHA": 32772,
+ "BLEND_COLOR": 32773,
+ "ARRAY_BUFFER": 34962,
+ "ELEMENT_ARRAY_BUFFER": 34963,
+ "ARRAY_BUFFER_BINDING": 34964,
+ "ELEMENT_ARRAY_BUFFER_BINDING": 34965,
+ "STREAM_DRAW": 35040,
+ "STATIC_DRAW": 35044,
+ "DYNAMIC_DRAW": 35048,
+ "BUFFER_SIZE": 34660,
+ "BUFFER_USAGE": 34661,
+ "CURRENT_VERTEX_ATTRIB": 34342,
+ "FRONT": 1028,
+ "BACK": 1029,
+ "FRONT_AND_BACK": 1032,
+ "CULL_FACE": 2884,
+ "BLEND": 3042,
+ "DITHER": 3024,
+ "STENCIL_TEST": 2960,
+ "DEPTH_TEST": 2929,
+ "SCISSOR_TEST": 3089,
+ "POLYGON_OFFSET_FILL": 32823,
+ "SAMPLE_ALPHA_TO_COVERAGE": 32926,
+ "SAMPLE_COVERAGE": 32928,
+ "NO_ERROR": 0,
+ "INVALID_ENUM": 1280,
+ "INVALID_VALUE": 1281,
+ "INVALID_OPERATION": 1282,
+ "OUT_OF_MEMORY": 1285,
+ "CW": 2304,
+ "CCW": 2305,
+ "LINE_WIDTH": 2849,
+ "ALIASED_POINT_SIZE_RANGE": 33901,
+ "ALIASED_LINE_WIDTH_RANGE": 33902,
+ "CULL_FACE_MODE": 2885,
+ "FRONT_FACE": 2886,
+ "DEPTH_RANGE": 2928,
+ "DEPTH_WRITEMASK": 2930,
+ "DEPTH_CLEAR_VALUE": 2931,
+ "DEPTH_FUNC": 2932,
+ "STENCIL_CLEAR_VALUE": 2961,
+ "STENCIL_FUNC": 2962,
+ "STENCIL_FAIL": 2964,
+ "STENCIL_PASS_DEPTH_FAIL": 2965,
+ "STENCIL_PASS_DEPTH_PASS": 2966,
+ "STENCIL_REF": 2967,
+ "STENCIL_VALUE_MASK": 2963,
+ "STENCIL_WRITEMASK": 2968,
+ "STENCIL_BACK_FUNC": 34816,
+ "STENCIL_BACK_FAIL": 34817,
+ "STENCIL_BACK_PASS_DEPTH_FAIL": 34818,
+ "STENCIL_BACK_PASS_DEPTH_PASS": 34819,
+ "STENCIL_BACK_REF": 36003,
+ "STENCIL_BACK_VALUE_MASK": 36004,
+ "STENCIL_BACK_WRITEMASK": 36005,
+ "VIEWPORT": 2978,
+ "SCISSOR_BOX": 3088,
+ "COLOR_CLEAR_VALUE": 3106,
+ "COLOR_WRITEMASK": 3107,
+ "UNPACK_ALIGNMENT": 3317,
+ "PACK_ALIGNMENT": 3333,
+ "MAX_TEXTURE_SIZE": 3379,
+ "MAX_VIEWPORT_DIMS": 3386,
+ "SUBPIXEL_BITS": 3408,
+ "RED_BITS": 3410,
+ "GREEN_BITS": 3411,
+ "BLUE_BITS": 3412,
+ "ALPHA_BITS": 3413,
+ "DEPTH_BITS": 3414,
+ "STENCIL_BITS": 3415,
+ "POLYGON_OFFSET_UNITS": 10752,
+ "POLYGON_OFFSET_FACTOR": 32824,
+ "TEXTURE_BINDING_2D": 32873,
+ "SAMPLE_BUFFERS": 32936,
+ "SAMPLES": 32937,
+ "SAMPLE_COVERAGE_VALUE": 32938,
+ "SAMPLE_COVERAGE_INVERT": 32939,
+ "COMPRESSED_TEXTURE_FORMATS": 34467,
+ "DONT_CARE": 4352,
+ "FASTEST": 4353,
+ "NICEST": 4354,
+ "GENERATE_MIPMAP_HINT": 33170,
+ "BYTE": 5120,
+ "UNSIGNED_BYTE": 5121,
+ "SHORT": 5122,
+ "UNSIGNED_SHORT": 5123,
+ "INT": 5124,
+ "UNSIGNED_INT": 5125,
+ "FLOAT": 5126,
+ "DEPTH_COMPONENT": 6402,
+ "ALPHA": 6406,
+ "RGB": 6407,
+ "RGBA": 6408,
+ "LUMINANCE": 6409,
+ "LUMINANCE_ALPHA": 6410,
+ "UNSIGNED_SHORT_4_4_4_4": 32819,
+ "UNSIGNED_SHORT_5_5_5_1": 32820,
+ "UNSIGNED_SHORT_5_6_5": 33635,
+ "FRAGMENT_SHADER": 35632,
+ "VERTEX_SHADER": 35633,
+ "MAX_VERTEX_ATTRIBS": 34921,
+ "MAX_VERTEX_UNIFORM_VECTORS": 36347,
+ "MAX_VARYING_VECTORS": 36348,
+ "MAX_COMBINED_TEXTURE_IMAGE_UNITS": 35661,
+ "MAX_VERTEX_TEXTURE_IMAGE_UNITS": 35660,
+ "MAX_TEXTURE_IMAGE_UNITS": 34930,
+ "MAX_FRAGMENT_UNIFORM_VECTORS": 36349,
+ "SHADER_TYPE": 35663,
+ "DELETE_STATUS": 35712,
+ "LINK_STATUS": 35714,
+ "VALIDATE_STATUS": 35715,
+ "ATTACHED_SHADERS": 35717,
+ "ACTIVE_UNIFORMS": 35718,
+ "ACTIVE_ATTRIBUTES": 35721,
+ "SHADING_LANGUAGE_VERSION": 35724,
+ "CURRENT_PROGRAM": 35725,
+ "NEVER": 512,
+ "LESS": 513,
+ "EQUAL": 514,
+ "LEQUAL": 515,
+ "GREATER": 516,
+ "NOTEQUAL": 517,
+ "GEQUAL": 518,
+ "ALWAYS": 519,
+ "KEEP": 7680,
+ "REPLACE": 7681,
+ "INCR": 7682,
+ "DECR": 7683,
+ "INVERT": 5386,
+ "INCR_WRAP": 34055,
+ "DECR_WRAP": 34056,
+ "VENDOR": 7936,
+ "RENDERER": 7937,
+ "VERSION": 7938,
+ "NEAREST": 9728,
+ "LINEAR": 9729,
+ "NEAREST_MIPMAP_NEAREST": 9984,
+ "LINEAR_MIPMAP_NEAREST": 9985,
+ "NEAREST_MIPMAP_LINEAR": 9986,
+ "LINEAR_MIPMAP_LINEAR": 9987,
+ "TEXTURE_MAG_FILTER": 10240,
+ "TEXTURE_MIN_FILTER": 10241,
+ "TEXTURE_WRAP_S": 10242,
+ "TEXTURE_WRAP_T": 10243,
+ "TEXTURE_2D": 3553,
+ "TEXTURE": 5890,
+ "TEXTURE_CUBE_MAP": 34067,
+ "TEXTURE_BINDING_CUBE_MAP": 34068,
+ "TEXTURE_CUBE_MAP_POSITIVE_X": 34069,
+ "TEXTURE_CUBE_MAP_NEGATIVE_X": 34070,
+ "TEXTURE_CUBE_MAP_POSITIVE_Y": 34071,
+ "TEXTURE_CUBE_MAP_NEGATIVE_Y": 34072,
+ "TEXTURE_CUBE_MAP_POSITIVE_Z": 34073,
+ "TEXTURE_CUBE_MAP_NEGATIVE_Z": 34074,
+ "MAX_CUBE_MAP_TEXTURE_SIZE": 34076,
+ "TEXTURE0": 33984,
+ "TEXTURE1": 33985,
+ "TEXTURE2": 33986,
+ "TEXTURE3": 33987,
+ "TEXTURE4": 33988,
+ "TEXTURE5": 33989,
+ "TEXTURE6": 33990,
+ "TEXTURE7": 33991,
+ "TEXTURE8": 33992,
+ "TEXTURE9": 33993,
+ "TEXTURE10": 33994,
+ "TEXTURE11": 33995,
+ "TEXTURE12": 33996,
+ "TEXTURE13": 33997,
+ "TEXTURE14": 33998,
+ "TEXTURE15": 33999,
+ "TEXTURE16": 34000,
+ "TEXTURE17": 34001,
+ "TEXTURE18": 34002,
+ "TEXTURE19": 34003,
+ "TEXTURE20": 34004,
+ "TEXTURE21": 34005,
+ "TEXTURE22": 34006,
+ "TEXTURE23": 34007,
+ "TEXTURE24": 34008,
+ "TEXTURE25": 34009,
+ "TEXTURE26": 34010,
+ "TEXTURE27": 34011,
+ "TEXTURE28": 34012,
+ "TEXTURE29": 34013,
+ "TEXTURE30": 34014,
+ "TEXTURE31": 34015,
+ "ACTIVE_TEXTURE": 34016,
+ "REPEAT": 10497,
+ "CLAMP_TO_EDGE": 33071,
+ "MIRRORED_REPEAT": 33648,
+ "FLOAT_VEC2": 35664,
+ "FLOAT_VEC3": 35665,
+ "FLOAT_VEC4": 35666,
+ "INT_VEC2": 35667,
+ "INT_VEC3": 35668,
+ "INT_VEC4": 35669,
+ "BOOL": 35670,
+ "BOOL_VEC2": 35671,
+ "BOOL_VEC3": 35672,
+ "BOOL_VEC4": 35673,
+ "FLOAT_MAT2": 35674,
+ "FLOAT_MAT3": 35675,
+ "FLOAT_MAT4": 35676,
+ "SAMPLER_2D": 35678,
+ "SAMPLER_CUBE": 35680,
+ "VERTEX_ATTRIB_ARRAY_ENABLED": 34338,
+ "VERTEX_ATTRIB_ARRAY_SIZE": 34339,
+ "VERTEX_ATTRIB_ARRAY_STRIDE": 34340,
+ "VERTEX_ATTRIB_ARRAY_TYPE": 34341,
+ "VERTEX_ATTRIB_ARRAY_NORMALIZED": 34922,
+ "VERTEX_ATTRIB_ARRAY_POINTER": 34373,
+ "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING": 34975,
+ "COMPILE_STATUS": 35713,
+ "LOW_FLOAT": 36336,
+ "MEDIUM_FLOAT": 36337,
+ "HIGH_FLOAT": 36338,
+ "LOW_INT": 36339,
+ "MEDIUM_INT": 36340,
+ "HIGH_INT": 36341,
+ "FRAMEBUFFER": 36160,
+ "RENDERBUFFER": 36161,
+ "RGBA4": 32854,
+ "RGB5_A1": 32855,
+ "RGB565": 36194,
+ "DEPTH_COMPONENT16": 33189,
+ "STENCIL_INDEX": 6401,
+ "STENCIL_INDEX8": 36168,
+ "DEPTH_STENCIL": 34041,
+ "RENDERBUFFER_WIDTH": 36162,
+ "RENDERBUFFER_HEIGHT": 36163,
+ "RENDERBUFFER_INTERNAL_FORMAT": 36164,
+ "RENDERBUFFER_RED_SIZE": 36176,
+ "RENDERBUFFER_GREEN_SIZE": 36177,
+ "RENDERBUFFER_BLUE_SIZE": 36178,
+ "RENDERBUFFER_ALPHA_SIZE": 36179,
+ "RENDERBUFFER_DEPTH_SIZE": 36180,
+ "RENDERBUFFER_STENCIL_SIZE": 36181,
+ "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE": 36048,
+ "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME": 36049,
+ "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL": 36050,
+ "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE": 36051,
+ "COLOR_ATTACHMENT0": 36064,
+ "DEPTH_ATTACHMENT": 36096,
+ "STENCIL_ATTACHMENT": 36128,
+ "DEPTH_STENCIL_ATTACHMENT": 33306,
+ "NONE": 0,
+ "FRAMEBUFFER_COMPLETE": 36053,
+ "FRAMEBUFFER_INCOMPLETE_ATTACHMENT": 36054,
+ "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT": 36055,
+ "FRAMEBUFFER_INCOMPLETE_DIMENSIONS": 36057,
+ "FRAMEBUFFER_UNSUPPORTED": 36061,
+ "FRAMEBUFFER_BINDING": 36006,
+ "RENDERBUFFER_BINDING": 36007,
+ "MAX_RENDERBUFFER_SIZE": 34024,
+ "INVALID_FRAMEBUFFER_OPERATION": 1286,
+ "UNPACK_FLIP_Y_WEBGL": 37440,
+ "UNPACK_PREMULTIPLY_ALPHA_WEBGL": 37441,
+ "CONTEXT_LOST_WEBGL": 37442,
+ "UNPACK_COLORSPACE_CONVERSION_WEBGL": 37443,
+ "BROWSER_DEFAULT_WEBGL": 37444,
+ "UNMASKED_VENDOR_WEBGL": 37445,
+ "UNMASKED_RENDERER_WEBGL": 37446
+ }
+ }
+ Property { name: "canvas"; type: "QtCanvas3D"; isReadonly: true; isPointer: true }
+ Property { name: "DEPTH_BUFFER_BIT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BUFFER_BIT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "COLOR_BUFFER_BIT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "POINTS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINES"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINE_LOOP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINE_STRIP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TRIANGLES"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TRIANGLE_STRIP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TRIANGLE_FAN"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ZERO"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ONE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SRC_COLOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ONE_MINUS_SRC_COLOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SRC_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ONE_MINUS_SRC_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DST_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ONE_MINUS_DST_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DST_COLOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ONE_MINUS_DST_COLOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SRC_ALPHA_SATURATE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FUNC_ADD"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_EQUATION"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_EQUATION_RGB"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_EQUATION_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FUNC_SUBTRACT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FUNC_REVERSE_SUBTRACT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_DST_RGB"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_SRC_RGB"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_DST_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_SRC_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CONSTANT_COLOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ONE_MINUS_CONSTANT_COLOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CONSTANT_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ONE_MINUS_CONSTANT_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND_COLOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ARRAY_BUFFER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ELEMENT_ARRAY_BUFFER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ARRAY_BUFFER_BINDING"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ELEMENT_ARRAY_BUFFER_BINDING"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STREAM_DRAW"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STATIC_DRAW"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DYNAMIC_DRAW"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BUFFER_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BUFFER_USAGE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CURRENT_VERTEX_ATTRIB"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FRONT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BACK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FRONT_AND_BACK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CULL_FACE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLEND"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DITHER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_TEST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_TEST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SCISSOR_TEST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "POLYGON_OFFSET_FILL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLE_ALPHA_TO_COVERAGE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLE_COVERAGE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NO_ERROR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INVALID_ENUM"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INVALID_VALUE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INVALID_OPERATION"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "OUT_OF_MEMORY"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CW"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CCW"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINE_WIDTH"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ALIASED_POINT_SIZE_RANGE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ALIASED_LINE_WIDTH_RANGE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CULL_FACE_MODE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FRONT_FACE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_RANGE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_WRITEMASK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_CLEAR_VALUE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_FUNC"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_CLEAR_VALUE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_FUNC"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_FAIL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_PASS_DEPTH_FAIL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_PASS_DEPTH_PASS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_REF"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_VALUE_MASK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_WRITEMASK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BACK_FUNC"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BACK_FAIL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BACK_PASS_DEPTH_FAIL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BACK_PASS_DEPTH_PASS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BACK_REF"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BACK_VALUE_MASK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BACK_WRITEMASK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VIEWPORT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SCISSOR_BOX"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "COLOR_CLEAR_VALUE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "COLOR_WRITEMASK"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "UNPACK_ALIGNMENT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "PACK_ALIGNMENT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_TEXTURE_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_VIEWPORT_DIMS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SUBPIXEL_BITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RED_BITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "GREEN_BITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BLUE_BITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ALPHA_BITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_BITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_BITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "POLYGON_OFFSET_UNITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "POLYGON_OFFSET_FACTOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_BINDING_2D"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLE_BUFFERS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLES"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLE_COVERAGE_VALUE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLE_COVERAGE_INVERT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "COMPRESSED_TEXTURE_FORMATS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DONT_CARE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FASTEST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NICEST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "GENERATE_MIPMAP_HINT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BYTE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "UNSIGNED_BYTE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SHORT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "UNSIGNED_SHORT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "UNSIGNED_INT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FLOAT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_COMPONENT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RGB"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RGBA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LUMINANCE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LUMINANCE_ALPHA"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "UNSIGNED_SHORT_4_4_4_4"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "UNSIGNED_SHORT_5_5_5_1"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "UNSIGNED_SHORT_5_6_5"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FRAGMENT_SHADER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VERTEX_SHADER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_VERTEX_ATTRIBS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_VERTEX_UNIFORM_VECTORS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_VARYING_VECTORS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "MAX_COMBINED_TEXTURE_IMAGE_UNITS"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property {
+ name: "MAX_VERTEX_TEXTURE_IMAGE_UNITS"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "MAX_TEXTURE_IMAGE_UNITS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_FRAGMENT_UNIFORM_VECTORS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SHADER_TYPE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DELETE_STATUS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINK_STATUS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VALIDATE_STATUS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ATTACHED_SHADERS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ACTIVE_UNIFORMS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ACTIVE_ATTRIBUTES"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SHADING_LANGUAGE_VERSION"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CURRENT_PROGRAM"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NEVER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LESS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "EQUAL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LEQUAL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "GREATER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NOTEQUAL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "GEQUAL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ALWAYS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "KEEP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "REPLACE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INCR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DECR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INVERT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INCR_WRAP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DECR_WRAP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VENDOR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VERSION"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NEAREST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINEAR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NEAREST_MIPMAP_NEAREST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINEAR_MIPMAP_NEAREST"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NEAREST_MIPMAP_LINEAR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LINEAR_MIPMAP_LINEAR"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_MAG_FILTER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_MIN_FILTER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_WRAP_S"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_WRAP_T"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_2D"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_CUBE_MAP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_BINDING_CUBE_MAP"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_CUBE_MAP_POSITIVE_X"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_CUBE_MAP_NEGATIVE_X"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_CUBE_MAP_POSITIVE_Y"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_CUBE_MAP_NEGATIVE_Y"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_CUBE_MAP_POSITIVE_Z"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE_CUBE_MAP_NEGATIVE_Z"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_CUBE_MAP_TEXTURE_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE0"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE1"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE2"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE3"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE4"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE5"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE6"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE7"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE8"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE9"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE10"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE11"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE12"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE13"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE14"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE15"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE16"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE17"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE18"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE19"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE20"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE21"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE22"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE23"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE24"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE25"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE26"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE27"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE28"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE29"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE30"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "TEXTURE31"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "ACTIVE_TEXTURE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "REPEAT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "CLAMP_TO_EDGE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MIRRORED_REPEAT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FLOAT_VEC2"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FLOAT_VEC3"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FLOAT_VEC4"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INT_VEC2"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INT_VEC3"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "INT_VEC4"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BOOL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BOOL_VEC2"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BOOL_VEC3"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "BOOL_VEC4"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FLOAT_MAT2"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FLOAT_MAT3"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FLOAT_MAT4"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLER_2D"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "SAMPLER_CUBE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VERTEX_ATTRIB_ARRAY_ENABLED"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VERTEX_ATTRIB_ARRAY_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VERTEX_ATTRIB_ARRAY_STRIDE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "VERTEX_ATTRIB_ARRAY_TYPE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "VERTEX_ATTRIB_ARRAY_NORMALIZED"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "VERTEX_ATTRIB_ARRAY_POINTER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "VERTEX_ATTRIB_ARRAY_BUFFER_BINDING"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "COMPILE_STATUS"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LOW_FLOAT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MEDIUM_FLOAT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "HIGH_FLOAT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "LOW_INT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MEDIUM_INT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "HIGH_INT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FRAMEBUFFER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RGBA4"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RGB5_A1"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RGB565"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_COMPONENT16"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_INDEX"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_INDEX8"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_STENCIL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_WIDTH"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_HEIGHT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_INTERNAL_FORMAT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_RED_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_GREEN_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_BLUE_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_ALPHA_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_DEPTH_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_STENCIL_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property {
+ name: "FRAMEBUFFER_ATTACHMENT_OBJECT_NAME"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property {
+ name: "FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property {
+ name: "FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "COLOR_ATTACHMENT0"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_ATTACHMENT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "STENCIL_ATTACHMENT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "DEPTH_STENCIL_ATTACHMENT"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "NONE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FRAMEBUFFER_COMPLETE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "FRAMEBUFFER_INCOMPLETE_ATTACHMENT"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property {
+ name: "FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property {
+ name: "FRAMEBUFFER_INCOMPLETE_DIMENSIONS"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "FRAMEBUFFER_UNSUPPORTED"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "FRAMEBUFFER_BINDING"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "RENDERBUFFER_BINDING"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property { name: "MAX_RENDERBUFFER_SIZE"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "INVALID_FRAMEBUFFER_OPERATION"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "UNPACK_FLIP_Y_WEBGL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "UNPACK_PREMULTIPLY_ALPHA_WEBGL"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "CONTEXT_LOST_WEBGL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Property {
+ name: "UNPACK_COLORSPACE_CONVERSION_WEBGL"
+ type: "QContext3D::glEnums"
+ isReadonly: true
+ }
+ Property { name: "BROWSER_DEFAULT_WEBGL"; type: "QContext3D::glEnums"; isReadonly: true }
+ Signal {
+ name: "viewportChanged"
+ Parameter { name: "viewport"; type: "QRect" }
+ }
+ Signal {
+ name: "viewportWidthChanged"
+ Parameter { name: "width"; type: "int" }
+ }
+ Signal {
+ name: "viewportHeightChanged"
+ Parameter { name: "height"; type: "int" }
+ }
+ Signal {
+ name: "imageLoaded"
+ Parameter { name: "url"; type: "QUrl" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ Parameter { name: "format"; type: "int" }
+ Parameter { name: "list"; type: "QVariantList" }
+ }
+ Signal {
+ name: "imageLoadingError"
+ Parameter { name: "url"; type: "QUrl" }
+ Parameter { name: "errorString"; type: "string" }
+ }
+ Signal {
+ name: "canvasChanged"
+ Parameter { name: "canvas"; type: "QtCanvas3D"; isPointer: true }
+ }
+ Method { name: "getSupportedExtensions"; type: "QVariantList" }
+ Method {
+ name: "getExtension"
+ type: "QVariant"
+ Parameter { name: "name"; type: "string" }
+ }
+ Method { name: "isContextLost"; type: "bool" }
+ Method { name: "getContextAttributes"; type: "QContextAttributes*" }
+ Method {
+ name: "getShaderPrecisionFormat"
+ type: "QShaderPrecisionFormat*"
+ Parameter { name: "shadertype"; type: "glEnums" }
+ Parameter { name: "precisiontype"; type: "glEnums" }
+ }
+ Method { name: "flush" }
+ Method { name: "finish" }
+ Method { name: "createTexture"; type: "QTexture3D*" }
+ Method {
+ name: "deleteTexture"
+ Parameter { name: "texture"; type: "QTexture3D"; isPointer: true }
+ }
+ Method {
+ name: "activeTexture"
+ Parameter { name: "texture"; type: "glEnums" }
+ }
+ Method {
+ name: "bindTexture"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "texture"; type: "QTexture3D"; isPointer: true }
+ }
+ Method {
+ name: "generateMipmap"
+ Parameter { name: "target"; type: "glEnums" }
+ }
+ Method {
+ name: "isTexture"
+ type: "bool"
+ Parameter { name: "texture"; type: "QObject"; isPointer: true }
+ }
+ Method {
+ name: "compressedTexImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "internalformat"; type: "glEnums" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ Parameter { name: "border"; type: "int" }
+ Parameter { name: "pixels"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "compressedTexSubImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "xoffset"; type: "int" }
+ Parameter { name: "yoffset"; type: "int" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ Parameter { name: "format"; type: "glEnums" }
+ Parameter { name: "pixels"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "copyTexImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "internalformat"; type: "glEnums" }
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ Parameter { name: "border"; type: "int" }
+ }
+ Method {
+ name: "copyTexSubImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "xoffset"; type: "int" }
+ Parameter { name: "yoffset"; type: "int" }
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ }
+ Method {
+ name: "texImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "internalformat"; type: "glEnums" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ Parameter { name: "border"; type: "int" }
+ Parameter { name: "format"; type: "glEnums" }
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "pixels"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "texSubImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "xoffset"; type: "int" }
+ Parameter { name: "yoffset"; type: "int" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ Parameter { name: "format"; type: "glEnums" }
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "pixels"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "texImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "internalformat"; type: "glEnums" }
+ Parameter { name: "format"; type: "glEnums" }
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "image"; type: "QTexImage3D"; isPointer: true }
+ }
+ Method {
+ name: "texSubImage2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "level"; type: "int" }
+ Parameter { name: "xoffset"; type: "int" }
+ Parameter { name: "yoffset"; type: "int" }
+ Parameter { name: "format"; type: "glEnums" }
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "image"; type: "QTexImage3D"; isPointer: true }
+ }
+ Method {
+ name: "texParameterf"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "pname"; type: "glEnums" }
+ Parameter { name: "param"; type: "float" }
+ }
+ Method {
+ name: "texParameteri"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "pname"; type: "glEnums" }
+ Parameter { name: "param"; type: "int" }
+ }
+ Method { name: "createFramebuffer"; type: "QFramebuffer3D*" }
+ Method {
+ name: "bindFramebuffer"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "framebuffer"; type: "QFramebuffer3D"; isPointer: true }
+ }
+ Method {
+ name: "checkFramebufferStatus"
+ type: "glEnums"
+ Parameter { name: "target"; type: "glEnums" }
+ }
+ Method {
+ name: "framebufferRenderbuffer"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "attachment"; type: "glEnums" }
+ Parameter { name: "renderbuffertarget"; type: "glEnums" }
+ Parameter { name: "renderbuffer"; type: "QRenderbuffer3D"; isPointer: true }
+ }
+ Method {
+ name: "framebufferTexture2D"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "attachment"; type: "glEnums" }
+ Parameter { name: "textarget"; type: "glEnums" }
+ Parameter { name: "texture"; type: "QTexture3D"; isPointer: true }
+ Parameter { name: "level"; type: "int" }
+ }
+ Method {
+ name: "isFramebuffer"
+ type: "bool"
+ Parameter { name: "anyObject"; type: "QObject"; isPointer: true }
+ }
+ Method {
+ name: "deleteFramebuffer"
+ Parameter { name: "buffer"; type: "QFramebuffer3D"; isPointer: true }
+ }
+ Method { name: "createRenderbuffer"; type: "QRenderbuffer3D*" }
+ Method {
+ name: "bindRenderbuffer"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "renderbuffer"; type: "QRenderbuffer3D"; isPointer: true }
+ }
+ Method {
+ name: "renderbufferStorage"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "internalformat"; type: "glEnums" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ }
+ Method {
+ name: "isRenderbuffer"
+ type: "bool"
+ Parameter { name: "anyObject"; type: "QObject"; isPointer: true }
+ }
+ Method {
+ name: "deleteRenderbuffer"
+ Parameter { name: "renderbuffer"; type: "QRenderbuffer3D"; isPointer: true }
+ }
+ Method {
+ name: "sampleCoverage"
+ Parameter { name: "value"; type: "float" }
+ Parameter { name: "invert"; type: "bool" }
+ }
+ Method {
+ name: "createShader"
+ type: "QShader3D*"
+ Parameter { name: "type"; type: "glEnums" }
+ }
+ Method {
+ name: "isShader"
+ type: "bool"
+ Parameter { name: "anyObject"; type: "QObject"; isPointer: true }
+ }
+ Method {
+ name: "deleteShader"
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ }
+ Method {
+ name: "shaderSource"
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ Parameter { name: "shaderSource"; type: "string" }
+ }
+ Method {
+ name: "getShaderSource"
+ type: "string"
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ }
+ Method {
+ name: "compileShader"
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ }
+ Method {
+ name: "uniform1f"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "float" }
+ }
+ Method {
+ name: "uniform1i"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "int" }
+ }
+ Method {
+ name: "uniform2f"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "float" }
+ Parameter { name: "y"; type: "float" }
+ }
+ Method {
+ name: "uniform2i"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ }
+ Method {
+ name: "uniform3f"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "float" }
+ Parameter { name: "y"; type: "float" }
+ Parameter { name: "z"; type: "float" }
+ }
+ Method {
+ name: "uniform3i"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ Parameter { name: "z"; type: "int" }
+ }
+ Method {
+ name: "uniform4f"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "float" }
+ Parameter { name: "y"; type: "float" }
+ Parameter { name: "z"; type: "float" }
+ Parameter { name: "w"; type: "float" }
+ }
+ Method {
+ name: "uniform4i"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ Parameter { name: "z"; type: "int" }
+ Parameter { name: "w"; type: "int" }
+ }
+ Method {
+ name: "uniform1fv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform1iv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Int32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform2fv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform2iv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Int32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform3fv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform3iv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Int32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform4fv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform4iv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "Int32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniform1fva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniform2fva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniform3fva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniform4fva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniform1iva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniform2iva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniform3iva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniform4iva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniformMatrix2fv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "transpose"; type: "bool" }
+ Parameter { name: "value"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniformMatrix3fv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "transpose"; type: "bool" }
+ Parameter { name: "value"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniformMatrix4fv"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "transpose"; type: "bool" }
+ Parameter { name: "value"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "uniformMatrix2fva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "transpose"; type: "bool" }
+ Parameter { name: "value"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniformMatrix3fva"
+ Parameter { name: "location"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "transpose"; type: "bool" }
+ Parameter { name: "value"; type: "QVariantList" }
+ }
+ Method {
+ name: "uniformMatrix4fva"
+ Parameter { name: "uniformLocation"; type: "QUniformLocation"; isPointer: true }
+ Parameter { name: "transpose"; type: "bool" }
+ Parameter { name: "value"; type: "QVariantList" }
+ }
+ Method { name: "createProgram"; type: "QProgram3D*" }
+ Method {
+ name: "attachShader"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ }
+ Method {
+ name: "detachShader"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ }
+ Method {
+ name: "linkProgram"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ }
+ Method {
+ name: "useProgram"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ }
+ Method {
+ name: "validateProgram"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ }
+ Method {
+ name: "getUniformLocation"
+ type: "QUniformLocation*"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "getAttribLocation"
+ type: "int"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "bindAttribLocation"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ Parameter { name: "index"; type: "int" }
+ Parameter { name: "name"; type: "string" }
+ }
+ Method {
+ name: "getProgramInfoLog"
+ type: "string"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ }
+ Method {
+ name: "isProgram"
+ type: "bool"
+ Parameter { name: "anyObject"; type: "QObject"; isPointer: true }
+ }
+ Method {
+ name: "deleteProgram"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ }
+ Method {
+ name: "disableVertexAttribArray"
+ Parameter { name: "index"; type: "int" }
+ }
+ Method {
+ name: "enableVertexAttribArray"
+ Parameter { name: "index"; type: "int" }
+ }
+ Method {
+ name: "vertexAttribPointer"
+ Parameter { name: "indx"; type: "int" }
+ Parameter { name: "size"; type: "int" }
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "normalized"; type: "bool" }
+ Parameter { name: "stride"; type: "int" }
+ Parameter { name: "offset"; type: "long" }
+ }
+ Method {
+ name: "vertexAttrib1f"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "x"; type: "float" }
+ }
+ Method {
+ name: "vertexAttrib1fv"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "values"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "vertexAttrib2f"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "x"; type: "float" }
+ Parameter { name: "y"; type: "float" }
+ }
+ Method {
+ name: "vertexAttrib2fv"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "values"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "vertexAttrib3f"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "x"; type: "float" }
+ Parameter { name: "y"; type: "float" }
+ Parameter { name: "z"; type: "float" }
+ }
+ Method {
+ name: "vertexAttrib3fv"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "values"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "vertexAttrib4f"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "x"; type: "float" }
+ Parameter { name: "y"; type: "float" }
+ Parameter { name: "z"; type: "float" }
+ Parameter { name: "w"; type: "float" }
+ }
+ Method {
+ name: "vertexAttrib4fv"
+ Parameter { name: "indx"; type: "uint" }
+ Parameter { name: "values"; type: "Float32Array"; isPointer: true }
+ }
+ Method {
+ name: "getShaderParameter"
+ type: "int"
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ Parameter { name: "paramName"; type: "glEnums" }
+ }
+ Method {
+ name: "getProgramParameter"
+ type: "int"
+ Parameter { name: "program"; type: "QProgram3D"; isPointer: true }
+ Parameter { name: "paramName"; type: "glEnums" }
+ }
+ Method {
+ name: "getShaderInfoLog"
+ type: "string"
+ Parameter { name: "shader"; type: "QShader3D"; isPointer: true }
+ }
+ Method { name: "createBuffer"; type: "QBuffer3D*" }
+ Method {
+ name: "bindBuffer"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "buffer"; type: "QBuffer3D"; isPointer: true }
+ }
+ Method {
+ name: "bufferData"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "size"; type: "long" }
+ Parameter { name: "hint"; type: "glEnums" }
+ }
+ Method {
+ name: "bufferData"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "data"; type: "TypedArray"; isPointer: true }
+ Parameter { name: "hint"; type: "glEnums" }
+ }
+ Method {
+ name: "bufferData"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "data"; type: "ArrayBuffer&" }
+ Parameter { name: "hint"; type: "glEnums" }
+ }
+ Method {
+ name: "bufferSubData"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "offset"; type: "int" }
+ Parameter { name: "data"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "bufferSubData"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "offset"; type: "int" }
+ Parameter { name: "data"; type: "ArrayBuffer&" }
+ }
+ Method {
+ name: "getBufferParameter"
+ type: "QVariant"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "pname"; type: "glEnums" }
+ }
+ Method {
+ name: "isBuffer"
+ type: "bool"
+ Parameter { name: "anyObject"; type: "QObject"; isPointer: true }
+ }
+ Method {
+ name: "deleteBuffer"
+ Parameter { name: "buffer"; type: "QBuffer3D"; isPointer: true }
+ }
+ Method { name: "getError"; type: "glEnums" }
+ Method {
+ name: "cullFace"
+ Parameter { name: "mode"; type: "glEnums" }
+ }
+ Method {
+ name: "frontFace"
+ Parameter { name: "mode"; type: "glEnums" }
+ }
+ Method {
+ name: "lineWidth"
+ Parameter { name: "width"; type: "float" }
+ }
+ Method {
+ name: "pixelStorei"
+ Parameter { name: "pname"; type: "glEnums" }
+ Parameter { name: "param"; type: "int" }
+ }
+ Method {
+ name: "polygonOffset"
+ Parameter { name: "factor"; type: "float" }
+ Parameter { name: "units"; type: "float" }
+ }
+ Method {
+ name: "hint"
+ Parameter { name: "target"; type: "glEnums" }
+ Parameter { name: "mode"; type: "glEnums" }
+ }
+ Method {
+ name: "enable"
+ Parameter { name: "flag"; type: "glEnums" }
+ }
+ Method {
+ name: "isEnabled"
+ type: "bool"
+ Parameter { name: "flag"; type: "glEnums" }
+ }
+ Method {
+ name: "disable"
+ Parameter { name: "flag"; type: "glEnums" }
+ }
+ Method {
+ name: "getParameter"
+ type: "QVariant"
+ Parameter { name: "pname"; type: "glEnums" }
+ }
+ Method {
+ name: "clear"
+ Parameter { name: "flags"; type: "glEnums" }
+ }
+ Method {
+ name: "depthMask"
+ Parameter { name: "flag"; type: "bool" }
+ }
+ Method {
+ name: "depthFunc"
+ Parameter { name: "func"; type: "glEnums" }
+ }
+ Method {
+ name: "depthRange"
+ Parameter { name: "zNear"; type: "float" }
+ Parameter { name: "zFar"; type: "float" }
+ }
+ Method {
+ name: "clearDepth"
+ Parameter { name: "depth"; type: "float" }
+ }
+ Method {
+ name: "clearColor"
+ Parameter { name: "red"; type: "float" }
+ Parameter { name: "green"; type: "float" }
+ Parameter { name: "blue"; type: "float" }
+ Parameter { name: "alpha"; type: "float" }
+ }
+ Method {
+ name: "clearStencil"
+ Parameter { name: "s"; type: "int" }
+ }
+ Method {
+ name: "colorMask"
+ Parameter { name: "red"; type: "bool" }
+ Parameter { name: "green"; type: "bool" }
+ Parameter { name: "blue"; type: "bool" }
+ Parameter { name: "alpha"; type: "bool" }
+ }
+ Method {
+ name: "blendColor"
+ Parameter { name: "red"; type: "float" }
+ Parameter { name: "green"; type: "float" }
+ Parameter { name: "blue"; type: "float" }
+ Parameter { name: "alpha"; type: "float" }
+ }
+ Method {
+ name: "blendEquation"
+ Parameter { name: "mode"; type: "glEnums" }
+ }
+ Method {
+ name: "blendEquationSeparate"
+ Parameter { name: "modeRGB"; type: "glEnums" }
+ Parameter { name: "modeAlpha"; type: "glEnums" }
+ }
+ Method {
+ name: "blendFunc"
+ Parameter { name: "sfactor"; type: "glEnums" }
+ Parameter { name: "dfactor"; type: "glEnums" }
+ }
+ Method {
+ name: "blendFuncSeparate"
+ Parameter { name: "srcRGB"; type: "glEnums" }
+ Parameter { name: "dstRGB"; type: "glEnums" }
+ Parameter { name: "srcAlpha"; type: "glEnums" }
+ Parameter { name: "dstAlpha"; type: "glEnums" }
+ }
+ Method {
+ name: "drawArrays"
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "first"; type: "int" }
+ Parameter { name: "count"; type: "int" }
+ }
+ Method {
+ name: "drawElements"
+ Parameter { name: "mode"; type: "glEnums" }
+ Parameter { name: "count"; type: "int" }
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "offset"; type: "long" }
+ }
+ Method {
+ name: "viewport"
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ }
+ Method {
+ name: "scissor"
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ Parameter { name: "width"; type: "int" }
+ Parameter { name: "height"; type: "int" }
+ }
+ Method {
+ name: "readPixels"
+ Parameter { name: "x"; type: "int" }
+ Parameter { name: "y"; type: "int" }
+ Parameter { name: "width"; type: "long" }
+ Parameter { name: "height"; type: "long" }
+ Parameter { name: "format"; type: "glEnums" }
+ Parameter { name: "type"; type: "glEnums" }
+ Parameter { name: "pixels"; type: "ArrayBufferView"; isPointer: true }
+ }
+ }
+ Component {
+ name: "QContextAttributes"
+ prototype: "QObject"
+ exports: ["ContextAttributes 1.0"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "alpha"; type: "bool" }
+ Property { name: "depth"; type: "bool" }
+ Property { name: "stencil"; type: "bool" }
+ Property { name: "antialias"; type: "bool" }
+ Property { name: "premultipliedAlpha"; type: "bool" }
+ Property { name: "preserveDrawingBuffer"; type: "bool" }
+ Property { name: "preferLowPowerToHighPerformance"; type: "bool" }
+ Property { name: "failIfMajorPerformanceCaveat"; type: "bool" }
+ Signal {
+ name: "alphaChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ Signal {
+ name: "depthChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ Signal {
+ name: "stencilChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ Signal {
+ name: "antialiasChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ Signal {
+ name: "premultipliedAlphaChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ Signal {
+ name: "preserveDrawingBufferChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ Signal {
+ name: "preferLowPowerToHighPerformanceChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ Signal {
+ name: "failIfMajorPerformanceCaveatChanged"
+ Parameter { name: "newValue"; type: "bool" }
+ }
+ }
+ Component {
+ name: "QFramebuffer3D"
+ prototype: "QAbstractObject3D"
+ exports: ["Framebuffer3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QProgram3D"
+ prototype: "QAbstractObject3D"
+ exports: ["Program3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "id"; type: "int"; isReadonly: true }
+ Signal {
+ name: "idChanged"
+ Parameter { name: "id"; type: "int" }
+ }
+ }
+ Component {
+ name: "QRenderbuffer3D"
+ prototype: "QObject"
+ exports: ["Renderbuffer3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QShader3D"
+ prototype: "QObject"
+ exports: ["Shader3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QShaderPrecisionFormat"
+ prototype: "QObject"
+ exports: ["ShaderPrecisionFormat 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "rangeMin"; type: "int"; isReadonly: true }
+ Property { name: "rangeMax"; type: "int"; isReadonly: true }
+ Property { name: "precision"; type: "int"; isReadonly: true }
+ Signal {
+ name: "rangeMinChanged"
+ Parameter { name: "rangeMin"; type: "int" }
+ }
+ Signal {
+ name: "rangeMaxChanged"
+ Parameter { name: "rangeMax"; type: "int" }
+ }
+ Signal {
+ name: "precisionChanged"
+ Parameter { name: "precision"; type: "int" }
+ }
+ }
+ Component {
+ name: "QTexImage3D"
+ prototype: "QAbstractObject3D"
+ exports: ["TexImage 1.0"]
+ exportMetaObjectRevisions: [0]
+ Enum {
+ name: "QTexImageState"
+ values: {
+ "INITIALIZED": 0,
+ "LOAD_PENDING": 1,
+ "LOADING": 2,
+ "LOADING_FINISHED": 3,
+ "LOADING_ERROR": 4
+ }
+ }
+ Property { name: "source"; type: "QUrl" }
+ Property { name: "imageState"; type: "QTexImageState"; isReadonly: true }
+ Property { name: "width"; type: "int"; isReadonly: true }
+ Property { name: "height"; type: "int"; isReadonly: true }
+ Property { name: "errorString"; type: "string"; isReadonly: true }
+ Signal {
+ name: "sourceChanged"
+ Parameter { name: "source"; type: "QUrl" }
+ }
+ Signal {
+ name: "imageStateChanged"
+ Parameter { name: "state"; type: "QTexImageState" }
+ }
+ Signal {
+ name: "widthChanged"
+ Parameter { name: "width"; type: "int" }
+ }
+ Signal {
+ name: "heightChanged"
+ Parameter { name: "height"; type: "int" }
+ }
+ Signal {
+ name: "errorStringChanged"
+ Parameter { name: "errorString"; type: "string" }
+ }
+ Signal {
+ name: "anythingChanged"
+ Parameter { name: "value"; type: "QVariant"; isPointer: true }
+ }
+ Method { name: "id"; type: "ulong" }
+ }
+ Component {
+ name: "QTexImageLoader3D"
+ prototype: "QObject"
+ exports: ["TextureImageLoader 1.0"]
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "loadImage"
+ type: "QTexImage3D*"
+ Parameter { name: "url"; type: "QUrl" }
+ }
+ }
+ Component {
+ name: "QTexture3D"
+ prototype: "QAbstractObject3D"
+ exports: ["Texture3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "QUniformLocation"
+ prototype: "QAbstractObject3D"
+ exports: ["UniformLocation3D 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ }
+ Component {
+ name: "TypedArray"
+ prototype: "ArrayBufferView"
+ exports: ["QTypedArray 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Property { name: "length"; type: "ulong"; isReadonly: true }
+ Signal {
+ name: "lengthChanged"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ }
+ Component {
+ name: "Arrays"
+ prototype: "QObject"
+ exports: ["Arrays 1.0"]
+ isCreatable: false
+ isSingleton: true
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "newInt8Array"
+ type: "Int8Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newInt8Array"
+ type: "Int8Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newInt8Array"
+ type: "Int8Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newInt8Array"
+ type: "Int8Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newUint8Array"
+ type: "Uint8Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newUint8Array"
+ type: "Uint8Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newUint8Array"
+ type: "Uint8Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newUint8Array"
+ type: "Uint8Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newInt16Array"
+ type: "Int16Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newInt16Array"
+ type: "Int16Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newInt16Array"
+ type: "Int16Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newInt16Array"
+ type: "Int16Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newUint16Array"
+ type: "Uint16Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newUint16Array"
+ type: "Uint16Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newUint16Array"
+ type: "Uint16Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newUint16Array"
+ type: "Uint16Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newInt32Array"
+ type: "Int32Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newInt32Array"
+ type: "Int32Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newInt32Array"
+ type: "Int32Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newInt32Array"
+ type: "Int32Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newUint32Array"
+ type: "Uint32Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newUint32Array"
+ type: "Uint32Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newUint32Array"
+ type: "Uint32Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newUint32Array"
+ type: "Uint32Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newFloat32Array"
+ type: "Float32Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newFloat32Array"
+ type: "Float32Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newFloat32Array"
+ type: "Float32Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newFloat32Array"
+ type: "Float32Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newFloat64Array"
+ type: "Float64Array*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newFloat64Array"
+ type: "Float64Array*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newFloat64Array"
+ type: "Float64Array*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newFloat64Array"
+ type: "Float64Array*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method {
+ name: "newUint8ClampedArray"
+ type: "Uint8ClampedArray*"
+ Parameter { name: "length"; type: "ulong" }
+ }
+ Method {
+ name: "newUint8ClampedArray"
+ type: "Uint8ClampedArray*"
+ Parameter { name: "array"; type: "TypedArray"; isPointer: true }
+ }
+ Method {
+ name: "newUint8ClampedArray"
+ type: "Uint8ClampedArray*"
+ Parameter { name: "array"; type: "QVariantList" }
+ }
+ Method {
+ name: "newUint8ClampedArray"
+ type: "Uint8ClampedArray*"
+ Parameter { name: "buffer"; type: "ArrayBuffer"; isPointer: true }
+ Parameter { name: "byteOffset"; type: "ulong" }
+ }
+ Method { name: "newTexImage"; type: "QTexImage3D*" }
+ }
+ Component {
+ name: "Uint16Array"
+ prototype: "TypedArray"
+ exports: ["QUint16Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "ushort"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "ushort" }
+ }
+ }
+ Component {
+ name: "Uint32Array"
+ prototype: "TypedArray"
+ exports: ["QUint32Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "uint"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "uint" }
+ }
+ }
+ Component {
+ name: "Uint8Array"
+ prototype: "TypedArray"
+ exports: ["QUint8Array 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "uchar"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "uchar" }
+ }
+ }
+ Component {
+ name: "Uint8ClampedArray"
+ prototype: "TypedArray"
+ exports: ["QUint8ClampedArray 1.0"]
+ isCreatable: false
+ exportMetaObjectRevisions: [0]
+ Method {
+ name: "get"
+ type: "uchar"
+ Parameter { name: "index"; type: "ulong" }
+ }
+ Method {
+ name: "set"
+ Parameter { name: "index"; type: "ulong" }
+ Parameter { name: "value"; type: "uchar" }
+ }
+ }
+}
diff --git a/src/renderbuffer3d.cpp b/src/renderbuffer3d.cpp
new file mode 100644
index 0000000..8f8b1ee
--- /dev/null
+++ b/src/renderbuffer3d.cpp
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "renderbuffer3d_p.h"
+
+/*!
+ * \qmltype RenderBuffer3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains an OpenGL renderbuffer.
+ *
+ * An uncreatable QML type that contains an OpenGL renderbuffer. You can get it by calling
+ * \l{Context3D::createRenderbuffer()}{Context3D.createRenderbuffer()} method.
+ */
+
+/*!
+ * \internal
+ */
+CanvasRenderBuffer::CanvasRenderBuffer(QObject *parent) :
+ QObject(parent)
+{
+ initializeOpenGLFunctions();
+ glGenRenderbuffers(1, &m_renderbufferId);
+}
+
+
+/*!
+ * \internal
+ */
+CanvasRenderBuffer::~CanvasRenderBuffer()
+{
+ del();
+}
+
+/*!
+ * \internal
+ */
+bool CanvasRenderBuffer::isAlive()
+{
+ return (m_renderbufferId);
+}
+
+/*!
+ * \internal
+ */
+void CanvasRenderBuffer::del()
+{
+ if (m_renderbufferId) {
+ glDeleteRenderbuffers(1, &m_renderbufferId);
+ m_renderbufferId = 0;
+ }
+}
+
+/*!
+ * \internal
+ */
+GLuint CanvasRenderBuffer::id()
+{
+ return m_renderbufferId;
+}
diff --git a/src/renderbuffer3d_p.h b/src/renderbuffer3d_p.h
new file mode 100644
index 0000000..5ce37e9
--- /dev/null
+++ b/src/renderbuffer3d_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef RENDERBUFFER3D_P_H
+#define RENDERBUFFER3D_P_H
+
+#include <QObject>
+#include <QOpenGLFunctions>
+
+class CanvasRenderBuffer : public QObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+public:
+ explicit CanvasRenderBuffer(QObject *parent = 0);
+ ~CanvasRenderBuffer();
+ bool isAlive();
+ void del();
+ GLuint id();
+
+private:
+ GLuint m_renderbufferId;
+};
+
+#endif // RENDERBUFFER3D_P_H
diff --git a/src/shader3d.cpp b/src/shader3d.cpp
new file mode 100644
index 0000000..1b2b990
--- /dev/null
+++ b/src/shader3d.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "shader3d_p.h"
+
+/*!
+ * \qmltype Shader3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a shader.
+ *
+ * An uncreatable QML type that contains a shader. You can get it by calling
+ * \l{Context3D::createShader()}{Context3D.createShader()} method.
+ */
+
+/*!
+ * \internal
+ */
+CanvasShader::CanvasShader(QOpenGLShader::ShaderType type, QObject *parent) :
+ QObject(parent),
+ m_shader(new QOpenGLShader(type, this)),
+ m_sourceCode("")
+{
+}
+
+/*!
+ * \internal
+ */
+CanvasShader::~CanvasShader()
+{
+ delete m_shader;
+}
+
+/*!
+ * \internal
+ */
+bool CanvasShader::isAlive()
+{
+ return bool(m_shader);
+}
+
+/*!
+ * \internal
+ */
+void CanvasShader::del()
+{
+ delete m_shader;
+ m_shader = 0;
+}
+
+/*!
+ * \internal
+ */
+QOpenGLShader *CanvasShader::qOGLShader()
+{
+ return m_shader;
+}
+
+/*!
+ * \internal
+ */
+QString CanvasShader::sourceCode()
+{
+ return m_sourceCode;
+}
+
+/*!
+ * \internal
+ */
+void CanvasShader::setSourceCode(const QString &source)
+{
+ m_sourceCode = source;
+}
diff --git a/src/shader3d_p.h b/src/shader3d_p.h
new file mode 100644
index 0000000..9e49a37
--- /dev/null
+++ b/src/shader3d_p.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SHADER3D_P_H
+#define SHADER3D_P_H
+
+#include "context3d_p.h"
+
+#include <QOpenGLShader>
+
+class CanvasShader : public QObject
+{
+ Q_OBJECT
+public:
+ explicit CanvasShader(QOpenGLShader::ShaderType type, QObject *parent = 0);
+ ~CanvasShader();
+
+ void del();
+ bool isAlive();
+ QOpenGLShader *qOGLShader();
+ QString sourceCode();
+ void setSourceCode(const QString &source);
+
+private:
+ QOpenGLShader *m_shader;
+ QOpenGLShader::ShaderType m_type;
+ QString m_sourceCode;
+};
+
+#endif // SHADER3D_P_H
diff --git a/src/shaderprecisionformat.cpp b/src/shaderprecisionformat.cpp
new file mode 100644
index 0000000..9b34f70
--- /dev/null
+++ b/src/shaderprecisionformat.cpp
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "shaderprecisionformat_p.h"
+
+/*!
+ * \qmltype ShaderPrecisionFormat
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains the shader precision format attributes.
+ *
+ * An uncreatable QML type that contains the information returned from the
+ * \l{Context3D::getShaderPrecisionFormat()} call.
+ *
+ * \sa Context3D, {QML Canvas 3D QML Types}
+ */
+
+/*!
+ * \internal
+ */
+CanvasShaderPrecisionFormat::CanvasShaderPrecisionFormat(QObject *parent) :
+ QObject(parent)
+{
+}
+
+/*!
+ * \fn inline void CanvasShaderPrecisionFormat::setRangeMin(int min)
+ * \internal
+ */
+
+/*!
+ * \fn inline void CanvasShaderPrecisionFormat::setRangeMax(int max)
+ * \internal
+ */
+
+/*!
+ * \fn inline void CanvasShaderPrecisionFormat::setPrecision(int precision)
+ * \internal
+ */
+
+/*!
+ * \qmlproperty int ShaderPrecisionFormat::rangeMin
+ * The base 2 log of the absolute value of the minimum value that can be represented.
+ */
+
+/*!
+ * \qmlproperty int ShaderPrecisionFormat::rangeMax
+ * The base 2 log of the absolute value of the maximum value that can be represented.
+ */
+
+/*!
+ * \qmlproperty int ShaderPrecisionFormat::precision
+ * The number of bits of precision that can be represented. 0 for integer formats.
+ */
diff --git a/src/shaderprecisionformat_p.h b/src/shaderprecisionformat_p.h
new file mode 100644
index 0000000..470c96b
--- /dev/null
+++ b/src/shaderprecisionformat_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef SHADERPRECISIONFORMAT_P_H
+#define SHADERPRECISIONFORMAT_P_H
+
+#include <QObject>
+
+class CanvasShaderPrecisionFormat : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int rangeMin READ rangeMin NOTIFY rangeMinChanged)
+ Q_PROPERTY(int rangeMax READ rangeMax NOTIFY rangeMaxChanged)
+ Q_PROPERTY(int precision READ precision NOTIFY precisionChanged)
+
+public:
+ explicit CanvasShaderPrecisionFormat(QObject *parent = 0);
+
+ inline void setRangeMin(int min) { m_rangeMin = min; }
+ inline void setRangeMax(int max) { m_rangeMax = max; }
+ inline void setPrecision(int precision) { m_precision = precision; }
+
+ inline int rangeMin() { return m_rangeMin; }
+ inline int rangeMax() { return m_rangeMax; }
+ inline int precision() { return m_precision; }
+
+signals:
+ void rangeMinChanged(int rangeMin);
+ void rangeMaxChanged(int rangeMax);
+ void precisionChanged(int precision);
+
+private:
+ int m_rangeMin;
+ int m_rangeMax;
+ int m_precision;
+};
+
+#endif // SHADERPRECISIONFORMAT_P_H
diff --git a/src/src.pro b/src/src.pro
new file mode 100644
index 0000000..e732825
--- /dev/null
+++ b/src/src.pro
@@ -0,0 +1,117 @@
+TEMPLATE = lib
+TARGET = qtcanvas3d
+QT += qml quick
+DEFINES += QTCANVAS3D_LIBRARY
+IMPORT_VERSION = $$MODULE_VERSION
+CONFIG += qt plugin
+
+#TARGET = $$qtLibraryTarget($$TARGET)
+message("TARGET")
+message($$TARGET)
+message("qtLibTARGET")
+message($$qtLibraryTarget($$TARGET))
+
+#TARGETPATH = com/digia/qtcanvas3d
+
+uri = com.digia.qtcanvas3d
+
+# Only build qml plugin static if Qt itself is also built static
+!contains(QT_CONFIG, static): CONFIG -= static staticlib
+
+QT.qtcanvas3d.name = QtCanvas3D
+#QT.qtcanvas3d.bins = $$QT_MODULE_INCLUDE_BASE
+QT.qtcanvas3d.sources = $$QT_MODULE_BASE/src
+
+QMAKE_DOCS = $$PWD/doc/qtcanvas3d.qdocconf
+
+load(qml_plugin)
+
+# Input
+SOURCES += qcanvas3d_plugin.cpp \
+ arraybuffer.cpp \
+ arraybufferview.cpp \
+ float32array.cpp \
+ uint8array.cpp \
+ uint16array.cpp \
+ int8array.cpp \
+ int16array.cpp \
+ int32array.cpp \
+ uint32array.cpp \
+ float64array.cpp \
+ typedarrayfactory.cpp \
+ typedarray.cpp \
+ arrayutils.cpp \
+ enumtostringmap.cpp \
+ uint8clampedarray.cpp \
+ abstractobject3d.cpp \
+ canvas3d.cpp \
+ buffer3d.cpp \
+ canvasrendernode.cpp \
+ context3d.cpp \
+ contextattributes.cpp \
+ contextextensions.cpp \
+ framebuffer3d.cpp \
+ program3d.cpp \
+ renderbuffer3d.cpp \
+ shader3d.cpp \
+ shaderprecisionformat.cpp \
+ teximage3d.cpp \
+ teximage3dloader.cpp \
+ texture3d.cpp \
+ uniformlocation.cpp
+
+HEADERS += qcanvas3d_plugin.h \
+ arraybuffer_p.h \
+ arraybufferview_p.h \
+ float32array_p.h \
+ uint8array_p.h \
+ uint16array_p.h \
+ int8array_p.h \
+ int16array_p.h \
+ int32array_p.h \
+ uint32array_p.h \
+ float64array_p.h \
+ typedarrayfactory_p.h \
+ typedarray_p.h \
+ arrayutils_p.h \
+ enumtostringmap_p.h \
+ uint8clampedarray_p.h \
+ abstractobject3d_p.h \
+ canvas3d_p.h \
+ buffer3d_p.h \
+ canvas3dcommon_p.h \
+ canvasrendernode_p.h \
+ context3d_p.h \
+ contextattributes_p.h \
+ contextextensions_p.h \
+ framebuffer3d_p.h \
+ program3d_p.h \
+ renderbuffer3d_p.h \
+ shader3d_p.h \
+ shaderprecisionformat_p.h \
+ teximage3d_p.h \
+ teximage3dloader_p.h \
+ texture3d_p.h \
+ uniformlocation_p.h
+
+OTHER_FILES = qmldir \
+ doc/* \
+ doc/src/* \
+ doc/images/* \
+ doc/snippets/* \
+ qtcanvas3d.qmltypes
+
+#!equals(_PRO_FILE_PWD_, $$OUT_PWD) {
+# copy_qmldir.target = $$OUT_PWD/qmldir
+# copy_qmldir.depends = $$_PRO_FILE_PWD_/qmldir
+# copy_qmldir.commands = $(COPY_FILE) \"$$replace(copy_qmldir.depends, /, $$QMAKE_DIR_SEP)\" \"$$replace(copy_qmldir.target, /, $$QMAKE_DIR_SEP)\"
+# QMAKE_EXTRA_TARGETS += copy_qmldir
+# PRE_TARGETDEPS += $$copy_qmldir.target
+#}
+
+qmldir.files = qmldir
+
+#installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
+#qmldir.path = $$installPath
+#target.path = $$installPath
+#INSTALLS += target qmldir
diff --git a/src/teximage3d.cpp b/src/teximage3d.cpp
new file mode 100644
index 0000000..feaa0cd
--- /dev/null
+++ b/src/teximage3d.cpp
@@ -0,0 +1,369 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "teximage3d_p.h"
+#include "canvas3dcommon_p.h"
+
+#include <QJSValueIterator>
+
+/*!
+ * \qmltype TextureImage
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a texture image.
+ *
+ * An uncreatable QML type that contains a texture image created by calling
+ * TextureImageLoader::loadImage().
+ *
+ * \sa TextureImageLoader
+ */
+
+/*!
+ * \internal
+ */
+CanvasTextureImage::CanvasTextureImage(QObject *parent) :
+ CanvasAbstractObject(parent),
+ m_requestId(0),
+ m_state(INITIALIZED),
+ m_errorString(""),
+ m_pixelCache(0),
+ m_pixelCacheFormat(CanvasContext::NONE)
+{
+ m_networkAccessManager = new QNetworkAccessManager(this);
+ QObject::connect(m_networkAccessManager, &QNetworkAccessManager::finished,
+ this, &CanvasTextureImage::handleReply);
+}
+
+/*!
+ * \internal
+ */
+CanvasTextureImage::~CanvasTextureImage()
+{
+ delete m_networkAccessManager;
+ delete m_pixelCache;
+}
+
+/*!
+ * \qmlproperty url TextureImage::source()
+ * Contains the url to the image.
+ */
+/*!
+ * \internal
+ */
+const QUrl &CanvasTextureImage::source() const
+{
+ return m_source;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::setSource(const QUrl &url)
+{
+ if (url == m_source)
+ return;
+
+ m_source = url;
+ emit sourceChanged(m_source);
+
+ load();
+}
+
+/*!
+ * \qmlmethod int TextureImage::id()
+ * Contains the object id.
+ */
+/*!
+ * \internal
+ */
+ulong CanvasTextureImage::id()
+{
+ return ulong(this);
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::load()
+{
+ if (m_source.isEmpty()) {
+ QByteArray array;
+ m_image.loadFromData(array);
+ m_glImage = m_image.convertToFormat(QImage::Format_RGBA8888);
+ setImageState(LOADING_FINISHED);
+ return;
+ }
+
+ if (m_state == LOADING)
+ return;
+
+ setImageState(LOADING);
+ QNetworkRequest request(m_source);
+ m_networkAccessManager->get(request);
+}
+
+/*!
+ * \qmlproperty string TextureImage::errorString()
+ * Contains the error string if an error happened during image creation.
+ */
+/*!
+ * \internal
+ */
+QString CanvasTextureImage::errorString() const
+{
+ return m_errorString;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::handleReply(QNetworkReply *reply)
+{
+ if (reply->error() != QNetworkReply::NoError) {
+ setImageState(LOADING_ERROR);
+ m_errorString = reply->errorString();
+ emit errorStringChanged(m_errorString);
+ return;
+ }
+
+ m_image.loadFromData(reply->readAll());
+ m_image = m_image.mirrored(false, true);
+ m_glImage = m_image.convertToFormat(QImage::Format_RGBA8888);
+
+ setImageState(LOADING_FINISHED);
+}
+
+/*!
+ * \internal
+ */
+QImage & CanvasTextureImage::getImage()
+{
+ return m_image;
+}
+
+/*!
+ * \internal
+ */
+uchar *CanvasTextureImage::getImageData()
+{
+ return m_image.bits();
+}
+
+/*!
+ * \internal
+ */
+QVariant *CanvasTextureImage::anything()
+{
+ return m_anyValue;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::setAnything(QVariant *value)
+{
+ if (m_anyValue == value)
+ return;
+ m_anyValue = value;
+ emit anythingChanged(value);
+}
+
+/*!
+ * \qmlproperty TextureImageState TextureImage::imageState()
+ * Contains the texture image state. It is one of \c{TextureImage.INITIALIZED},
+ * \c{TextureImage.LOAD_PENDING}, \c{TextureImage.LOADING}, \c{TextureImage.LOADING_FINISHED} or
+ * \c{TextureImage.LOADING_ERROR}.
+ */
+/*!
+ * \internal
+ */
+CanvasTextureImage::TextureImageState CanvasTextureImage::imageState()
+{
+ return m_state;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::setImageState(TextureImageState state)
+{
+ if (state == m_state)
+ return;
+ m_state = state;
+ emit imageStateChanged(state);
+}
+
+/*!
+ * \qmlproperty int TextureImage::width()
+ * Contains the texture image width.
+ */
+/*!
+ * \internal
+ */
+int CanvasTextureImage::width()
+{
+ if (m_state != LOADING_FINISHED)
+ return 0;
+
+ return m_image.width();
+}
+
+/*!
+ * \qmlproperty int TextureImage::height()
+ * Contains the texture image height.
+ */
+/*!
+ * \internal
+ */
+int CanvasTextureImage::height()
+{
+ if (m_state != LOADING_FINISHED)
+ return 0;
+
+ return m_image.height();
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::emitImageLoadedSGRT()
+{
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImage::emitImageLoadingErrorSGRT()
+{
+}
+
+/*!
+ * \internal
+ */
+void *CanvasTextureImage::convertToFormat(CanvasContext::glEnums format)
+{
+ if (m_pixelCacheFormat == format)
+ return m_pixelCache;
+
+ uchar *origPixels = m_glImage.bits();
+ int width = m_glImage.width();
+ int height = m_glImage.height();
+
+ switch (format) {
+ case CanvasContext::UNSIGNED_BYTE: {
+ return origPixels;
+ break;
+ }
+ case CanvasContext::UNSIGNED_SHORT_5_6_5: {
+ delete m_pixelCache;
+ m_pixelCache = 0;
+ m_pixelCacheFormat = CanvasContext::NONE;
+ ushort *pixels = new ushort[width * height];
+ ushort pixel;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int srcIdx = y * width * 4 + x * 4;
+ pixel = ((origPixels[srcIdx++] >> 3) & 0x1F) << 11;
+ pixel |= ((origPixels[srcIdx++] >> 2) & 0x3F) << 5;
+ pixel |= ((origPixels[srcIdx++] >> 3) & 0x1F) << 0;
+ pixels[y * width + x] = pixel;
+ }
+ }
+ m_pixelCacheFormat = CanvasContext::UNSIGNED_SHORT_5_6_5;
+ m_pixelCache = (uchar *)pixels;
+ return m_pixelCache;
+ }
+ case CanvasContext::UNSIGNED_SHORT_4_4_4_4: {
+ delete m_pixelCache;
+ m_pixelCache = 0;
+ m_pixelCacheFormat = CanvasContext::NONE;
+ ushort *pixels = new ushort[width * height];
+ ushort pixel;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int srcIdx = y * width * 4 + x * 4;
+ pixel = ((origPixels[srcIdx++] >> 4) & 0x0F) << 12;
+ pixel |= ((origPixels[srcIdx++] >> 4) & 0x0F) << 8;
+ pixel |= ((origPixels[srcIdx++] >> 4) & 0x0F) << 4;
+ pixel |= ((origPixels[srcIdx++] >> 4) & 0x0F) << 0;
+ pixels[y * width + x] = pixel;
+ }
+ }
+ m_pixelCacheFormat = CanvasContext::UNSIGNED_SHORT_4_4_4_4;
+ m_pixelCache = (uchar *)pixels;
+ return m_pixelCache;
+ }
+ case CanvasContext::UNSIGNED_SHORT_5_5_5_1: {
+ delete m_pixelCache;
+ m_pixelCache = 0;
+ m_pixelCacheFormat = CanvasContext::NONE;
+ ushort *pixels = new ushort[width * height];
+ ushort pixel;
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ int srcIdx = y * width * 4 + x * 4;
+ pixel = ((origPixels[srcIdx++] >> 3) & 0x1F) << 11;
+ pixel |= ((origPixels[srcIdx++] >> 3) & 0x1F) << 6;
+ pixel |= ((origPixels[srcIdx++] >> 3) & 0x1F) << 1;
+ pixel |= ((origPixels[srcIdx++] >> 7) & 0x01) << 0;
+ pixels[y * width + x] = pixel;
+ }
+ }
+ m_pixelCacheFormat = CanvasContext::UNSIGNED_SHORT_5_5_5_1;
+ m_pixelCache = (uchar *)pixels;
+ return m_pixelCache;
+ }
+ default: {
+ qDebug() << "TexImage3D::" << __FUNCTION__ << ":INVALID_ENUM Invalid type enum";
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasTextureImage *texImage)
+{
+ if (texImage)
+ dbg.nospace() << "TexImage3D("<< ((void*) texImage) << texImage->m_name << ")";
+ else
+ dbg.nospace() << "TexImage3D("<< ((void*) texImage) <<")";
+ return dbg.maybeSpace();
+}
+
diff --git a/src/teximage3d_p.h b/src/teximage3d_p.h
new file mode 100644
index 0000000..f6f2d64
--- /dev/null
+++ b/src/teximage3d_p.h
@@ -0,0 +1,128 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef TEXIMAGE3D_P_H
+#define TEXIMAGE3D_P_H
+
+#include "context3d_p.h"
+#include "abstractobject3d_p.h"
+
+#include <QUrl>
+#include <QNetworkAccessManager>
+#include <QImage>
+#include <QNetworkReply>
+
+class CanvasTextureImage : public CanvasAbstractObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CanvasTextureImage)
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(TextureImageState imageState READ imageState NOTIFY imageStateChanged)
+ Q_PROPERTY(int width READ width NOTIFY widthChanged)
+ Q_PROPERTY(int height READ height NOTIFY heightChanged)
+ Q_PROPERTY(QString errorString READ errorString NOTIFY errorStringChanged)
+ Q_ENUMS(TextureImageState)
+
+public:
+ enum TextureImageState {
+ INITIALIZED = 0,
+ LOAD_PENDING,
+ LOADING,
+ LOADING_FINISHED,
+ LOADING_ERROR
+ };
+
+ explicit CanvasTextureImage(QObject *parent = 0);
+ virtual ~CanvasTextureImage();
+
+ Q_INVOKABLE ulong id();
+
+ QVariant *anything();
+ void setAnything(QVariant *value);
+
+ const QUrl &source() const;
+ void setSource(const QUrl &src);
+ TextureImageState imageState();
+ int width();
+ int height();
+ QString errorString() const;
+
+ void load();
+ void handleReply(QNetworkReply *reply);
+ QImage &getImage();
+ uchar *getImageData();
+ void *convertToFormat(CanvasContext::glEnums format);
+
+ void emitImageLoadedSGRT();
+ void emitImageLoadingErrorSGRT();
+
+ friend QDebug operator<< (QDebug d, const CanvasTextureImage *buffer);
+
+private:
+ void setImageState(TextureImageState state);
+
+signals:
+ void sourceChanged(QUrl source);
+ void imageStateChanged(TextureImageState state);
+ void widthChanged(int width);
+ void heightChanged(int height);
+ void errorStringChanged(const QString errorString);
+ void anythingChanged(QVariant *value);
+
+private:
+ QNetworkAccessManager *m_networkAccessManager;
+ int m_requestId;
+ QImage m_image;
+ QUrl m_source;
+ TextureImageState m_state;
+ QString m_errorString;
+ uchar *m_pixelCache;
+ CanvasContext::glEnums m_pixelCacheFormat;
+ QImage m_glImage;
+ QVariant *m_anyValue;
+};
+
+#endif // TEXIMAGE3D_P_H
diff --git a/src/teximage3dloader.cpp b/src/teximage3dloader.cpp
new file mode 100644
index 0000000..f2d3b89
--- /dev/null
+++ b/src/teximage3dloader.cpp
@@ -0,0 +1,209 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "teximage3dloader_p.h"
+#include "canvas3d_p.h"
+#include "canvas3dcommon_p.h"
+
+/*!
+ * \qmltype TextureImageLoader
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Texture image loader.
+ *
+ * Texture image loader that allows loading of 2D images to be used as input of Context3D
+ * texture upload calls.
+ *
+ * \sa Context3D, TextureImage, {QML Canvas 3D QML Types}
+ */
+
+/*!
+ * \internal
+ */
+CanvasTextureImageLoader::CanvasTextureImageLoader(QObject *parent) :
+ QObject(parent),
+ m_logAllCalls(false),
+ m_logAllErrors(true)
+{
+}
+
+/*!
+ * \internal
+ */
+CanvasTextureImageLoader::~CanvasTextureImageLoader()
+{
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageLoader::setLogAllCalls(bool logCalls)
+{
+ if (m_logAllCalls != logCalls) {
+ m_logAllCalls = logCalls;
+ emit logAllCallsChanged(logCalls);
+ }
+}
+
+/*!
+ * \qmlproperty bool TextureImageLoader::logAllCalls
+ * Specifies if all TextureImageLoader method calls (including internal ones) are logged to the
+ * console.
+ * Defaults to \c{false}.
+ */
+/*!
+ * \internal
+ */
+bool CanvasTextureImageLoader::logAllCalls() const
+{
+ return m_logAllCalls;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageLoader::setLogAllErrors(bool logErrors)
+{
+ if (m_logAllErrors != logErrors) {
+ m_logAllErrors = logErrors;
+ emit logAllErrorsChanged(logErrors);
+ }
+}
+
+/*!
+ * \qmlproperty bool TextureImageLoader::logAllErrors
+ * Specifies if all TextureImageLoader errors are logged to the console. Defaults to \c{true}.
+ */
+/*!
+ * \internal
+ */
+bool CanvasTextureImageLoader::logAllErrors() const
+{
+ return m_logAllErrors;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageLoader::emitImageLoaded(CanvasTextureImage *textureImage)
+{
+ // Can't use signals as those change the signal processing to main thread
+ // Using invokeMethod() preserves execution on scene graph render thread.
+ if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__;
+ QVariant ignoredReturnedValue;
+ QMetaObject::invokeMethod(this, "imageLoaded",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, ignoredReturnedValue),
+ Q_ARG(QVariant, QVariant::fromValue(textureImage)));
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageLoader::emitImageLoadingError(CanvasTextureImage *textureImage)
+{
+ // Can't use signals as those change the signal processing to main thread
+ // Using invokeMethod() preserves execution on scene graph render thread.
+ if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__;
+ QVariant ignoredReturnedValue;
+ QMetaObject::invokeMethod(this, "imageLoadingError",
+ Qt::DirectConnection,
+ Q_RETURN_ARG(QVariant, ignoredReturnedValue),
+ Q_ARG(QVariant, QVariant::fromValue(textureImage)));
+}
+
+/*!
+ * \qmlmethod TextureImage TextureImageLoader::loadImage(url url)
+ * Loads an image located in \a url and creates a TextureImage of it.
+ */
+/*!
+ * \internal
+ */
+CanvasTextureImage *CanvasTextureImageLoader::loadImage(const QUrl &url)
+{
+ if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << "(url:" << url << ")";
+
+ if (!m_canvas && m_logAllErrors) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << ": ERROR tried to load image before setting as property of a canvas.";
+
+ CanvasContext *context = m_canvas->context();
+ if (!context) {
+ if (m_logAllErrors) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << ": ERROR tried to load image before GL context was created.";
+ return 0;
+ }
+
+ CanvasTextureImage *img;
+ if (m_urlToImageMap.contains(url) && m_urlToImageMap.values(url).size() != 0) {
+ img = m_urlToImageMap[url];
+ } else {
+ img = new CanvasTextureImage(context);
+ m_urlToImageMap[url] = img;
+ m_loadingImagesList << img;
+ img->setSource(url);
+ }
+
+ return img;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageLoader::setCanvas(Canvas *canvas)
+{
+ m_canvas = canvas;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTextureImageLoader::notifyLoadedImages()
+{
+ if (!m_loadingImagesList.size())
+ return;
+
+ if (m_logAllCalls) qDebug() << "TexImage3DLoader::" << __FUNCTION__ << "(m_loadingImagesList.size():"<<m_loadingImagesList.size()<<")";
+
+ QMutableListIterator<CanvasTextureImage *> it(m_loadingImagesList);
+ while (it.hasNext()) {
+ CanvasTextureImage *loader = it.next();
+ if (loader->imageState() == CanvasTextureImage::LOADING_FINISHED) {
+ m_loadingImagesList.removeOne(loader);
+ emitImageLoaded(loader);
+ } else if (loader->imageState() == CanvasTextureImage::LOADING_ERROR) {
+ m_loadingImagesList.removeOne(loader);
+ emitImageLoadingError(loader);
+ }
+ }
+}
diff --git a/src/teximage3dloader_p.h b/src/teximage3dloader_p.h
new file mode 100644
index 0000000..d056963
--- /dev/null
+++ b/src/teximage3dloader_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef TEXIMAGE3DLOADER_P_H
+#define TEXIMAGE3DLOADER_P_H
+
+#include "teximage3d_p.h"
+
+class Canvas;
+
+class CanvasTextureImageLoader : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool logAllCalls READ logAllCalls WRITE setLogAllCalls NOTIFY logAllCallsChanged)
+ Q_PROPERTY(bool logAllErrors READ logAllErrors WRITE setLogAllErrors NOTIFY logAllErrorsChanged)
+
+public:
+ explicit CanvasTextureImageLoader(QObject *parent = 0);
+ virtual ~CanvasTextureImageLoader();
+
+ Q_INVOKABLE CanvasTextureImage *loadImage(const QUrl &url);
+
+ void setLogAllCalls(bool logCalls);
+ bool logAllCalls() const;
+ void setLogAllErrors(bool logErrors);
+ bool logAllErrors() const;
+ void setCanvas(Canvas *canvas);
+ void notifyLoadedImages();
+ void emitImageLoaded(CanvasTextureImage *textureImage);
+ void emitImageLoadingError(CanvasTextureImage *textureImage);
+
+signals:
+ void logAllCallsChanged(bool logCalls);
+ void logAllErrorsChanged(bool logErrors);
+
+private:
+ bool m_logAllCalls;
+ bool m_logAllErrors;
+ QMap<QUrl, CanvasTextureImage *> m_urlToImageMap;
+ QList<CanvasTextureImage *> m_loadingImagesList;
+ Canvas *m_canvas;
+};
+
+#endif // TEXIMAGE3DLOADER_P_H
diff --git a/src/texture3d.cpp b/src/texture3d.cpp
new file mode 100644
index 0000000..e11558f
--- /dev/null
+++ b/src/texture3d.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "texture3d_p.h"
+
+/*!
+ * \qmltype Texture3D
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains an OpenGL texture.
+ *
+ * An uncreatable QML type that contains an OpenGL texture. You can get it by calling
+ * \l{Context3D::createTexture()}{Context3D.createTexture()} method.
+ */
+
+/*!
+ * \internal
+ */
+CanvasTexture::CanvasTexture(QObject *parent) :
+ CanvasAbstractObject(parent),
+ m_textureId(0),
+ m_isAlive(true)
+{
+ initializeOpenGLFunctions();
+ glGenTextures(1, &m_textureId);
+}
+
+/*!
+ * \internal
+ */
+CanvasTexture::~CanvasTexture()
+{
+ if (m_textureId)
+ glDeleteTextures(1, &m_textureId);
+}
+
+/*!
+ * \internal
+ */
+void CanvasTexture::bind(CanvasContext::glEnums target)
+{
+ if (!m_textureId)
+ return;
+
+ glBindTexture(GLenum(target), m_textureId);
+}
+
+/*!
+ * \internal
+ */
+GLuint CanvasTexture::textureId()
+{
+ if (!m_isAlive)
+ return 0;
+
+ return m_textureId;
+}
+
+/*!
+ * \internal
+ */
+bool CanvasTexture::isAlive()
+{
+ return bool(m_textureId);
+}
+
+/*!
+ * \internal
+ */
+void CanvasTexture::del()
+{
+ if (m_textureId)
+ glDeleteTextures(1, &m_textureId);
+ m_textureId = 0;
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasTexture *texture)
+{
+ if (texture)
+ dbg.nospace() << "Texture3D("<< ((void*) texture) << texture->m_name << ")";
+ else
+ dbg.nospace() << "Texture3D("<< ((void*) texture) <<")";
+ return dbg.maybeSpace();
+}
diff --git a/src/texture3d_p.h b/src/texture3d_p.h
new file mode 100644
index 0000000..6c821b1
--- /dev/null
+++ b/src/texture3d_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef TEXTURE3D_P_H
+#define TEXTURE3D_P_H
+
+#include "context3d_p.h"
+#include "abstractobject3d_p.h"
+
+#include <QtGui/QOpenGLTexture>
+#include <QtGui/QOpenGLFunctions>
+
+class CanvasTexture : public CanvasAbstractObject, protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasTexture(QObject *parent = 0);
+ ~CanvasTexture();
+
+ void bind(CanvasContext::glEnums target);
+
+ void del();
+ bool isAlive();
+ GLuint textureId();
+
+ friend QDebug operator<< (QDebug d, const CanvasTexture *texture);
+
+ GLuint m_textureId;
+ bool m_isAlive;
+};
+
+#endif // TEXTURE3D_P_H
diff --git a/src/typedarray.cpp b/src/typedarray.cpp
new file mode 100644
index 0000000..119aca0
--- /dev/null
+++ b/src/typedarray.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "typedarray_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype TypedArray
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array.
+ *
+ * An uncreatable QML type that contains a typed array.
+ * Use Arrays for creating an array of required type.
+ *
+ * \sa Arrays, Float32Array, Float64Array, Int8Array, Int16Array, Int32Array, Uint8Array,
+ * Uint16Array, Uint32Array, Uint8ClampedArray
+ */
+
+/*!
+ * \fn virtual inline int CanvasTypedArray::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasTypedArray::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasTypedArray::CanvasTypedArray(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent):
+ CanvasArrayBufferView(buffer, byteOffset, parent),
+ m_length(0)
+{
+}
+
+/*!
+ * \internal
+ */
+CanvasTypedArray::~CanvasTypedArray()
+{
+}
+
+/*!
+ * \qmlmethod int TypedArray::length()
+ * Holds the length of the array.
+ */
+/*!
+ * \internal
+ */
+unsigned long CanvasTypedArray::length() const
+{
+ return m_length;
+}
+
+/*!
+ * \internal
+ */
+void CanvasTypedArray::copyFrom(const CanvasArrayBuffer &array)
+{
+ m_buffer->copyRawDataFrom(array.m_rawData, array.byteLength());
+}
+
+/*!
+ * \internal
+ */
+void CanvasTypedArray::setLength(unsigned long length)
+{
+ if (length == m_length)
+ return;
+
+ m_length = length;
+ emit lengthChanged(length);
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasTypedArray *array)
+{
+ if (array)
+ dbg.nospace() << "TypedArray ("<< array->m_name <<", length:" << array->length() << ")";
+ else
+ dbg.nospace() << "TypedArray (null)";
+ return dbg.maybeSpace();
+}
diff --git a/src/typedarray_p.h b/src/typedarray_p.h
new file mode 100644
index 0000000..cc1157b
--- /dev/null
+++ b/src/typedarray_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef TYPEDARRAY_P_H
+#define TYPEDARRAY_P_H
+
+#include "arraybufferview_p.h"
+
+class CanvasArrayBuffer;
+
+class CanvasTypedArray : public CanvasArrayBufferView
+{
+ Q_OBJECT
+ Q_PROPERTY(unsigned long length READ length NOTIFY lengthChanged)
+
+public:
+ explicit CanvasTypedArray(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+ virtual ~CanvasTypedArray();
+
+ void copyFrom(const CanvasArrayBuffer &array);
+
+ unsigned long length() const;
+ virtual int bytesPerElement() = 0 ;
+ virtual CanvasContext::glEnums dataType() = 0;
+
+ friend QDebug operator<< (QDebug dbg, const CanvasTypedArray *array);
+
+signals:
+ void lengthChanged(unsigned long length);
+
+protected:
+ void setLength(unsigned long length);
+
+private:
+ unsigned long m_length;
+};
+
+#endif // TYPEDARRAY_P_H
diff --git a/src/typedarrayfactory.cpp b/src/typedarrayfactory.cpp
new file mode 100644
index 0000000..78e7a4d
--- /dev/null
+++ b/src/typedarrayfactory.cpp
@@ -0,0 +1,589 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "typedarrayfactory_p.h"
+#include "arraybuffer_p.h"
+#include "int8array_p.h"
+#include "uint8array_p.h"
+#include "int16array_p.h"
+#include "uint16array_p.h"
+#include "int32array_p.h"
+#include "uint32array_p.h"
+#include "float32array_p.h"
+#include "float64array_p.h"
+#include "uint8clampedarray_p.h"
+#include "canvas3dcommon_p.h"
+#include "teximage3d_p.h"
+
+#include <QDebug>
+
+/*!
+ * \qmltype Arrays
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Create typed arrays.
+ *
+ * This QML type can be used for creating typed arrays of required type.
+ *
+ * \sa Float32Array, Float64Array, Int8Array, Int16Array, Int32Array, Uint8Array,
+ * Uint16Array, Uint32Array, Uint8ClampedArray
+ */
+
+/*!
+ * \internal
+ */
+QObject *CanvasTypedArrayFactory::type_array_factory_provider(QQmlEngine *engine,
+ QJSEngine *scriptEngine)
+{
+ Q_UNUSED(engine)
+ Q_UNUSED(scriptEngine)
+
+ return new CanvasTypedArrayFactory();
+}
+
+/*!
+ * \internal
+ */
+CanvasTypedArrayFactory::CanvasTypedArrayFactory(QObject *parent) :
+ QObject(parent)
+{
+}
+
+/*!
+ * \internal
+ */
+CanvasTypedArrayFactory::~CanvasTypedArrayFactory()
+{
+}
+
+/* Typed array creation functions. Typed arrays should be in the V4VM implementation.*/
+
+/*!
+ * \qmlmethod Int8Array Arrays::newInt8Array(int length)
+ * Returns a new Int8Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasInt8Array *CanvasTypedArrayFactory::newInt8Array(unsigned long length)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<")";
+ return new CanvasInt8Array(length);
+}
+
+/*!
+ * \qmlmethod Int8Array Arrays::newInt8Array(TypedArray array)
+ * Returns a new Int8Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasInt8Array *CanvasTypedArrayFactory::newInt8Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasInt8Array(array);
+}
+
+/*!
+ * \qmlmethod Int8Array Arrays::newInt8Array(list<variant> array)
+ * Returns a new Int8Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasInt8Array *CanvasTypedArrayFactory::newInt8Array(QVariantList array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return new CanvasInt8Array(&array);
+}
+
+/*!
+ * \qmlmethod Int8Array Arrays::newInt8Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Int8Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasInt8Array *CanvasTypedArrayFactory::newInt8Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer buffer, unsigned long byteOffset)";
+ return new CanvasInt8Array(buffer, byteOffset);
+}
+
+/*!
+ * \qmlmethod Uint8Array Arrays::newUint8Array(int length)
+ * Returns a new Uint8Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8Array *CanvasTypedArrayFactory::newUint8Array(unsigned long length)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<")";
+ return new CanvasUint8Array(length);
+}
+
+/*!
+ * \qmlmethod Uint8Array Arrays::newUint8Array(TypedArray array)
+ * Returns a new Uint8Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8Array *CanvasTypedArrayFactory::newUint8Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasUint8Array(array);
+}
+
+/*!
+ * \qmlmethod Uint8Array Arrays::newUint8Array(list<variant> array)
+ * Returns a new Uint8Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8Array *CanvasTypedArrayFactory::newUint8Array(QVariantList array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return new CanvasUint8Array(&array);
+}
+
+/*!
+ * \qmlmethod Uint8Array Arrays::newUint8Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Uint8Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8Array *CanvasTypedArrayFactory::newUint8Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer buffer, unsigned long byteOffset)";
+ return new CanvasUint8Array(buffer, byteOffset);
+}
+
+/*!
+ * \qmlmethod Int16Array Arrays::newInt16Array(int length)
+ * Returns a new Int16Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasInt16Array *CanvasTypedArrayFactory::newInt16Array(unsigned long length)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<")";
+ return new CanvasInt16Array(length);
+}
+
+/*!
+ * \qmlmethod Int16Array Arrays::newInt16Array(TypedArray array)
+ * Returns a new Int16Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasInt16Array *CanvasTypedArrayFactory::newInt16Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasInt16Array(array);
+}
+
+/*!
+ * \qmlmethod Int16Array Arrays::newInt16Array(list<variant> array)
+ * Returns a new Int16Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasInt16Array *CanvasTypedArrayFactory::newInt16Array(QVariantList array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return new CanvasInt16Array(&array);
+}
+
+/*!
+ * \qmlmethod Int16Array Arrays::newInt16Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Int16Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasInt16Array *CanvasTypedArrayFactory::newInt16Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer buffer, unsigned long byteOffset)";
+ return new CanvasInt16Array(buffer, byteOffset);
+}
+
+/*!
+ * \qmlmethod Uint16Array Arrays::newUint16Array(int length)
+ * Returns a new Uint16Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasUint16Array *CanvasTypedArrayFactory::newUint16Array(unsigned long length)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<")";
+ return new CanvasUint16Array(length);
+}
+
+/*!
+ * \qmlmethod Uint16Array Arrays::newUint16Array(TypedArray array)
+ * Returns a new Uint16Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint16Array *CanvasTypedArrayFactory::newUint16Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasUint16Array(array);
+}
+
+/*!
+ * \qmlmethod Uint16Array Arrays::newUint16Array(list<variant> array)
+ * Returns a new Uint16Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint16Array *CanvasTypedArrayFactory::newUint16Array(QVariantList array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return new CanvasUint16Array(&array);
+}
+
+/*!
+ * \qmlmethod Uint16Array Arrays::newUint16Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Uint16Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasUint16Array *CanvasTypedArrayFactory::newUint16Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer buffer, unsigned long byteOffset)";
+ return new CanvasUint16Array(buffer, byteOffset);
+}
+
+/*!
+ * \qmlmethod Int32Array Arrays::newInt32Array(int length)
+ * Returns a new Int32Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasInt32Array *CanvasTypedArrayFactory::newInt32Array(unsigned long length)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<")";
+ return new CanvasInt32Array(length);
+}
+
+/*!
+ * \qmlmethod Int32Array Arrays::newInt32Array(TypedArray array)
+ * Returns a new Int32Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasInt32Array *CanvasTypedArrayFactory::newInt32Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasInt32Array(array);
+}
+
+/*!
+ * \qmlmethod Int32Array Arrays::newInt32Array(list<variant> array)
+ * Returns a new Int32Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasInt32Array *CanvasTypedArrayFactory::newInt32Array(QVariantList array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return new CanvasInt32Array(&array);
+}
+
+/*!
+ * \qmlmethod Int32Array Arrays::newInt32Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Int32Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasInt32Array *CanvasTypedArrayFactory::newInt32Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer buffer, unsigned long byteOffset)";
+ return new CanvasInt32Array(buffer, byteOffset);
+}
+
+/*!
+ * \qmlmethod Uint32Array Arrays::newUint32Array(int length)
+ * Returns a new Uint32Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasUint32Array *CanvasTypedArrayFactory::newUint32Array(unsigned long length)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<")";
+ return new CanvasUint32Array(length);
+}
+
+/*!
+ * \qmlmethod Uint32Array Arrays::newUint32Array(TypedArray array)
+ * Returns a new Uint32Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint32Array *CanvasTypedArrayFactory::newUint32Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasUint32Array(array);
+}
+
+/*!
+ * \qmlmethod Uint32Array Arrays::newUint32Array(list<variant> array)
+ * Returns a new Uint32Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint32Array *CanvasTypedArrayFactory::newUint32Array(QVariantList array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return new CanvasUint32Array(&array);
+}
+
+/*!
+ * \qmlmethod Uint32Array Arrays::newUint32Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Uint32Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasUint32Array *CanvasTypedArrayFactory::newUint32Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer buffer, unsigned long byteOffset)";
+ return new CanvasUint32Array(buffer, byteOffset);
+}
+
+/*!
+ * \qmlmethod Float32Array Arrays::newFloat32Array(int length)
+ * Returns a new Float32Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat32Array *CanvasTypedArrayFactory::newFloat32Array(unsigned long length)
+{
+ CanvasFloat32Array *newArray = new CanvasFloat32Array(length);
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<"):" << newArray;
+ return newArray;
+}
+
+/*!
+ * \qmlmethod Float32Array Arrays::newFloat32Array(TypedArray array)
+ * Returns a new Float32Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat32Array *CanvasTypedArrayFactory::newFloat32Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasFloat32Array(array);
+}
+
+/*!
+ * \qmlmethod Float32Array Arrays::newFloat32Array(list<variant> array)
+ * Returns a new Float32Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat32Array *CanvasTypedArrayFactory::newFloat32Array(QVariantList array)
+{
+ CanvasFloat32Array *newArray = new CanvasFloat32Array(&array);
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return newArray;
+}
+
+/*!
+ * \qmlmethod Float32Array Arrays::newFloat32Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Float32Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat32Array *CanvasTypedArrayFactory::newFloat32Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ CanvasFloat32Array *newArray = new CanvasFloat32Array(buffer, byteOffset);
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer "<<buffer<<", unsigned long "<<byteOffset<<"):"<<newArray;
+ return newArray;
+}
+
+/*!
+ * \qmlmethod Float64Array Arrays::newFloat64Array(int length)
+ * Returns a new Float64Array of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat64Array *CanvasTypedArrayFactory::newFloat64Array(unsigned long length)
+{
+ CanvasFloat64Array *newArray = new CanvasFloat64Array(length);
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<"):" << newArray;
+ return newArray;
+}
+
+/*!
+ * \qmlmethod Float64Array Arrays::newFloat64Array(TypedArray array)
+ * Returns a new Float64Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat64Array *CanvasTypedArrayFactory::newFloat64Array(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasFloat64Array(array);
+}
+
+/*!
+ * \qmlmethod Float64Array Arrays::newFloat64Array(list<variant> array)
+ * Returns a new Float64Array with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat64Array *CanvasTypedArrayFactory::newFloat64Array(QVariantList array)
+{
+ CanvasFloat64Array * newArray = new CanvasFloat64Array(&array);
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return newArray;
+}
+
+/*!
+ * \qmlmethod Float64Array Arrays::newFloat64Array(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Float64Array with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasFloat64Array *CanvasTypedArrayFactory::newFloat64Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ CanvasFloat64Array *newArray = new CanvasFloat64Array(buffer, byteOffset);
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer "<<buffer<<", unsigned long "<<byteOffset<<"):"<<newArray;
+ return newArray;
+}
+
+/*!
+ * \qmlmethod Uint8ClampedArray Arrays::newUint8ClampedArray(int length)
+ * Returns a new Uint8ClampedArray of \a length.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray *CanvasTypedArrayFactory::newUint8ClampedArray(unsigned long length)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(unsigned long "<<length<<")";
+ return new CanvasUint8ClampedArray(length);
+}
+
+/*!
+ * \qmlmethod Uint8ClampedArray Arrays::newUint8ClampedArray(TypedArray array)
+ * Returns a new Uint8ClampedArray with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray *CanvasTypedArrayFactory::newUint8ClampedArray(CanvasTypedArray *array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(TypedArray " << array << ")";
+ return new CanvasUint8ClampedArray(array);
+}
+
+/*!
+ * \qmlmethod Uint8ClampedArray Arrays::newUint8ClampedArray(list<variant> array)
+ * Returns a new Uint8ClampedArray with data from \a array.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray *CanvasTypedArrayFactory::newUint8ClampedArray(QVariantList array)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(QVariantList" << array.count() << ")";
+ return new CanvasUint8ClampedArray(&array);
+}
+
+/*!
+ * \qmlmethod Uint8ClampedArray Arrays::newUint8ClampedArray(ArrayBuffer buffer, int byteOffset)
+ * Returns a new Uint8ClampedArray with data from \a buffer starting from \a byteOffset.
+ */
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray *CanvasTypedArrayFactory::newUint8ClampedArray(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset)
+{
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "(ArrayBuffer buffer, unsigned long byteOffset)";
+ return new CanvasUint8ClampedArray(buffer, byteOffset);
+}
+
+/*!
+ * \qmlmethod TextureImage Arrays::newTexImage()
+ * Returns a new empty TextureImage.
+ */
+/*!
+ * \internal
+ */
+CanvasTextureImage *CanvasTypedArrayFactory::newTexImage()
+{
+ CanvasTextureImage *newImg = new CanvasTextureImage();
+ if (VERBOSE_ALL_TYPED_ARRAY_CALLS) qDebug() << "Arrays::" << __FUNCTION__ << "():"<<newImg;
+ return newImg;
+}
diff --git a/src/typedarrayfactory_p.h b/src/typedarrayfactory_p.h
new file mode 100644
index 0000000..f36bf29
--- /dev/null
+++ b/src/typedarrayfactory_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef TYPEDARRAYFACTORY_P_H
+#define TYPEDARRAYFACTORY_P_H
+
+#include <QObject>
+#include <QVariantList>
+#include <QQmlEngine>
+#include <QJSEngine>
+
+class CanvasInt8Array;
+class CanvasUint8Array;
+class CanvasInt16Array;
+class CanvasUint16Array;
+class CanvasInt32Array;
+class CanvasUint32Array;
+class CanvasFloat32Array;
+class CanvasFloat64Array;
+class CanvasUint8ClampedArray;
+class CanvasArrayBuffer;
+class CanvasTypedArray;
+class CanvasTextureImage;
+
+class CanvasTypedArrayFactory : public QObject
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(CanvasTypedArrayFactory)
+
+public:
+ static QObject *type_array_factory_provider(QQmlEngine *engine, QJSEngine *scriptEngine);
+
+ explicit CanvasTypedArrayFactory(QObject *parent = 0);
+ ~CanvasTypedArrayFactory();
+
+ /* Typed array creation functions. Typed arrays should be in the V4VM implementation.*/
+ Q_INVOKABLE CanvasInt8Array* newInt8Array(unsigned long length);
+ Q_INVOKABLE CanvasInt8Array* newInt8Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasInt8Array* newInt8Array(QVariantList array);
+ Q_INVOKABLE CanvasInt8Array* newInt8Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasUint8Array* newUint8Array(unsigned long length);
+ Q_INVOKABLE CanvasUint8Array* newUint8Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasUint8Array* newUint8Array(QVariantList array);
+ Q_INVOKABLE CanvasUint8Array* newUint8Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasInt16Array* newInt16Array(unsigned long length);
+ Q_INVOKABLE CanvasInt16Array* newInt16Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasInt16Array* newInt16Array(QVariantList array);
+ Q_INVOKABLE CanvasInt16Array* newInt16Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasUint16Array* newUint16Array(unsigned long length);
+ Q_INVOKABLE CanvasUint16Array* newUint16Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasUint16Array* newUint16Array(QVariantList array);
+ Q_INVOKABLE CanvasUint16Array* newUint16Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasInt32Array* newInt32Array(unsigned long length);
+ Q_INVOKABLE CanvasInt32Array* newInt32Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasInt32Array* newInt32Array(QVariantList array);
+ Q_INVOKABLE CanvasInt32Array* newInt32Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasUint32Array* newUint32Array(unsigned long length);
+ Q_INVOKABLE CanvasUint32Array* newUint32Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasUint32Array* newUint32Array(QVariantList array);
+ Q_INVOKABLE CanvasUint32Array* newUint32Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasFloat32Array* newFloat32Array(unsigned long length);
+ Q_INVOKABLE CanvasFloat32Array* newFloat32Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasFloat32Array* newFloat32Array(QVariantList array);
+ Q_INVOKABLE CanvasFloat32Array* newFloat32Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasFloat64Array* newFloat64Array(unsigned long length);
+ Q_INVOKABLE CanvasFloat64Array* newFloat64Array(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasFloat64Array* newFloat64Array(QVariantList array);
+ Q_INVOKABLE CanvasFloat64Array* newFloat64Array(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasUint8ClampedArray* newUint8ClampedArray(unsigned long length);
+ Q_INVOKABLE CanvasUint8ClampedArray* newUint8ClampedArray(CanvasTypedArray *array);
+ Q_INVOKABLE CanvasUint8ClampedArray* newUint8ClampedArray(QVariantList array);
+ Q_INVOKABLE CanvasUint8ClampedArray* newUint8ClampedArray(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset);
+
+ Q_INVOKABLE CanvasTextureImage* newTexImage();
+};
+
+#endif // TYPEDARRAYFACTORY_P_H
diff --git a/src/uint16array.cpp b/src/uint16array.cpp
new file mode 100644
index 0000000..1eebb09
--- /dev/null
+++ b/src/uint16array.cpp
@@ -0,0 +1,201 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "uint16array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Uint16Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of 16 bit unsigned ints.
+ *
+ * An uncreatable QML type that contains a typed array of 16 bit unsigned ints.
+ * Use \l Arrays::newUint16Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasUint16Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasUint16Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasUint16Array::CanvasUint16Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Uint16Array(QObject *parent)";
+ setLength(0);
+}
+
+/*!
+ * \internal
+ */
+CanvasUint16Array::CanvasUint16Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Uint16Array(unsigned long length, QObject *parent)";
+ setLength(length);
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(float) * CanvasTypedArray::length());
+ m_typedBuffer = (unsigned short *)m_buffer->m_rawData;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint16Array::CanvasUint16Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (unsigned short *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<unsigned short>(m_typedBuffer, array,
+ CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint16Array::CanvasUint16Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Uint16Array(const QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(sizeof(unsigned short) * CanvasTypedArray::length(), this);
+ m_typedBuffer = (unsigned short *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<unsigned short>()) {
+ m_typedBuffer[idx] = (unsigned short)(element.toInt());
+ } else {
+ //qDebug() << "Failed conversion to unsigned byte of "<<element;
+ m_typedBuffer[idx] = (unsigned short)0;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint16Array::CanvasUint16Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Uint16Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (unsigned short *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod int Uint16Array::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+unsigned short CanvasUint16Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return ushort(0);
+}
+
+/*!
+ * \qmlmethod int Uint16Array::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+unsigned short CanvasUint16Array::get(unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return ushort(0);
+}
+
+/*!
+ * \qmlmethod void Uint16Array::set(int index, int value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasUint16Array::set(unsigned long index, unsigned short value)
+{
+ if (index < length())
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Uint16Array::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Uint16Array::set(float *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Uint16Array::subarray(long begin)
+{
+
+}
+
+TypedArray *Uint16Array::subarray(long begin, long end)
+{
+
+}
+*/
diff --git a/src/uint16array_p.h b/src/uint16array_p.h
new file mode 100644
index 0000000..82ca4a1
--- /dev/null
+++ b/src/uint16array_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef UINT16ARRAY_P_H
+#define UINT16ARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasUint16Array : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasUint16Array(QObject *parent = 0);
+ explicit CanvasUint16Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasUint16Array(CanvasTypedArray *array, QObject *parent = 0);
+ explicit CanvasUint16Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasUint16Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ Q_INVOKABLE unsigned short operator [] (unsigned long index);
+ Q_INVOKABLE unsigned short get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, unsigned short value);
+ virtual inline int bytesPerElement() { return sizeof(unsigned short); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::UNSIGNED_SHORT; }
+
+ //Q_INVOKABLE void set(ArrayBufferView *array, unsigned long offset);
+ //Q_INVOKABLE void set(unsigned short *array, unsigned long offset);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin, long end);
+
+private:
+ unsigned short *m_typedBuffer;
+};
+
+#endif // UINT16ARRAY_P_H
diff --git a/src/uint32array.cpp b/src/uint32array.cpp
new file mode 100644
index 0000000..81c2e1c
--- /dev/null
+++ b/src/uint32array.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "uint32array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Uint32Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of unsigned ints.
+ *
+ * An uncreatable QML type that contains a typed array of unsigned ints.
+ * Use \l Arrays::newUint32Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasUint32Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasUint32Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasUint32Array::CanvasUint32Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Uint32Array(QObject *parent)";
+ setLength(0);
+}
+
+/*!
+ * \internal
+ */
+CanvasUint32Array::CanvasUint32Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ //qDebug() << "Uint32Array(unsigned long length, QObject *parent)";
+ setLength(length);
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(float) * CanvasTypedArray::length());
+ m_typedBuffer = (unsigned int *)m_buffer->m_rawData;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint32Array::CanvasUint32Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (unsigned int *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<unsigned int>(m_typedBuffer, array, CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint32Array::CanvasUint32Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Uint32Array(const QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(sizeof(unsigned int) * CanvasTypedArray::length(), this);
+ m_typedBuffer = (unsigned int *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<unsigned int>()) {
+ m_typedBuffer[idx] = (unsigned int)(element.toInt());
+ } else {
+ //qDebug() << "Failed conversion to unsigned byte of "<<element;
+ m_typedBuffer[idx] = (unsigned int)0;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint32Array::CanvasUint32Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Uint32Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (unsigned int *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod int Uint32Array::operator [] (int index)
+ */
+/*!
+ * \internal
+ */
+unsigned int CanvasUint32Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return uint(0);
+}
+
+/*!
+ * \qmlmethod int Uint32Array::get(int index)
+ */
+/*!
+ * \internal
+ */
+unsigned int CanvasUint32Array::get(unsigned long index)
+{
+ return m_typedBuffer[index];
+}
+
+/*!
+ * \qmlmethod void Uint32Array::set(int index, int value)
+ */
+/*!
+ * \internal
+ */
+void CanvasUint32Array::set(unsigned long index, unsigned int value)
+{
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Uint32Array::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Uint32Array::set(float *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Uint32Array::subarray(long begin)
+{
+
+}
+
+TypedArray *Uint32Array::subarray(long begin, long end)
+{
+
+}
+*/
diff --git a/src/uint32array_p.h b/src/uint32array_p.h
new file mode 100644
index 0000000..eb09f7a
--- /dev/null
+++ b/src/uint32array_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef UINT32ARRAY_P_H
+#define UINT32ARRAY_P_H
+
+#include "typedarray_p.h"
+
+#include <QObject>
+
+class CanvasUint32Array : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasUint32Array(QObject *parent = 0);
+ explicit CanvasUint32Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasUint32Array(CanvasTypedArray *array, QObject *parent = 0);
+ explicit CanvasUint32Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasUint32Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ Q_INVOKABLE unsigned int operator [] (unsigned long index);
+ Q_INVOKABLE unsigned int get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, unsigned int value);
+ virtual inline int bytesPerElement() { return sizeof(unsigned int); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::UNSIGNED_INT; }
+
+ //Q_INVOKABLE void set(ArrayBufferView *array, unsigned long offset);
+ //Q_INVOKABLE void set(unsigned int *array, unsigned long offset);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin, long end);
+
+private:
+ unsigned int *m_typedBuffer;
+};
+
+#endif // UINT32ARRAY_P_H
diff --git a/src/uint8array.cpp b/src/uint8array.cpp
new file mode 100644
index 0000000..56630c5
--- /dev/null
+++ b/src/uint8array.cpp
@@ -0,0 +1,198 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "uint8array_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Uint8Array
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of 8 bit unsigned ints.
+ *
+ * An uncreatable QML type that contains a typed array of 8 bit unsigned ints.
+ * Use \l Arrays::newUint8Array() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasUint8Array::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasUint8Array::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasUint8Array::CanvasUint8Array(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ setLength(0);
+ //qDebug() << "Uint8Array(QObject *parent)";
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8Array::CanvasUint8Array(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ setLength(length);
+ //qDebug() << "Uint8Array(unsigned long length, QObject *parent)";
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(unsigned char) * CanvasTypedArray::length());
+ m_typedBuffer = (unsigned char *)m_buffer->m_rawData;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8Array::CanvasUint8Array(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (unsigned char *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTarget<unsigned char>(m_typedBuffer, array,
+ CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8Array::CanvasUint8Array(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Uint8Array(const QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * sizeof(unsigned char), this);
+ m_typedBuffer = (unsigned char *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<unsigned char>()) {
+ m_typedBuffer[idx] = (unsigned char)(element.toInt());
+ } else {
+ //qDebug() << "Failed conversion to unsigned byte of "<<element;
+ m_typedBuffer[idx] = (unsigned char)0;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8Array::CanvasUint8Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Uint8Array(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (unsigned char *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod int Uint8Array::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+unsigned char CanvasUint8Array::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return uchar(0);
+}
+
+/*!
+ * \qmlmethod int Uint8Array::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+unsigned char CanvasUint8Array::get(unsigned long index)
+{
+ return m_typedBuffer[index];
+}
+
+/*!
+ * \qmlmethod void Uint8Array::set(int index, int value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasUint8Array::set(unsigned long index, unsigned char value)
+{
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Uint8Array::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Uint8Array::set(float *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Uint8Array::subarray(long begin)
+{
+
+}
+
+TypedArray *Uint8Array::subarray(long begin, long end)
+{
+
+}
+*/
diff --git a/src/uint8array_p.h b/src/uint8array_p.h
new file mode 100644
index 0000000..fda9201
--- /dev/null
+++ b/src/uint8array_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef UINT8ARRAY_P_H
+#define UINT8ARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasUint8Array : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasUint8Array(QObject *parent = 0);
+ explicit CanvasUint8Array(unsigned long length, QObject *parent = 0);
+ explicit CanvasUint8Array(QVariantList *array, QObject *parent = 0);
+ explicit CanvasUint8Array(CanvasTypedArray *array, QObject *parent = 0);
+ explicit CanvasUint8Array(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ Q_INVOKABLE unsigned char operator [] (unsigned long index);
+ Q_INVOKABLE unsigned char get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, unsigned char value);
+ virtual inline int bytesPerElement() { return sizeof(unsigned char); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::UNSIGNED_BYTE; }
+
+ //Q_INVOKABLE void set(ArrayBufferView *array, unsigned long offset);
+ //Q_INVOKABLE void set(unsigned char *array, unsigned long offset);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin, long end);
+
+private:
+ unsigned char *m_typedBuffer;
+};
+
+#endif // UINT8ARRAY_P_H
diff --git a/src/uint8clampedarray.cpp b/src/uint8clampedarray.cpp
new file mode 100644
index 0000000..d3c89b2
--- /dev/null
+++ b/src/uint8clampedarray.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "uint8clampedarray_p.h"
+#include "arrayutils_p.h"
+#include "arraybuffer_p.h"
+
+/*!
+ * \qmltype Uint8ClampedArray
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains a typed array of clamped 8 bit unsigned ints.
+ *
+ * An uncreatable QML type that contains a typed array of clamped 8 bit unsigned ints.
+ * Use \l Arrays::newUint8ClampedArray() for getting an array of this type.
+ */
+
+/*!
+ * \fn virtual inline int CanvasUint8ClampedArray::bytesPerElement();
+ * \internal
+ */
+
+/*!
+ * \fn virtual inline CanvasContext3D::glEnums CanvasUint8ClampedArray::dataType();
+ * \internal
+ */
+
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray::CanvasUint8ClampedArray(QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ setLength(0);
+ //qDebug() << "Uint8ClampedArray(QObject *parent)";
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray::CanvasUint8ClampedArray(unsigned long length, QObject *parent) :
+ CanvasTypedArray(0, 0, parent),
+ m_typedBuffer(0)
+{
+ setLength(length);
+ //qDebug() << "Uint8ClampedArray(unsigned long length, QObject *parent)";
+ if (length > 0) {
+ m_buffer = new CanvasArrayBuffer(sizeof(unsigned char) * CanvasTypedArray::length());
+ m_typedBuffer = (unsigned char *)m_buffer->m_rawData;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray::CanvasUint8ClampedArray(CanvasTypedArray *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ setLength(array->length());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * this->bytesPerElement());
+ m_typedBuffer = (unsigned char *)m_buffer->m_rawData;
+
+ if (!ArrayUtils::copyToTargetClampedByte(m_typedBuffer, array, CanvasTypedArray::length())) {
+ // Conversion failed, make this an empty buffer
+ delete m_buffer;
+ setLength(0);
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray::CanvasUint8ClampedArray(QVariantList *array, QObject *parent) :
+ CanvasTypedArray(0, 0, parent)
+{
+ //qDebug() << "Uint8ClampedArray(const QVariantList *array[" << array->count() << "], QObject *parent)";
+ setLength(array->count());
+ m_buffer = new CanvasArrayBuffer(CanvasTypedArray::length() * sizeof(unsigned char), this);
+ m_typedBuffer = (unsigned char *)m_buffer->m_rawData;
+ int idx = 0;
+ for (QVariantList::const_iterator it = array->begin(); it != array->end(); ++it) {
+ QVariant element = *it;
+ if (element.canConvert<unsigned char>()) {
+ m_typedBuffer[idx] = (unsigned char)(element.toInt());
+ } else {
+ //qDebug() << "Failed conversion to unsigned byte of "<<element;
+ m_typedBuffer[idx] = (unsigned char)0;
+ }
+ idx++;
+ }
+}
+
+/*!
+ * \internal
+ */
+CanvasUint8ClampedArray::CanvasUint8ClampedArray(CanvasArrayBuffer *buffer,
+ unsigned long byteOffset, QObject *parent) :
+ CanvasTypedArray(buffer, byteOffset, parent)
+{
+ //qDebug() << "Uint8ClampedArray(ArrayBuffer *buffer, unsigned long byteOffset, QObject *parent)";
+ m_typedBuffer = (unsigned char *)(m_buffer->m_rawData + byteOffset);
+ setLength((byteLength() - byteOffset) / bytesPerElement());
+}
+
+/*!
+ * \qmlmethod int Uint8ClampedArray::operator [] (int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+unsigned char CanvasUint8ClampedArray::operator [] (unsigned long index)
+{
+ if (index < length())
+ return m_typedBuffer[index];
+ return uchar(0);
+}
+
+/*!
+ * \qmlmethod int Uint8ClampedArray::get(int index)
+ * Returns the array value at \a index.
+ */
+/*!
+ * \internal
+ */
+unsigned char CanvasUint8ClampedArray::get(unsigned long index)
+{
+ return m_typedBuffer[index];
+}
+
+/*!
+ * \qmlmethod void Uint8ClampedArray::set(int index, int value)
+ * Sets the \a value to \a index in the array.
+ */
+/*!
+ * \internal
+ */
+void CanvasUint8ClampedArray::set(unsigned long index, unsigned char value)
+{
+ m_typedBuffer[index] = value;
+}
+
+/*
+void Uint8ClampedArray::set(TypedArray *array, unsigned long offset)
+{
+
+}
+
+void Uint8ClampedArray::set(float *array, unsigned long offset)
+{
+
+}
+
+TypedArray *Uint8ClampedArray::subarray(long begin)
+{
+
+}
+
+TypedArray *Uint8ClampedArray::subarray(long begin, long end)
+{
+
+}
+*/
diff --git a/src/uint8clampedarray_p.h b/src/uint8clampedarray_p.h
new file mode 100644
index 0000000..f6ab055
--- /dev/null
+++ b/src/uint8clampedarray_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef UINT8CLAMPEDARRAY_P_H
+#define UINT8CLAMPEDARRAY_P_H
+
+#include "typedarray_p.h"
+
+class CanvasUint8ClampedArray : public CanvasTypedArray
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasUint8ClampedArray(QObject *parent = 0);
+ explicit CanvasUint8ClampedArray(unsigned long length, QObject *parent = 0);
+ explicit CanvasUint8ClampedArray(QVariantList *array, QObject *parent = 0);
+ explicit CanvasUint8ClampedArray(CanvasTypedArray *array, QObject *parent = 0);
+ explicit CanvasUint8ClampedArray(CanvasArrayBuffer *buffer, unsigned long byteOffset,
+ QObject *parent = 0);
+
+ Q_INVOKABLE unsigned char operator [] (unsigned long index);
+ Q_INVOKABLE unsigned char get(unsigned long index);
+ Q_INVOKABLE void set(unsigned long index, unsigned char value);
+ virtual inline int bytesPerElement() { return sizeof(unsigned char); }
+ virtual inline CanvasContext::glEnums dataType() { return CanvasContext::UNSIGNED_BYTE; }
+
+ //Q_INVOKABLE void set(ArrayBufferView *array, unsigned long offset);
+ //Q_INVOKABLE void set(unsigned char *array, unsigned long offset);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin);
+ //Q_INVOKABLE ArrayBufferView *subarray(long begin, long end);
+
+private:
+ unsigned char *m_typedBuffer;
+};
+
+#endif // UINT8CLAMPEDARRAY_P_H
diff --git a/src/uniformlocation.cpp b/src/uniformlocation.cpp
new file mode 100644
index 0000000..a1b38be
--- /dev/null
+++ b/src/uniformlocation.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "uniformlocation_p.h"
+
+/*!
+ * \qmltype UniformLocation
+ * \since QtCanvas3D 1.0
+ * \ingroup qtcanvas3d-qml-types
+ * \brief Contains uniform location id.
+ *
+ * An uncreatable QML type that contains an uniform location id. You can get it by calling
+ * \l{Context3D::getUniformLocation()}{Context3D.getUniformLocation()} method.
+ */
+
+/*!
+ * \internal
+ */
+CanvasUniformLocation::CanvasUniformLocation(int location, QObject *parent) :
+ CanvasAbstractObject(parent),
+ m_location(location)
+{
+}
+
+/*!
+ * \internal
+ */
+CanvasUniformLocation::~CanvasUniformLocation()
+{
+}
+
+/*!
+ * \internal
+ */
+int CanvasUniformLocation::id()
+{
+ return m_location;
+}
+
+/*!
+ * \internal
+ */
+QDebug operator<<(QDebug dbg, const CanvasUniformLocation *uLoc)
+{
+ if (uLoc)
+ dbg.nospace() << "UniformLocation("<< (void *) uLoc << ", name:"<< uLoc->m_name <<", location:" << uLoc->m_location << ")";
+ else
+ dbg.nospace() << "UniformLocation("<< (void *)(uLoc) << ")";
+
+ return dbg.maybeSpace();
+}
diff --git a/src/uniformlocation_p.h b/src/uniformlocation_p.h
new file mode 100644
index 0000000..7c4c45b
--- /dev/null
+++ b/src/uniformlocation_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtCanvas3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCanvas3D API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef UNIFORMLOCATION_P_H
+#define UNIFORMLOCATION_P_H
+
+#include "abstractobject3d_p.h"
+
+#include <QDebug>
+
+class CanvasUniformLocation : public CanvasAbstractObject
+{
+ Q_OBJECT
+
+public:
+ explicit CanvasUniformLocation(int location, QObject *parent = 0);
+ virtual ~CanvasUniformLocation();
+
+ int id();
+
+ friend QDebug operator<< (QDebug d, const CanvasUniformLocation *uLoc);
+
+private:
+ int m_location;
+};
+
+#endif // UNIFORMLOCATION_P_H
diff --git a/sync.profile b/sync.profile
new file mode 100644
index 0000000..6c7b1d5
--- /dev/null
+++ b/sync.profile
@@ -0,0 +1,15 @@
+%modules = ( # path to module name map
+ "QtCanvas3D" => "$basedir/src",
+);
+%moduleheaders = ( # restrict the module headers to those found in relative path
+);
+# Module dependencies.
+# Every module that is required to build this module should have one entry.
+# Each of the module version specifiers can take one of the following values:
+# - A specific Git revision.
+# - any git symbolic ref resolvable from the module's repository (e.g. "refs/heads/master" to track master branch)
+#
+%dependencies = (
+ "qtbase" => "refs/heads/stable",
+ "qtdeclarative" => "refs/heads/stable",
+);