summaryrefslogtreecommitdiffstats
path: root/demos/boxes
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@nokia.com>2009-03-23 09:34:13 (GMT)
committerSimon Hausmann <simon.hausmann@nokia.com>2009-03-23 09:34:13 (GMT)
commit67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch)
tree1dbf50b3dff8d5ca7e9344733968c72704eb15ff /demos/boxes
downloadQt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip
Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz
Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2
Long live Qt!
Diffstat (limited to 'demos/boxes')
-rw-r--r--demos/boxes/3rdparty/fbm.c207
-rw-r--r--demos/boxes/3rdparty/fbm.h40
-rw-r--r--demos/boxes/basic.fsh73
-rw-r--r--demos/boxes/basic.vsh61
-rw-r--r--demos/boxes/boxes.pro50
-rw-r--r--demos/boxes/boxes.qrc25
-rw-r--r--demos/boxes/cubemap_negx.jpgbin0 -> 41060 bytes
-rw-r--r--demos/boxes/cubemap_negy.jpgbin0 -> 15520 bytes
-rw-r--r--demos/boxes/cubemap_negz.jpgbin0 -> 68911 bytes
-rw-r--r--demos/boxes/cubemap_posx.jpgbin0 -> 74915 bytes
-rw-r--r--demos/boxes/cubemap_posy.jpgbin0 -> 24193 bytes
-rw-r--r--demos/boxes/cubemap_posz.jpgbin0 -> 57881 bytes
-rw-r--r--demos/boxes/dotted.fsh66
-rw-r--r--demos/boxes/fresnel.fsh79
-rw-r--r--demos/boxes/glass.fsh76
-rw-r--r--demos/boxes/glbuffers.cpp390
-rw-r--r--demos/boxes/glbuffers.h362
-rw-r--r--demos/boxes/glextensions.cpp135
-rw-r--r--demos/boxes/glextensions.h284
-rw-r--r--demos/boxes/glshaders.cpp266
-rw-r--r--demos/boxes/glshaders.h108
-rw-r--r--demos/boxes/gltrianglemesh.h91
-rw-r--r--demos/boxes/granite.fsh76
-rw-r--r--demos/boxes/main.cpp149
-rw-r--r--demos/boxes/marble.fsh71
-rw-r--r--demos/boxes/parameters.par5
-rw-r--r--demos/boxes/qt-logo.jpgbin0 -> 40886 bytes
-rw-r--r--demos/boxes/qt-logo.pngbin0 -> 13923 bytes
-rw-r--r--demos/boxes/qtbox.cpp469
-rw-r--r--demos/boxes/qtbox.h116
-rw-r--r--demos/boxes/reflection.fsh54
-rw-r--r--demos/boxes/refraction.fsh70
-rw-r--r--demos/boxes/roundedbox.cpp160
-rw-r--r--demos/boxes/roundedbox.h71
-rw-r--r--demos/boxes/scene.cpp1057
-rw-r--r--demos/boxes/scene.h243
-rw-r--r--demos/boxes/smiley.pngbin0 -> 14508 bytes
-rw-r--r--demos/boxes/square.jpgbin0 -> 14542 bytes
-rw-r--r--demos/boxes/trackball.cpp158
-rw-r--r--demos/boxes/trackball.h78
-rw-r--r--demos/boxes/vector.h602
-rw-r--r--demos/boxes/wood.fsh70
42 files changed, 5762 insertions, 0 deletions
diff --git a/demos/boxes/3rdparty/fbm.c b/demos/boxes/3rdparty/fbm.c
new file mode 100644
index 0000000..98eb87a
--- /dev/null
+++ b/demos/boxes/3rdparty/fbm.c
@@ -0,0 +1,207 @@
+/*****************************************************************
+
+ Implementation of the fractional Brownian motion algorithm. These
+ functions were originally the work of F. Kenton Musgrave.
+ For documentation of the different functions please refer to the
+ book:
+ "Texturing and modeling: a procedural approach"
+ by David S. Ebert et. al.
+
+******************************************************************/
+
+#if defined (_MSC_VER)
+#include <qglobal.h>
+#endif
+
+#include <time.h>
+#include <stdlib.h>
+#include "fbm.h"
+
+#if defined(Q_CC_MSVC)
+#pragma warning(disable:4244)
+#endif
+
+/* Definitions used by the noise2() functions */
+
+//#define B 0x100
+//#define BM 0xff
+#define B 0x20
+#define BM 0x1f
+
+#define N 0x1000
+#define NP 12 /* 2^N */
+#define NM 0xfff
+
+static int p[B + B + 2];
+static float g3[B + B + 2][3];
+static float g2[B + B + 2][2];
+static float g1[B + B + 2];
+static int start = 1;
+
+static void init(void);
+
+#define s_curve(t) ( t * t * (3. - 2. * t) )
+
+#define lerp(t, a, b) ( a + t * (b - a) )
+
+#define setup(i,b0,b1,r0,r1)\
+ t = vec[i] + N;\
+ b0 = ((int)t) & BM;\
+ b1 = (b0+1) & BM;\
+ r0 = t - (int)t;\
+ r1 = r0 - 1.;
+#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] )
+
+/* Fractional Brownian Motion function */
+
+double fBm( Vector point, double H, double lacunarity, double octaves,
+ int init )
+{
+
+ double value, frequency, remainder;
+ int i;
+ static double exponent_array[10];
+ float vec[3];
+
+ /* precompute and store spectral weights */
+ if ( init ) {
+ start = 1;
+ srand( time(0) );
+ /* seize required memory for exponent_array */
+ frequency = 1.0;
+ for (i=0; i<=octaves; i++) {
+ /* compute weight for each frequency */
+ exponent_array[i] = pow( frequency, -H );
+ frequency *= lacunarity;
+ }
+ }
+
+ value = 0.0; /* initialize vars to proper values */
+ frequency = 1.0;
+ vec[0]=point.x;
+ vec[1]=point.y;
+ vec[2]=point.z;
+
+
+ /* inner loop of spectral construction */
+ for (i=0; i<octaves; i++) {
+ /* value += noise3( vec ) * exponent_array[i];*/
+ value += noise3( vec ) * exponent_array[i];
+ vec[0] *= lacunarity;
+ vec[1] *= lacunarity;
+ vec[2] *= lacunarity;
+ } /* for */
+
+ remainder = octaves - (int)octaves;
+ if ( remainder ) /* add in ``octaves'' remainder */
+ /* ``i'' and spatial freq. are preset in loop above */
+ value += remainder * noise3( vec ) * exponent_array[i];
+
+ return( value );
+
+} /* fBm() */
+
+
+float noise3(float vec[3])
+{
+ int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
+ float rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v;
+ register int i, j;
+
+ if (start) {
+ start = 0;
+ init();
+ }
+
+ setup(0, bx0,bx1, rx0,rx1);
+ setup(1, by0,by1, ry0,ry1);
+ setup(2, bz0,bz1, rz0,rz1);
+
+ i = p[ bx0 ];
+ j = p[ bx1 ];
+
+ b00 = p[ i + by0 ];
+ b10 = p[ j + by0 ];
+ b01 = p[ i + by1 ];
+ b11 = p[ j + by1 ];
+
+ t = s_curve(rx0);
+ sy = s_curve(ry0);
+ sz = s_curve(rz0);
+
+
+ q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0);
+ q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0);
+ a = lerp(t, u, v);
+
+ q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0);
+ q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0);
+ b = lerp(t, u, v);
+
+ c = lerp(sy, a, b);
+
+ q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1);
+ q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1);
+ a = lerp(t, u, v);
+
+ q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1);
+ q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1);
+ b = lerp(t, u, v);
+
+ d = lerp(sy, a, b);
+
+ return lerp(sz, c, d);
+}
+
+static void normalize2(float v[2])
+{
+ float s;
+
+ s = sqrt(v[0] * v[0] + v[1] * v[1]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+}
+
+static void normalize3(float v[3])
+{
+ float s;
+
+ s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+ v[0] = v[0] / s;
+ v[1] = v[1] / s;
+ v[2] = v[2] / s;
+}
+
+static void init(void)
+{
+ int i, j, k;
+
+ for (i = 0 ; i < B ; i++) {
+ p[i] = i;
+
+ g1[i] = (float)((rand() % (B + B)) - B) / B;
+
+ for (j = 0 ; j < 2 ; j++)
+ g2[i][j] = (float)((rand() % (B + B)) - B) / B;
+ normalize2(g2[i]);
+
+ for (j = 0 ; j < 3 ; j++)
+ g3[i][j] = (float)((rand() % (B + B)) - B) / B;
+ normalize3(g3[i]);
+ }
+
+ while (--i) {
+ k = p[i];
+ p[i] = p[j = rand() % B];
+ p[j] = k;
+ }
+
+ for (i = 0 ; i < B + 2 ; i++) {
+ p[B + i] = p[i];
+ g1[B + i] = g1[i];
+ for (j = 0 ; j < 2 ; j++)
+ g2[B + i][j] = g2[i][j];
+ for (j = 0 ; j < 3 ; j++)
+ g3[B + i][j] = g3[i][j];
+ }
+}
diff --git a/demos/boxes/3rdparty/fbm.h b/demos/boxes/3rdparty/fbm.h
new file mode 100644
index 0000000..b8a4a99
--- /dev/null
+++ b/demos/boxes/3rdparty/fbm.h
@@ -0,0 +1,40 @@
+/*****************************************************************
+
+ Prototypes for the fractional Brownian motion algorithm. These
+ functions were originally the work of F. Kenton Musgrave. For
+ documentation of the different functions please refer to the book:
+ "Texturing and modeling: a procedural approach"
+ by David S. Ebert et. al.
+
+******************************************************************/
+
+#ifndef _fbm_h
+#define _fbm_h
+
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define TRUE 1
+//#define FALSE 0
+
+typedef struct {
+ double x;
+ double y;
+ double z;
+} Vector;
+
+float noise3(float vec[]);
+double fBm( Vector point, double H, double lacunarity, double octaves,
+ int init );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+
diff --git a/demos/boxes/basic.fsh b/demos/boxes/basic.fsh
new file mode 100644
index 0000000..06ef24a
--- /dev/null
+++ b/demos/boxes/basic.fsh
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform vec4 basicColor;
+
+void main()
+{
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec3 absN = abs(gl_TexCoord[1].xyz);
+ vec3 texCoord;
+ if (absN.x > absN.y && absN.x > absN.z)
+ texCoord = gl_TexCoord[1].yzx;
+ else if (absN.y > absN.z)
+ texCoord = gl_TexCoord[1].zxy;
+ else
+ texCoord = gl_TexCoord[1].xyz;
+ texCoord.y *= -sign(texCoord.z);
+ texCoord += 0.5;
+
+ vec4 texColor = texture2D(tex, texCoord.xy);
+ vec4 unlitColor = gl_Color * mix(basicColor, vec4(texColor.xyz, 1.0), texColor.w);
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/basic.vsh b/demos/boxes/basic.vsh
new file mode 100644
index 0000000..5a02df2
--- /dev/null
+++ b/demos/boxes/basic.vsh
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform mat4 view;
+
+void main()
+{
+ gl_TexCoord[0] = gl_MultiTexCoord0;
+ gl_TexCoord[1] = gl_Vertex;
+ specular = gl_LightSource[0].specular;
+ ambient = gl_LightSource[0].ambient;
+ diffuse = gl_LightSource[0].diffuse;
+ lightDirection = view * gl_LightSource[0].position;
+
+ normal = gl_NormalMatrix * gl_Normal;
+ position = (gl_ModelViewMatrix * gl_Vertex).xyz;
+
+ gl_FrontColor = gl_Color;
+ gl_Position = ftransform();
+}
diff --git a/demos/boxes/boxes.pro b/demos/boxes/boxes.pro
new file mode 100644
index 0000000..6c1a331
--- /dev/null
+++ b/demos/boxes/boxes.pro
@@ -0,0 +1,50 @@
+######################################################################
+# Automatically generated by qmake (2.01a) ma 3. nov 17:33:30 2008
+######################################################################
+
+TEMPLATE = app
+TARGET =
+DEPENDPATH += .
+INCLUDEPATH += .
+
+# Input
+HEADERS += 3rdparty/fbm.h \
+ glbuffers.h \
+ glextensions.h \
+ glshaders.h \
+ gltrianglemesh.h \
+ qtbox.h \
+ roundedbox.h \
+ scene.h \
+ trackball.h \
+ vector.h
+SOURCES += 3rdparty/fbm.c \
+ glbuffers.cpp \
+ glextensions.cpp \
+ glshaders.cpp \
+ main.cpp \
+ qtbox.cpp \
+ roundedbox.cpp \
+ scene.cpp \
+ trackball.cpp
+
+RESOURCES += boxes.qrc
+
+QT += opengl
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/boxes
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.pro *.html *.jpg *.png *.fsh *.vsh *.par
+sources.files -= 3rdparty/fbm.h 3rdparty/fbm.c
+sources.files += 3rdparty
+sources.path = $$[QT_INSTALL_DEMOS]/boxes
+INSTALLS += target sources
+
+wince*: {
+ DEPLOYMENT_PLUGIN += qjpeg
+}
+
+win32-msvc* {
+ QMAKE_CXXFLAGS += /Zm1200
+ QMAKE_CFLAGS += /Zm1200
+}
diff --git a/demos/boxes/boxes.qrc b/demos/boxes/boxes.qrc
new file mode 100644
index 0000000..d27506d
--- /dev/null
+++ b/demos/boxes/boxes.qrc
@@ -0,0 +1,25 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource prefix="/res/boxes">
+ <file>cubemap_negx.jpg</file>
+ <file>cubemap_negy.jpg</file>
+ <file>cubemap_negz.jpg</file>
+ <file>cubemap_posx.jpg</file>
+ <file>cubemap_posy.jpg</file>
+ <file>cubemap_posz.jpg</file>
+ <file>square.jpg</file>
+ <file>basic.vsh</file>
+ <file>basic.fsh</file>
+ <file>dotted.fsh</file>
+ <file>fresnel.fsh</file>
+ <file>glass.fsh</file>
+ <file>granite.fsh</file>
+ <file>marble.fsh</file>
+ <file>reflection.fsh</file>
+ <file>refraction.fsh</file>
+ <file>wood.fsh</file>
+ <file>parameters.par</file>
+ <file>qt-logo.png</file>
+ <file>smiley.png</file>
+ <file>qt-logo.jpg</file>
+</qresource>
+</RCC>
diff --git a/demos/boxes/cubemap_negx.jpg b/demos/boxes/cubemap_negx.jpg
new file mode 100644
index 0000000..07c282e
--- /dev/null
+++ b/demos/boxes/cubemap_negx.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_negy.jpg b/demos/boxes/cubemap_negy.jpg
new file mode 100644
index 0000000..46cd2f9
--- /dev/null
+++ b/demos/boxes/cubemap_negy.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_negz.jpg b/demos/boxes/cubemap_negz.jpg
new file mode 100644
index 0000000..40c01dd
--- /dev/null
+++ b/demos/boxes/cubemap_negz.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_posx.jpg b/demos/boxes/cubemap_posx.jpg
new file mode 100644
index 0000000..0b42e8a
--- /dev/null
+++ b/demos/boxes/cubemap_posx.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_posy.jpg b/demos/boxes/cubemap_posy.jpg
new file mode 100644
index 0000000..2aca9b1
--- /dev/null
+++ b/demos/boxes/cubemap_posy.jpg
Binary files differ
diff --git a/demos/boxes/cubemap_posz.jpg b/demos/boxes/cubemap_posz.jpg
new file mode 100644
index 0000000..2e49173
--- /dev/null
+++ b/demos/boxes/cubemap_posz.jpg
Binary files differ
diff --git a/demos/boxes/dotted.fsh b/demos/boxes/dotted.fsh
new file mode 100644
index 0000000..26425f6
--- /dev/null
+++ b/demos/boxes/dotted.fsh
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+
+void main()
+{
+ vec3 N = normalize(normal);
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ // assume directional light
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ float r1 = length(fract(7.0 * gl_TexCoord[1].xyz) - 0.5);
+ float r2 = length(fract(5.0 * gl_TexCoord[1].xyz + 0.2) - 0.5);
+ float r3 = length(fract(11.0 * gl_TexCoord[1].xyz + 0.7) - 0.5);
+ vec4 rs = vec4(r1, r2, r3, 0.0);
+
+ vec4 unlitColor = gl_Color * (0.8 - clamp(10.0 * (0.4 - rs), 0.0, 0.2));
+ unlitColor.w = 1.0;
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/fresnel.fsh b/demos/boxes/fresnel.fsh
new file mode 100644
index 0000000..dd98061
--- /dev/null
+++ b/demos/boxes/fresnel.fsh
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+uniform vec4 basicColor;
+
+void main()
+{
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec3 absN = abs(gl_TexCoord[1].xyz);
+ vec3 texCoord;
+ if (absN.x > absN.y && absN.x > absN.z)
+ texCoord = gl_TexCoord[1].yzx;
+ else if (absN.y > absN.z)
+ texCoord = gl_TexCoord[1].zxy;
+ else
+ texCoord = gl_TexCoord[1].xyz;
+ texCoord.y *= -sign(texCoord.z);
+ texCoord += 0.5;
+
+ vec4 texColor = texture2D(tex, texCoord.xy);
+ vec4 unlitColor = gl_Color * mix(basicColor, vec4(texColor.xyz, 1.0), texColor.w);
+ vec4 litColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+
+ vec3 R = 2.0 * dot(-position, N) * N + position;
+ vec4 reflectedColor = textureCube(env, R * mat3(view[0].xyz, view[1].xyz, view[2].xyz));
+ gl_FragColor = mix(litColor, reflectedColor, 0.2 + 0.8 * pow(1.0 + dot(N, normalize(position)), 2.0));
+}
diff --git a/demos/boxes/glass.fsh b/demos/boxes/glass.fsh
new file mode 100644
index 0000000..2b59a0a
--- /dev/null
+++ b/demos/boxes/glass.fsh
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+
+// Some arbitrary values
+// Arrays don't work here on glsl < 120, apparently.
+//const float coeffs[6] = float[6](1.0/4.0, 1.0/4.1, 1.0/4.2, 1.0/4.3, 1.0/4.4, 1.0/4.5);
+float coeffs(int i)
+{
+ return 1.0 / (3.0 + 0.1 * float(i));
+}
+
+void main()
+{
+ vec3 N = normalize(normal);
+ vec3 I = -normalize(position);
+ mat3 V = mat3(view[0].xyz, view[1].xyz, view[2].xyz);
+ float IdotN = dot(I, N);
+ float scales[6];
+ vec3 C[6];
+ for (int i = 0; i < 6; ++i) {
+ scales[i] = (IdotN - sqrt(1.0 - coeffs(i) + coeffs(i) * (IdotN * IdotN)));
+ C[i] = textureCube(env, (-I + coeffs(i) * N) * V).xyz;
+ }
+ vec4 refractedColor = 0.25 * vec4(C[5].x + 2.0*C[0].x + C[1].x, C[1].y + 2.0*C[2].y + C[3].y,
+ C[3].z + 2.0*C[4].z + C[5].z, 4.0);
+
+ vec3 R = 2.0 * dot(-position, N) * N + position;
+ vec4 reflectedColor = textureCube(env, R * V);
+
+ gl_FragColor = mix(refractedColor, reflectedColor, 0.4 + 0.6 * pow(1.0 - IdotN, 2.0));
+}
diff --git a/demos/boxes/glbuffers.cpp b/demos/boxes/glbuffers.cpp
new file mode 100644
index 0000000..b2a594e
--- /dev/null
+++ b/demos/boxes/glbuffers.cpp
@@ -0,0 +1,390 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "glbuffers.h"
+
+//============================================================================//
+// GLTexture //
+//============================================================================//
+
+GLTexture::GLTexture() : m_texture(0), m_failed(false)
+{
+ glGenTextures(1, &m_texture);
+}
+
+GLTexture::~GLTexture()
+{
+ glDeleteTextures(1, &m_texture);
+}
+
+//============================================================================//
+// GLTexture2D //
+//============================================================================//
+
+GLTexture2D::GLTexture2D(int width, int height)
+{
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+
+GLTexture2D::GLTexture2D(const QString& fileName, int width, int height)
+{
+ // TODO: Add error handling.
+ QImage image(fileName);
+
+ if (image.isNull()) {
+ m_failed = true;
+ return;
+ }
+
+ image = image.convertToFormat(QImage::Format_ARGB32);
+
+ //qDebug() << "Image size:" << image.width() << "x" << image.height();
+ if (width <= 0)
+ width = image.width();
+ if (height <= 0)
+ height = image.height();
+ if (width != image.width() || height != image.height())
+ image = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+
+ // Works on x86, so probably works on all little-endian systems.
+ // Does it work on big-endian systems?
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, image.width(), image.height(), 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void GLTexture2D::load(int width, int height, QRgb *data)
+{
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ glBindTexture(GL_TEXTURE_2D, 0);
+}
+
+void GLTexture2D::bind()
+{
+ glBindTexture(GL_TEXTURE_2D, m_texture);
+ glEnable(GL_TEXTURE_2D);
+}
+
+void GLTexture2D::unbind()
+{
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDisable(GL_TEXTURE_2D);
+}
+
+
+//============================================================================//
+// GLTexture3D //
+//============================================================================//
+
+GLTexture3D::GLTexture3D(int width, int height, int depth)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLTexture3D::GLTexture3D", glTexImage3D, return)
+
+ glBindTexture(GL_TEXTURE_3D, m_texture);
+ glTexImage3D(GL_TEXTURE_3D, 0, 4, width, height, depth, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_3D, 0);
+}
+
+void GLTexture3D::load(int width, int height, int depth, QRgb *data)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLTexture3D::load", glTexImage3D, return)
+
+ glBindTexture(GL_TEXTURE_3D, m_texture);
+ glTexImage3D(GL_TEXTURE_3D, 0, 4, width, height, depth, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ glBindTexture(GL_TEXTURE_3D, 0);
+}
+
+void GLTexture3D::bind()
+{
+ glBindTexture(GL_TEXTURE_3D, m_texture);
+ glEnable(GL_TEXTURE_3D);
+}
+
+void GLTexture3D::unbind()
+{
+ glBindTexture(GL_TEXTURE_3D, 0);
+ glDisable(GL_TEXTURE_3D);
+}
+
+//============================================================================//
+// GLTextureCube //
+//============================================================================//
+
+GLTextureCube::GLTextureCube(int size)
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+
+ for (int i = 0; i < 6; ++i)
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 4, size, size, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+}
+
+GLTextureCube::GLTextureCube(const QStringList& fileNames, int size)
+{
+ // TODO: Add error handling.
+
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+
+ int index = 0;
+ foreach (QString file, fileNames) {
+ QImage image(file);
+ if (image.isNull()) {
+ m_failed = true;
+ break;
+ }
+
+ image = image.convertToFormat(QImage::Format_ARGB32);
+
+ //qDebug() << "Image size:" << image.width() << "x" << image.height();
+ if (size <= 0)
+ size = image.width();
+ if (size != image.width() || size != image.height())
+ image = image.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ // Works on x86, so probably works on all little-endian systems.
+ // Does it work on big-endian systems?
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, 0, 4, image.width(), image.height(), 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
+
+ if (++index == 6)
+ break;
+ }
+
+ // Clear remaining faces.
+ while (index < 6) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, 0, 4, size, size, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, 0);
+ ++index;
+ }
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+}
+
+void GLTextureCube::load(int size, int face, QRgb *data)
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, 4, size, size, 0,
+ GL_BGRA, GL_UNSIGNED_BYTE, data);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+}
+
+void GLTextureCube::bind()
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
+ glEnable(GL_TEXTURE_CUBE_MAP);
+}
+
+void GLTextureCube::unbind()
+{
+ glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
+ glDisable(GL_TEXTURE_CUBE_MAP);
+}
+
+//============================================================================//
+// GLFrameBufferObject //
+//============================================================================//
+
+GLFrameBufferObject::GLFrameBufferObject(int width, int height)
+ : m_fbo(0)
+ , m_depthBuffer(0)
+ , m_width(width)
+ , m_height(height)
+ , m_failed(false)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::GLFrameBufferObject",
+ glGenFramebuffersEXT && glGenRenderbuffersEXT && glBindRenderbufferEXT && glRenderbufferStorageEXT, return)
+
+ // TODO: share depth buffers of same size
+ glGenFramebuffersEXT(1, &m_fbo);
+ //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glGenRenderbuffersEXT(1, &m_depthBuffer);
+ glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
+ glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, m_width, m_height);
+ //glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
+ //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+}
+
+GLFrameBufferObject::~GLFrameBufferObject()
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::~GLFrameBufferObject",
+ glDeleteFramebuffersEXT && glDeleteRenderbuffersEXT, return)
+
+ glDeleteFramebuffersEXT(1, &m_fbo);
+ glDeleteRenderbuffersEXT(1, &m_depthBuffer);
+}
+
+void GLFrameBufferObject::setAsRenderTarget(bool state)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::setAsRenderTarget", glBindFramebufferEXT, return)
+
+ if (state) {
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
+ glPushAttrib(GL_VIEWPORT_BIT);
+ glViewport(0, 0, m_width, m_height);
+ } else {
+ glPopAttrib();
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ }
+}
+
+bool GLFrameBufferObject::isComplete()
+{
+ GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::isComplete", glCheckFramebufferStatusEXT, return false)
+
+ return GL_FRAMEBUFFER_COMPLETE_EXT == glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+}
+
+//============================================================================//
+// GLRenderTargetCube //
+//============================================================================//
+
+GLRenderTargetCube::GLRenderTargetCube(int size)
+ : GLTextureCube(size)
+ , m_fbo(size, size)
+{
+}
+
+void GLRenderTargetCube::begin(int face)
+{
+ GLBUFFERS_ASSERT_OPENGL("GLRenderTargetCube::begin",
+ glFramebufferTexture2DEXT && glFramebufferRenderbufferEXT, return)
+
+ m_fbo.setAsRenderTarget(true);
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, m_texture, 0);
+ glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_fbo.m_depthBuffer);
+}
+
+void GLRenderTargetCube::end()
+{
+ m_fbo.setAsRenderTarget(false);
+}
+
+void GLRenderTargetCube::getViewMatrix(gfx::Matrix4x4f& mat, int face)
+{
+ if (face < 0 || face >= 6) {
+ qWarning("GLRenderTargetCube::getViewMatrix: 'face' must be in the range [0, 6). (face == %d)", face);
+ return;
+ }
+
+ static int perm[6][3] = {
+ {2, 1, 0},
+ {2, 1, 0},
+ {0, 2, 1},
+ {0, 2, 1},
+ {0, 1, 2},
+ {0, 1, 2},
+ };
+
+ static float signs[6][3] = {
+ {-1.0f, -1.0f, -1.0f},
+ {+1.0f, -1.0f, +1.0f},
+ {+1.0f, +1.0f, -1.0f},
+ {+1.0f, -1.0f, +1.0f},
+ {+1.0f, -1.0f, -1.0f},
+ {-1.0f, -1.0f, +1.0f},
+ };
+
+ memset(mat.bits(), 0, sizeof(float) * 16);
+ for (int i = 0; i < 3; ++i)
+ mat(perm[face][i], i) = signs[face][i];
+ mat(3, 3) = 1.0f;
+}
+
+void GLRenderTargetCube::getProjectionMatrix(gfx::Matrix4x4f& mat, float nearZ, float farZ)
+{
+ float proj[] = {
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, (nearZ+farZ)/(nearZ-farZ), -1.0f,
+ 0.0f, 0.0f, 2.0f*nearZ*farZ/(nearZ-farZ), 0.0f,
+ };
+
+ memcpy(mat.bits(), proj, sizeof(float) * 16);
+}
diff --git a/demos/boxes/glbuffers.h b/demos/boxes/glbuffers.h
new file mode 100644
index 0000000..88de4e8
--- /dev/null
+++ b/demos/boxes/glbuffers.h
@@ -0,0 +1,362 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLBUFFERS_H
+#define GLBUFFERS_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "vector.h"
+
+#define BUFFER_OFFSET(i) ((char*)0 + (i))
+#define SIZE_OF_MEMBER(cls, member) sizeof(static_cast<cls *>(0)->member)
+
+#define GLBUFFERS_ASSERT_OPENGL(prefix, assertion, returnStatement) \
+if (m_failed || !(assertion)) { \
+ if (!m_failed) qCritical(prefix ": The necessary OpenGL functions are not available."); \
+ m_failed = true; \
+ returnStatement; \
+}
+
+class GLTexture
+{
+public:
+ GLTexture();
+ virtual ~GLTexture();
+ virtual void bind() = 0;
+ virtual void unbind() = 0;
+ virtual bool failed() const {return m_failed;}
+protected:
+ GLuint m_texture;
+ bool m_failed;
+};
+
+class GLFrameBufferObject
+{
+public:
+ friend class GLRenderTargetCube;
+ // friend class GLRenderTarget2D;
+
+ GLFrameBufferObject(int width, int height);
+ virtual ~GLFrameBufferObject();
+ bool isComplete();
+ virtual bool failed() const {return m_failed;}
+protected:
+ void setAsRenderTarget(bool state = true);
+ GLuint m_fbo;
+ GLuint m_depthBuffer;
+ int m_width, m_height;
+ bool m_failed;
+};
+
+class GLTexture2D : public GLTexture
+{
+public:
+ GLTexture2D(int width, int height);
+ GLTexture2D(const QString& fileName, int width = 0, int height = 0);
+ void load(int width, int height, QRgb *data);
+ virtual void bind();
+ virtual void unbind();
+};
+
+class GLTexture3D : public GLTexture
+{
+public:
+ GLTexture3D(int width, int height, int depth);
+ // TODO: Implement function below
+ //GLTexture3D(const QString& fileName, int width = 0, int height = 0);
+ void load(int width, int height, int depth, QRgb *data);
+ virtual void bind();
+ virtual void unbind();
+};
+
+class GLTextureCube : public GLTexture
+{
+public:
+ GLTextureCube(int size);
+ GLTextureCube(const QStringList& fileNames, int size = 0);
+ void load(int size, int face, QRgb *data);
+ virtual void bind();
+ virtual void unbind();
+};
+
+// TODO: Define and implement class below
+//class GLRenderTarget2D : public GLTexture2D
+
+class GLRenderTargetCube : public GLTextureCube
+{
+public:
+ GLRenderTargetCube(int size);
+ // begin rendering to one of the cube's faces. 0 <= face < 6
+ void begin(int face);
+ // end rendering
+ void end();
+ virtual bool failed() {return m_failed || m_fbo.failed();}
+
+ static void getViewMatrix(gfx::Matrix4x4f& mat, int face);
+ static void getProjectionMatrix(gfx::Matrix4x4f& mat, float nearZ, float farZ);
+private:
+ GLFrameBufferObject m_fbo;
+};
+
+struct VertexDescription
+{
+ enum
+ {
+ Null = 0, // Terminates a VertexDescription array
+ Position,
+ TexCoord,
+ Normal,
+ Color,
+ };
+ int field; // Position, TexCoord, Normal, Color
+ int type; // GL_FLOAT, GL_UNSIGNED_BYTE
+ int count; // number of elements
+ int offset; // field's offset into vertex struct
+ int index; // 0 (unused at the moment)
+};
+
+// Implementation of interleaved buffers.
+// 'T' is a struct which must include a null-terminated static array
+// 'VertexDescription* description'.
+// Example:
+/*
+struct Vertex
+{
+ GLfloat position[3];
+ GLfloat texCoord[2];
+ GLfloat normal[3];
+ GLbyte color[4];
+ static VertexDescription description[];
+};
+
+VertexDescription Vertex::description[] = {
+ {VertexDescription::Position, GL_FLOAT, SIZE_OF_MEMBER(Vertex, position) / sizeof(GLfloat), offsetof(Vertex, position), 0},
+ {VertexDescription::TexCoord, GL_FLOAT, SIZE_OF_MEMBER(Vertex, texCoord) / sizeof(GLfloat), offsetof(Vertex, texCoord), 0},
+ {VertexDescription::Normal, GL_FLOAT, SIZE_OF_MEMBER(Vertex, normal) / sizeof(GLfloat), offsetof(Vertex, normal), 0},
+ {VertexDescription::Color, GL_BYTE, SIZE_OF_MEMBER(Vertex, color) / sizeof(GLbyte), offsetof(Vertex, color), 0},
+ {VertexDescription::Null, 0, 0, 0, 0},
+};
+*/
+template<class T>
+class GLVertexBuffer
+{
+public:
+ GLVertexBuffer(int length, const T *data = 0, int mode = GL_STATIC_DRAW)
+ : m_length(0)
+ , m_mode(mode)
+ , m_buffer(0)
+ , m_failed(false)
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::GLVertexBuffer", glGenBuffers && glBindBuffer && glBufferData, return)
+
+ glGenBuffers(1, &m_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ glBufferData(GL_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode);
+ }
+
+ ~GLVertexBuffer()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::~GLVertexBuffer", glDeleteBuffers, return)
+
+ glDeleteBuffers(1, &m_buffer);
+ }
+
+ void bind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::bind", glBindBuffer, return)
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) {
+ switch (desc->field) {
+ case VertexDescription::Position:
+ glVertexPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_VERTEX_ARRAY);
+ break;
+ case VertexDescription::TexCoord:
+ glTexCoordPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ break;
+ case VertexDescription::Normal:
+ glNormalPointer(desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_NORMAL_ARRAY);
+ break;
+ case VertexDescription::Color:
+ glColorPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset));
+ glEnableClientState(GL_COLOR_ARRAY);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ void unbind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unbind", glBindBuffer, return)
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) {
+ switch (desc->field) {
+ case VertexDescription::Position:
+ glDisableClientState(GL_VERTEX_ARRAY);
+ break;
+ case VertexDescription::TexCoord:
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ break;
+ case VertexDescription::Normal:
+ glDisableClientState(GL_NORMAL_ARRAY);
+ break;
+ case VertexDescription::Color:
+ glDisableClientState(GL_COLOR_ARRAY);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ int length() const {return m_length;}
+
+ T *lock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::lock", glBindBuffer && glMapBuffer, return 0)
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ //glBufferData(GL_ARRAY_BUFFER, m_length, NULL, m_mode);
+ GLvoid* buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE);
+ m_failed = (buffer == 0);
+ return reinterpret_cast<T *>(buffer);
+ }
+
+ void unlock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unlock", glBindBuffer && glUnmapBuffer, return)
+
+ glBindBuffer(GL_ARRAY_BUFFER, m_buffer);
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+ }
+
+ bool failed()
+ {
+ return m_failed;
+ }
+
+private:
+ int m_length, m_mode;
+ GLuint m_buffer;
+ bool m_failed;
+};
+
+template<class T>
+class GLIndexBuffer
+{
+public:
+ GLIndexBuffer(int length, const T *data = 0, int mode = GL_STATIC_DRAW)
+ : m_length(0)
+ , m_mode(mode)
+ , m_buffer(0)
+ , m_failed(false)
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::GLIndexBuffer", glGenBuffers && glBindBuffer && glBufferData, return)
+
+ glGenBuffers(1, &m_buffer);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode);
+ }
+
+ ~GLIndexBuffer()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::~GLIndexBuffer", glDeleteBuffers, return)
+
+ glDeleteBuffers(1, &m_buffer);
+ }
+
+ void bind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::bind", glBindBuffer, return)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ }
+
+ void unbind()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unbind", glBindBuffer, return)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ int length() const {return m_length;}
+
+ T *lock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::lock", glBindBuffer && glMapBuffer, return 0)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ GLvoid* buffer = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE);
+ m_failed = (buffer == 0);
+ return reinterpret_cast<T *>(buffer);
+ }
+
+ void unlock()
+ {
+ GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unlock", glBindBuffer && glUnmapBuffer, return)
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer);
+ glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
+ }
+
+ bool failed()
+ {
+ return m_failed;
+ }
+
+private:
+ int m_length, m_mode;
+ GLuint m_buffer;
+ bool m_failed;
+};
+
+#endif
diff --git a/demos/boxes/glextensions.cpp b/demos/boxes/glextensions.cpp
new file mode 100644
index 0000000..59256a8
--- /dev/null
+++ b/demos/boxes/glextensions.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "glextensions.h"
+
+#define RESOLVE_GL_FUNC(f) ok &= bool((f = (_gl##f) context->getProcAddress(QLatin1String("gl" #f))));
+
+bool GLExtensionFunctions::resolve(const QGLContext *context)
+{
+ bool ok = true;
+
+ RESOLVE_GL_FUNC(CreateShaderObjectARB)
+ RESOLVE_GL_FUNC(ShaderSourceARB)
+ RESOLVE_GL_FUNC(CompileShaderARB)
+ RESOLVE_GL_FUNC(GetObjectParameterivARB)
+ RESOLVE_GL_FUNC(DeleteObjectARB)
+ RESOLVE_GL_FUNC(GetInfoLogARB)
+ RESOLVE_GL_FUNC(CreateProgramObjectARB)
+ RESOLVE_GL_FUNC(AttachObjectARB)
+ RESOLVE_GL_FUNC(DetachObjectARB)
+ RESOLVE_GL_FUNC(LinkProgramARB)
+ RESOLVE_GL_FUNC(UseProgramObjectARB)
+ RESOLVE_GL_FUNC(GetUniformLocationARB)
+ RESOLVE_GL_FUNC(Uniform1iARB)
+ RESOLVE_GL_FUNC(Uniform1fARB)
+ RESOLVE_GL_FUNC(Uniform4fARB)
+ RESOLVE_GL_FUNC(UniformMatrix4fvARB)
+
+ RESOLVE_GL_FUNC(GenFramebuffersEXT)
+ RESOLVE_GL_FUNC(GenRenderbuffersEXT)
+ RESOLVE_GL_FUNC(BindRenderbufferEXT)
+ RESOLVE_GL_FUNC(RenderbufferStorageEXT)
+ RESOLVE_GL_FUNC(DeleteFramebuffersEXT)
+ RESOLVE_GL_FUNC(DeleteRenderbuffersEXT)
+ RESOLVE_GL_FUNC(BindFramebufferEXT)
+ RESOLVE_GL_FUNC(FramebufferTexture2DEXT)
+ RESOLVE_GL_FUNC(FramebufferRenderbufferEXT)
+ RESOLVE_GL_FUNC(CheckFramebufferStatusEXT)
+
+ RESOLVE_GL_FUNC(ActiveTexture)
+ RESOLVE_GL_FUNC(TexImage3D)
+
+ RESOLVE_GL_FUNC(GenBuffers)
+ RESOLVE_GL_FUNC(BindBuffer)
+ RESOLVE_GL_FUNC(BufferData)
+ RESOLVE_GL_FUNC(DeleteBuffers)
+ RESOLVE_GL_FUNC(MapBuffer)
+ RESOLVE_GL_FUNC(UnmapBuffer)
+
+ return ok;
+}
+
+bool GLExtensionFunctions::glslSupported() {
+ return CreateShaderObjectARB
+ && CreateShaderObjectARB
+ && ShaderSourceARB
+ && CompileShaderARB
+ && GetObjectParameterivARB
+ && DeleteObjectARB
+ && GetInfoLogARB
+ && CreateProgramObjectARB
+ && AttachObjectARB
+ && DetachObjectARB
+ && LinkProgramARB
+ && UseProgramObjectARB
+ && GetUniformLocationARB
+ && Uniform1iARB
+ && Uniform1fARB
+ && Uniform4fARB
+ && UniformMatrix4fvARB;
+}
+
+bool GLExtensionFunctions::fboSupported() {
+ return GenFramebuffersEXT
+ && GenRenderbuffersEXT
+ && BindRenderbufferEXT
+ && RenderbufferStorageEXT
+ && DeleteFramebuffersEXT
+ && DeleteRenderbuffersEXT
+ && BindFramebufferEXT
+ && FramebufferTexture2DEXT
+ && FramebufferRenderbufferEXT
+ && CheckFramebufferStatusEXT;
+}
+
+bool GLExtensionFunctions::openGL15Supported() {
+ return ActiveTexture
+ && TexImage3D
+ && GenBuffers
+ && BindBuffer
+ && BufferData
+ && DeleteBuffers
+ && MapBuffer
+ && UnmapBuffer;
+}
+
+#undef RESOLVE_GL_FUNC
diff --git a/demos/boxes/glextensions.h b/demos/boxes/glextensions.h
new file mode 100644
index 0000000..74617d6
--- /dev/null
+++ b/demos/boxes/glextensions.h
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLEXTENSIONS_H
+#define GLEXTENSIONS_H
+
+#include <QtOpenGL>
+
+/*
+Functions resolved:
+
+glCreateShaderObjectARB
+glShaderSourceARB
+glCompileShaderARB
+glGetObjectParameterivARB
+glDeleteObjectARB
+glGetInfoLogARB
+glCreateProgramObjectARB
+glAttachObjectARB
+glDetachObjectARB
+glLinkProgramARB
+glUseProgramObjectARB
+glGetUniformLocationARB
+glUniform1iARB
+glUniform1fARB
+glUniform4fARB
+glUniformMatrix4fvARB
+
+glGenFramebuffersEXT
+glGenRenderbuffersEXT
+glBindRenderbufferEXT
+glRenderbufferStorageEXT
+glDeleteFramebuffersEXT
+glDeleteRenderbuffersEXT
+glBindFramebufferEXT
+glFramebufferTexture2DEXT
+glFramebufferRenderbufferEXT
+glCheckFramebufferStatusEXT
+
+glActiveTexture
+glTexImage3D
+
+glGenBuffers
+glBindBuffer
+glBufferData
+glDeleteBuffers
+glMapBuffer
+glUnmapBuffer
+*/
+
+#ifndef Q_WS_MAC
+# ifndef APIENTRYP
+# ifdef APIENTRY
+# define APIENTRYP APIENTRY *
+# else
+# define APIENTRY
+# define APIENTRYP *
+# endif
+# endif
+#else
+# define APIENTRY
+# define APIENTRYP *
+#endif
+
+#ifndef GL_VERSION_1_2
+#define GL_TEXTURE_3D 0x806F
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_BGRA 0x80E1
+#endif
+
+#ifndef GL_VERSION_1_3
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+//#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+//#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+//#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#endif
+
+#ifndef GL_VERSION_1_5
+typedef ptrdiff_t GLsizeiptr;
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_READ_WRITE 0x88BA
+#define GL_STATIC_DRAW 0x88E4
+#endif
+
+#ifndef GL_EXT_framebuffer_object
+#define GL_RENDERBUFFER_EXT 0x8D41
+#define GL_FRAMEBUFFER_EXT 0x8D40
+#define GL_FRAMEBUFFER_COMPLETE_EXT 0x8CD5
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_DEPTH_ATTACHMENT_EXT 0x8D00
+#endif
+
+#ifndef GL_ARB_vertex_shader
+#define GL_VERTEX_SHADER_ARB 0x8B31
+#endif
+
+#ifndef GL_ARB_fragment_shader
+#define GL_FRAGMENT_SHADER_ARB 0x8B30
+#endif
+
+#ifndef GL_ARB_shader_objects
+typedef char GLcharARB;
+typedef unsigned int GLhandleARB;
+#define GL_OBJECT_COMPILE_STATUS_ARB 0x8B81
+#define GL_OBJECT_LINK_STATUS_ARB 0x8B82
+#define GL_OBJECT_INFO_LOG_LENGTH_ARB 0x8B84
+#endif
+
+typedef GLhandleARB (APIENTRY *_glCreateShaderObjectARB) (GLenum);
+typedef void (APIENTRY *_glShaderSourceARB) (GLhandleARB, GLuint, const GLcharARB**, GLint *);
+typedef void (APIENTRY *_glCompileShaderARB) (GLhandleARB);
+typedef void (APIENTRY *_glGetObjectParameterivARB) (GLhandleARB, GLenum, int *);
+typedef void (APIENTRY *_glDeleteObjectARB) (GLhandleARB);
+typedef void (APIENTRY *_glGetInfoLogARB) (GLhandleARB, GLsizei, GLsizei *, GLcharARB *);
+typedef GLhandleARB (APIENTRY *_glCreateProgramObjectARB) ();
+typedef void (APIENTRY *_glAttachObjectARB) (GLhandleARB, GLhandleARB);
+typedef void (APIENTRY *_glDetachObjectARB) (GLhandleARB, GLhandleARB);
+typedef void (APIENTRY *_glLinkProgramARB) (GLhandleARB);
+typedef void (APIENTRY *_glUseProgramObjectARB) (GLhandleARB);
+typedef GLint (APIENTRY *_glGetUniformLocationARB) (GLhandleARB, const GLcharARB *);
+typedef void (APIENTRY *_glUniform1iARB) (GLint, GLint);
+typedef void (APIENTRY *_glUniform1fARB) (GLint, GLfloat);
+typedef void (APIENTRY *_glUniform4fARB) (GLint, GLfloat, GLfloat, GLfloat, GLfloat);
+typedef void (APIENTRY *_glUniformMatrix4fvARB) (GLint, GLuint, GLboolean, const GLfloat *);
+
+typedef void (APIENTRY *_glGenFramebuffersEXT) (GLsizei, GLuint *);
+typedef void (APIENTRY *_glGenRenderbuffersEXT) (GLsizei, GLuint *);
+typedef void (APIENTRY *_glBindRenderbufferEXT) (GLenum, GLuint);
+typedef void (APIENTRY *_glRenderbufferStorageEXT) (GLenum, GLenum, GLsizei, GLsizei);
+typedef void (APIENTRY *_glDeleteFramebuffersEXT) (GLsizei, const GLuint*);
+typedef void (APIENTRY *_glDeleteRenderbuffersEXT) (GLsizei, const GLuint*);
+typedef void (APIENTRY *_glBindFramebufferEXT) (GLenum, GLuint);
+typedef void (APIENTRY *_glFramebufferTexture2DEXT) (GLenum, GLenum, GLenum, GLuint, GLint);
+typedef void (APIENTRY *_glFramebufferRenderbufferEXT) (GLenum, GLenum, GLenum, GLuint);
+typedef GLenum (APIENTRY *_glCheckFramebufferStatusEXT) (GLenum);
+
+typedef void (APIENTRY *_glActiveTexture) (GLenum);
+typedef void (APIENTRY *_glTexImage3D) (GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid *);
+
+typedef void (APIENTRY *_glGenBuffers) (GLsizei, GLuint *);
+typedef void (APIENTRY *_glBindBuffer) (GLenum, GLuint);
+typedef void (APIENTRY *_glBufferData) (GLenum, GLsizeiptr, const GLvoid *, GLenum);
+typedef void (APIENTRY *_glDeleteBuffers) (GLsizei, const GLuint *);
+typedef void *(APIENTRY *_glMapBuffer) (GLenum, GLenum);
+typedef GLboolean (APIENTRY *_glUnmapBuffer) (GLenum);
+
+struct GLExtensionFunctions
+{
+ bool resolve(const QGLContext *context);
+
+ bool glslSupported();
+ bool fboSupported();
+ bool openGL15Supported(); // the rest: multi-texture, 3D-texture, vertex buffer objects
+
+ _glCreateShaderObjectARB CreateShaderObjectARB;
+ _glShaderSourceARB ShaderSourceARB;
+ _glCompileShaderARB CompileShaderARB;
+ _glGetObjectParameterivARB GetObjectParameterivARB;
+ _glDeleteObjectARB DeleteObjectARB;
+ _glGetInfoLogARB GetInfoLogARB;
+ _glCreateProgramObjectARB CreateProgramObjectARB;
+ _glAttachObjectARB AttachObjectARB;
+ _glDetachObjectARB DetachObjectARB;
+ _glLinkProgramARB LinkProgramARB;
+ _glUseProgramObjectARB UseProgramObjectARB;
+ _glGetUniformLocationARB GetUniformLocationARB;
+ _glUniform1iARB Uniform1iARB;
+ _glUniform1fARB Uniform1fARB;
+ _glUniform4fARB Uniform4fARB;
+ _glUniformMatrix4fvARB UniformMatrix4fvARB;
+
+ _glGenFramebuffersEXT GenFramebuffersEXT;
+ _glGenRenderbuffersEXT GenRenderbuffersEXT;
+ _glBindRenderbufferEXT BindRenderbufferEXT;
+ _glRenderbufferStorageEXT RenderbufferStorageEXT;
+ _glDeleteFramebuffersEXT DeleteFramebuffersEXT;
+ _glDeleteRenderbuffersEXT DeleteRenderbuffersEXT;
+ _glBindFramebufferEXT BindFramebufferEXT;
+ _glFramebufferTexture2DEXT FramebufferTexture2DEXT;
+ _glFramebufferRenderbufferEXT FramebufferRenderbufferEXT;
+ _glCheckFramebufferStatusEXT CheckFramebufferStatusEXT;
+
+ _glActiveTexture ActiveTexture;
+ _glTexImage3D TexImage3D;
+
+ _glGenBuffers GenBuffers;
+ _glBindBuffer BindBuffer;
+ _glBufferData BufferData;
+ _glDeleteBuffers DeleteBuffers;
+ _glMapBuffer MapBuffer;
+ _glUnmapBuffer UnmapBuffer;
+};
+
+inline GLExtensionFunctions &getGLExtensionFunctions()
+{
+ static GLExtensionFunctions funcs;
+ return funcs;
+}
+
+#define glCreateShaderObjectARB getGLExtensionFunctions().CreateShaderObjectARB
+#define glShaderSourceARB getGLExtensionFunctions().ShaderSourceARB
+#define glCompileShaderARB getGLExtensionFunctions().CompileShaderARB
+#define glGetObjectParameterivARB getGLExtensionFunctions().GetObjectParameterivARB
+#define glDeleteObjectARB getGLExtensionFunctions().DeleteObjectARB
+#define glGetInfoLogARB getGLExtensionFunctions().GetInfoLogARB
+#define glCreateProgramObjectARB getGLExtensionFunctions().CreateProgramObjectARB
+#define glAttachObjectARB getGLExtensionFunctions().AttachObjectARB
+#define glDetachObjectARB getGLExtensionFunctions().DetachObjectARB
+#define glLinkProgramARB getGLExtensionFunctions().LinkProgramARB
+#define glUseProgramObjectARB getGLExtensionFunctions().UseProgramObjectARB
+#define glGetUniformLocationARB getGLExtensionFunctions().GetUniformLocationARB
+#define glUniform1iARB getGLExtensionFunctions().Uniform1iARB
+#define glUniform1fARB getGLExtensionFunctions().Uniform1fARB
+#define glUniform4fARB getGLExtensionFunctions().Uniform4fARB
+#define glUniformMatrix4fvARB getGLExtensionFunctions().UniformMatrix4fvARB
+
+#define glGenFramebuffersEXT getGLExtensionFunctions().GenFramebuffersEXT
+#define glGenRenderbuffersEXT getGLExtensionFunctions().GenRenderbuffersEXT
+#define glBindRenderbufferEXT getGLExtensionFunctions().BindRenderbufferEXT
+#define glRenderbufferStorageEXT getGLExtensionFunctions().RenderbufferStorageEXT
+#define glDeleteFramebuffersEXT getGLExtensionFunctions().DeleteFramebuffersEXT
+#define glDeleteRenderbuffersEXT getGLExtensionFunctions().DeleteRenderbuffersEXT
+#define glBindFramebufferEXT getGLExtensionFunctions().BindFramebufferEXT
+#define glFramebufferTexture2DEXT getGLExtensionFunctions().FramebufferTexture2DEXT
+#define glFramebufferRenderbufferEXT getGLExtensionFunctions().FramebufferRenderbufferEXT
+#define glCheckFramebufferStatusEXT getGLExtensionFunctions().CheckFramebufferStatusEXT
+
+#define glActiveTexture getGLExtensionFunctions().ActiveTexture
+#define glTexImage3D getGLExtensionFunctions().TexImage3D
+
+#define glGenBuffers getGLExtensionFunctions().GenBuffers
+#define glBindBuffer getGLExtensionFunctions().BindBuffer
+#define glBufferData getGLExtensionFunctions().BufferData
+#define glDeleteBuffers getGLExtensionFunctions().DeleteBuffers
+#define glMapBuffer getGLExtensionFunctions().MapBuffer
+#define glUnmapBuffer getGLExtensionFunctions().UnmapBuffer
+
+#endif
diff --git a/demos/boxes/glshaders.cpp b/demos/boxes/glshaders.cpp
new file mode 100644
index 0000000..b6999a8
--- /dev/null
+++ b/demos/boxes/glshaders.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "glshaders.h"
+
+#define GLSHADERS_ASSERT_OPENGL(prefix, assertion, returnStatement) \
+if (m_failed || !(assertion)) { \
+ if (!m_failed) qCritical(prefix ": The necessary OpenGL functions are not available."); \
+ m_failed = true; \
+ returnStatement; \
+}
+
+
+GLShader::GLShader(const char *data, int size, GLenum shaderType)
+: m_compileError(false), m_failed(false)
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::GLShader",
+ glCreateShaderObjectARB && glShaderSourceARB && glCompileShaderARB && glGetObjectParameterivARB, return)
+
+ m_shader = glCreateShaderObjectARB(shaderType);
+
+ GLint glSize = size;
+ glShaderSourceARB(m_shader, 1, &data, &glSize);
+ glCompileShaderARB(m_shader);
+ int status;
+ glGetObjectParameterivARB(m_shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+ m_compileError = (status != 1);
+}
+
+GLShader::GLShader(const QString& fileName, GLenum shaderType)
+ : m_compileError(false), m_failed(false)
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::GLShader",
+ glCreateShaderObjectARB && glShaderSourceARB && glCompileShaderARB && glGetObjectParameterivARB, return)
+
+ m_shader = glCreateShaderObjectARB(shaderType);
+
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly)) {
+ QByteArray bytes = file.readAll();
+ GLint size = file.size();
+ const char *p = bytes.data();
+ file.close();
+ glShaderSourceARB(m_shader, 1, &p, &size);
+ glCompileShaderARB(m_shader);
+ int status;
+ glGetObjectParameterivARB(m_shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+ m_compileError = (status != 1);
+ } else {
+ m_compileError = true;
+ }
+}
+
+GLShader::~GLShader()
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::~GLShader", glDeleteObjectARB, return)
+
+ glDeleteObjectARB(m_shader);
+}
+
+QString GLShader::log()
+{
+ GLSHADERS_ASSERT_OPENGL("GLShader::log", glGetObjectParameterivARB
+ && glGetInfoLogARB, return QLatin1String("GLSL not supported."))
+
+ int length;
+ glGetObjectParameterivARB(m_shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+ char *log = new char[length + 1];
+ GLsizei glLength = length;
+ glGetInfoLogARB(m_shader, glLength, &glLength, log);
+ log[glLength] = '\0';
+ QString result(log);
+ delete log;
+ return result;
+}
+
+GLVertexShader::GLVertexShader(const char *data, int size) : GLShader(data, size, GL_VERTEX_SHADER_ARB)
+{
+}
+
+GLVertexShader::GLVertexShader(const QString& fileName) : GLShader(fileName, GL_VERTEX_SHADER_ARB)
+{
+}
+
+GLFragmentShader::GLFragmentShader(const char *data, int size) : GLShader(data, size, GL_FRAGMENT_SHADER_ARB)
+{
+}
+
+GLFragmentShader::GLFragmentShader(const QString& fileName) : GLShader(fileName, GL_FRAGMENT_SHADER_ARB)
+{
+}
+
+GLProgram::GLProgram() : m_linked(false), m_linkError(false), m_failed(false)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::GLProgram", glCreateProgramObjectARB, return)
+
+ m_program = glCreateProgramObjectARB();
+}
+
+GLProgram::~GLProgram()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::~GLProgram", glDeleteObjectARB, return)
+
+ glDeleteObjectARB(m_program);
+}
+
+void GLProgram::attach(const GLShader &shader)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::attach", glAttachObjectARB, return)
+
+ glAttachObjectARB(m_program, shader.m_shader);
+ m_linked = m_linkError = false;
+}
+
+void GLProgram::detach(const GLShader &shader)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::detach", glDetachObjectARB, return)
+
+ glDetachObjectARB(m_program, shader.m_shader);
+ m_linked = m_linkError = false;
+}
+
+bool GLProgram::failed()
+{
+ if (m_failed || m_linkError)
+ return true;
+
+ if (m_linked)
+ return false;
+
+ GLSHADERS_ASSERT_OPENGL("GLProgram::failed", glLinkProgramARB && glGetObjectParameterivARB, return true)
+
+ glLinkProgramARB(m_program);
+ int status;
+ glGetObjectParameterivARB(m_program, GL_OBJECT_LINK_STATUS_ARB, &status);
+ m_linkError = !(m_linked = (status == 1));
+ return m_linkError;
+}
+
+QString GLProgram::log()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::log", glGetObjectParameterivARB && glGetInfoLogARB,
+ return QLatin1String("Failed."))
+
+ int length;
+ glGetObjectParameterivARB(m_program, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
+ char *log = new char[length + 1];
+ GLsizei glLength = length;
+ glGetInfoLogARB(m_program, glLength, &glLength, log);
+ log[glLength] = '\0';
+ QString result(log);
+ delete log;
+ return result;
+}
+
+void GLProgram::bind()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::bind", glUseProgramObjectARB, return)
+
+ if (!failed())
+ glUseProgramObjectARB(m_program);
+}
+
+void GLProgram::unbind()
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::bind", glUseProgramObjectARB, return)
+
+ glUseProgramObjectARB(0);
+}
+
+bool GLProgram::hasParameter(const QString& name)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::hasParameter", glGetUniformLocationARB, return false)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ return -1 != glGetUniformLocationARB(m_program, asciiName.data());
+ }
+ return false;
+}
+
+void GLProgram::setInt(const QString& name, int value)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setInt", glGetUniformLocationARB && glUniform1iARB, return)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ glUniform1iARB(loc, value);
+ }
+}
+
+void GLProgram::setFloat(const QString& name, float value)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setFloat", glGetUniformLocationARB && glUniform1fARB, return)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ glUniform1fARB(loc, value);
+ }
+}
+
+void GLProgram::setColor(const QString& name, QRgb value)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setColor", glGetUniformLocationARB && glUniform4fARB, return)
+
+ //qDebug() << "Setting color" << name;
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ //qDebug() << "Location of" << name << "is" << loc;
+ QColor color(value);
+ glUniform4fARB(loc, color.redF(), color.greenF(), color.blueF(), color.alphaF());
+ }
+}
+
+void GLProgram::setMatrix(const QString& name, const gfx::Matrix4x4f &mat)
+{
+ GLSHADERS_ASSERT_OPENGL("GLProgram::setMatrix", glGetUniformLocationARB && glUniformMatrix4fvARB, return)
+
+ if (!failed()) {
+ QByteArray asciiName = name.toAscii();
+ int loc = glGetUniformLocationARB(m_program, asciiName.data());
+ //qDebug() << "Location of" << name << "is" << loc;
+ glUniformMatrix4fvARB(loc, 1, GL_FALSE, mat.bits());
+ }
+} \ No newline at end of file
diff --git a/demos/boxes/glshaders.h b/demos/boxes/glshaders.h
new file mode 100644
index 0000000..2b6209a
--- /dev/null
+++ b/demos/boxes/glshaders.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLSHADERS_H
+#define GLSHADERS_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "vector.h"
+
+class GLShader
+{
+public:
+ friend class GLProgram;
+ virtual ~GLShader();
+ bool failed() const {return m_failed;}
+ QString log();
+protected:
+ GLShader(const char *data, int size, GLenum shaderType);
+ GLShader(const QString& fileName, GLenum shaderType);
+
+ GLhandleARB m_shader;
+ bool m_compileError;
+ bool m_failed;
+};
+
+class GLVertexShader : public GLShader
+{
+public:
+ GLVertexShader(const char *data, int size);
+ GLVertexShader(const QString& fileName);
+};
+
+class GLFragmentShader : public GLShader
+{
+public:
+ GLFragmentShader(const char *data, int size);
+ GLFragmentShader(const QString& fileName);
+};
+
+class GLProgram
+{
+public:
+ GLProgram();
+ ~GLProgram();
+ void attach(const GLShader &shader);
+ void detach(const GLShader &shader);
+ void bind();
+ void unbind();
+ bool failed();
+ QString log();
+ bool hasParameter(const QString& name);
+ // use program before setting values
+ void setInt(const QString& name, int value);
+ void setFloat(const QString& name, float value);
+ void setColor(const QString& name, QRgb value);
+ void setMatrix(const QString& name, const gfx::Matrix4x4f &mat);
+ // TODO: add a bunch of set-functions for different types.
+private:
+ GLhandleARB m_program;
+ bool m_linked;
+ bool m_linkError;
+ bool m_failed;
+};
+
+#endif
diff --git a/demos/boxes/gltrianglemesh.h b/demos/boxes/gltrianglemesh.h
new file mode 100644
index 0000000..c06ce90
--- /dev/null
+++ b/demos/boxes/gltrianglemesh.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef GLTRIANGLEMESH_H
+#define GLTRIANGLEMESH_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "glbuffers.h"
+
+template<class TVertex, class TIndex>
+class GLTriangleMesh
+{
+public:
+ GLTriangleMesh(int vertexCount, int indexCount) : m_vb(vertexCount), m_ib(indexCount)
+ {
+ }
+
+ virtual ~GLTriangleMesh()
+ {
+ }
+
+ virtual void draw()
+ {
+ if (failed())
+ return;
+
+ int type = GL_UNSIGNED_INT;
+ if (sizeof(TIndex) == sizeof(char)) type = GL_UNSIGNED_BYTE;
+ if (sizeof(TIndex) == sizeof(short)) type = GL_UNSIGNED_SHORT;
+
+ m_vb.bind();
+ m_ib.bind();
+ glDrawElements(GL_TRIANGLES, m_ib.length(), type, BUFFER_OFFSET(0));
+ m_vb.unbind();
+ m_ib.unbind();
+ }
+
+ bool failed()
+ {
+ return m_vb.failed() || m_ib.failed();
+ }
+protected:
+ GLVertexBuffer<TVertex> m_vb;
+ GLIndexBuffer<TIndex> m_ib;
+};
+
+
+#endif
diff --git a/demos/boxes/granite.fsh b/demos/boxes/granite.fsh
new file mode 100644
index 0000000..9b75d1d
--- /dev/null
+++ b/demos/boxes/granite.fsh
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform sampler3D noise;
+
+//const vec4 graniteColors[3] = {vec4(0.0, 0.0, 0.0, 1), vec4(0.30, 0.15, 0.10, 1), vec4(0.80, 0.70, 0.75, 1)};
+uniform vec4 graniteColors[3];
+
+float steep(float x)
+{
+ return clamp(5.0 * x - 2.0, 0.0, 1.0);
+}
+
+void main()
+{
+ vec2 turbulence = vec2(0, 0);
+ float scale = 1.0;
+ for (int i = 0; i < 4; ++i) {
+ turbulence += scale * (texture3D(noise, gl_TexCoord[1].xyz / scale).xy - 0.5);
+ scale *= 0.5;
+ }
+
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec4 unlitColor = mix(graniteColors[1], mix(graniteColors[0], graniteColors[2], steep(0.5 + turbulence.y)), 4.0 * abs(turbulence.x));
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/main.cpp b/demos/boxes/main.cpp
new file mode 100644
index 0000000..10bbde1
--- /dev/null
+++ b/demos/boxes/main.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include "scene.h"
+
+#include <QtGui>
+#include <QGLWidget>
+
+class GraphicsView : public QGraphicsView
+{
+public:
+ GraphicsView()
+ {
+ setWindowTitle(tr("Boxes"));
+ setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ //setRenderHints(QPainter::SmoothPixmapTransform);
+ }
+
+protected:
+ void resizeEvent(QResizeEvent *event) {
+ if (scene())
+ scene()->setSceneRect(QRect(QPoint(0, 0), event->size()));
+ QGraphicsView::resizeEvent(event);
+ }
+};
+
+inline bool matchString(const char *extensionString, const char *subString)
+{
+ int subStringLength = strlen(subString);
+ return (strncmp(extensionString, subString, subStringLength) == 0)
+ && ((extensionString[subStringLength] == ' ') || (extensionString[subStringLength] == '\0'));
+}
+
+bool necessaryExtensionsSupported()
+{
+ const char *extensionString = reinterpret_cast<const char *>(glGetString(GL_EXTENSIONS));
+ const char *p = extensionString;
+
+ const int GL_EXT_FBO = 1;
+ const int GL_ARB_VS = 2;
+ const int GL_ARB_FS = 4;
+ const int GL_ARB_SO = 8;
+ int extensions = 0;
+
+ while (*p) {
+ if (matchString(p, "GL_EXT_framebuffer_object"))
+ extensions |= GL_EXT_FBO;
+ else if (matchString(p, "GL_ARB_vertex_shader"))
+ extensions |= GL_ARB_VS;
+ else if (matchString(p, "GL_ARB_fragment_shader"))
+ extensions |= GL_ARB_FS;
+ else if (matchString(p, "GL_ARB_shader_objects"))
+ extensions |= GL_ARB_SO;
+ while ((*p != ' ') && (*p != '\0'))
+ ++p;
+ if (*p == ' ')
+ ++p;
+ }
+ return (extensions == 15);
+}
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+
+ if ((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_1_5) == 0) {
+ QMessageBox::critical(0, "OpenGL features missing",
+ "OpenGL version 1.5 or higher is required to run this demo.\n"
+ "The program will now exit.");
+ return -1;
+ }
+
+ int maxTextureSize = 1024;
+ QGLWidget *widget = new QGLWidget(QGLFormat(QGL::SampleBuffers));
+ widget->makeCurrent();
+
+ if (!necessaryExtensionsSupported()) {
+ QMessageBox::critical(0, "OpenGL features missing",
+ "The OpenGL extensions required to run this demo are missing.\n"
+ "The program will now exit.");
+ delete widget;
+ return -2;
+ }
+
+ // Check if all the necessary functions are resolved.
+ if (!getGLExtensionFunctions().resolve(widget->context())) {
+ QMessageBox::critical(0, "OpenGL features missing",
+ "Failed to resolve OpenGL functions required to run this demo.\n"
+ "The program will now exit.");
+ delete widget;
+ return -3;
+ }
+
+ // TODO: Make conditional for final release
+ QMessageBox::information(0, "For your information",
+ "This demo can be GPU and CPU intensive and may\n"
+ "work poorly or not at all on your system.");
+
+ GraphicsView view;
+ view.setViewport(widget);
+ view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
+ widget->makeCurrent(); // The current context must be set before calling Scene's constructor
+ view.setScene(new Scene(1024, 768, maxTextureSize));
+ view.show();
+
+ return app.exec();
+}
+
diff --git a/demos/boxes/marble.fsh b/demos/boxes/marble.fsh
new file mode 100644
index 0000000..62d3c9f
--- /dev/null
+++ b/demos/boxes/marble.fsh
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform sampler3D noise;
+
+//const vec4 marbleColors[2] = {vec4(0.9, 0.9, 0.9, 1), vec4(0.6, 0.5, 0.5, 1)};
+uniform vec4 marbleColors[2];
+
+void main()
+{
+ float turbulence = 0.0;
+ float scale = 1.0;
+ for (int i = 0; i < 4; ++i) {
+ turbulence += scale * (texture3D(noise, 0.125 * gl_TexCoord[1].xyz / scale).x - 0.5);
+ scale *= 0.5;
+ }
+
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ vec4 unlitColor = mix(marbleColors[0], marbleColors[1], exp(-4.0 * abs(turbulence)));
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}
diff --git a/demos/boxes/parameters.par b/demos/boxes/parameters.par
new file mode 100644
index 0000000..50e2073
--- /dev/null
+++ b/demos/boxes/parameters.par
@@ -0,0 +1,5 @@
+color basicColor ff0e3d0e
+color woodColors ff5e3d33 ffcc9966
+float woodTubulence 0.1
+color graniteColors ff000000 ff4d261a ffccb3bf
+color marbleColors ffe6e6e6 ff998080
diff --git a/demos/boxes/qt-logo.jpg b/demos/boxes/qt-logo.jpg
new file mode 100644
index 0000000..4014b46
--- /dev/null
+++ b/demos/boxes/qt-logo.jpg
Binary files differ
diff --git a/demos/boxes/qt-logo.png b/demos/boxes/qt-logo.png
new file mode 100644
index 0000000..7d3e97e
--- /dev/null
+++ b/demos/boxes/qt-logo.png
Binary files differ
diff --git a/demos/boxes/qtbox.cpp b/demos/boxes/qtbox.cpp
new file mode 100644
index 0000000..0607698
--- /dev/null
+++ b/demos/boxes/qtbox.cpp
@@ -0,0 +1,469 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtbox.h"
+
+const qreal ROTATE_SPEED_X = 30.0 / 1000.0;
+const qreal ROTATE_SPEED_Y = 20.0 / 1000.0;
+const qreal ROTATE_SPEED_Z = 40.0 / 1000.0;
+const int MAX_ITEM_SIZE = 512;
+const int MIN_ITEM_SIZE = 16;
+
+//============================================================================//
+// ItemBase //
+//============================================================================//
+
+ItemBase::ItemBase(int size, int x, int y) : m_size(size), m_isResizing(false)
+{
+ setFlag(QGraphicsItem::ItemIsMovable, true);
+ setFlag(QGraphicsItem::ItemIsSelectable, true);
+ setFlag(QGraphicsItem::ItemIsFocusable, true);
+ setAcceptHoverEvents(true);
+ setPos(x, y);
+ m_startTime = QTime::currentTime();
+}
+
+ItemBase::~ItemBase()
+{
+}
+
+QRectF ItemBase::boundingRect() const
+{
+ return QRectF(-m_size / 2, -m_size / 2, m_size, m_size);
+}
+
+void ItemBase::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *)
+{
+ if (option->state & QStyle::State_Selected) {
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ if (option->state & QStyle::State_HasFocus)
+ painter->setPen(Qt::yellow);
+ else
+ painter->setPen(Qt::white);
+ painter->drawRect(boundingRect());
+
+ painter->drawLine(m_size / 2 - 9, m_size / 2, m_size / 2, m_size / 2 - 9);
+ painter->drawLine(m_size / 2 - 6, m_size / 2, m_size / 2, m_size / 2 - 6);
+ painter->drawLine(m_size / 2 - 3, m_size / 2, m_size / 2, m_size / 2 - 3);
+
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ }
+}
+
+void ItemBase::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
+{
+ if (!isSelected() && scene()) {
+ scene()->clearSelection();
+ setSelected(true);
+ }
+
+ QMenu menu;
+ QAction *delAction = menu.addAction("Delete");
+ QAction *newAction = menu.addAction("New");
+ QAction *growAction = menu.addAction("Grow");
+ QAction *shrinkAction = menu.addAction("Shrink");
+
+ QAction *selectedAction = menu.exec(event->screenPos());
+
+ if (selectedAction == delAction)
+ deleteSelectedItems(scene());
+ else if (selectedAction == newAction)
+ duplicateSelectedItems(scene());
+ else if (selectedAction == growAction)
+ growSelectedItems(scene());
+ else if (selectedAction == shrinkAction)
+ shrinkSelectedItems(scene());
+}
+
+void ItemBase::duplicateSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase)
+ scene->addItem(itemBase->createNew(itemBase->m_size, itemBase->pos().x() + itemBase->m_size, itemBase->pos().y()));
+ }
+}
+
+void ItemBase::deleteSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase)
+ delete itemBase;
+ }
+}
+
+void ItemBase::growSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase) {
+ itemBase->prepareGeometryChange();
+ itemBase->m_size *= 2;
+ if (itemBase->m_size > MAX_ITEM_SIZE)
+ itemBase->m_size = MAX_ITEM_SIZE;
+ }
+ }
+}
+
+void ItemBase::shrinkSelectedItems(QGraphicsScene *scene)
+{
+ if (!scene)
+ return;
+
+ QList<QGraphicsItem *> selected;
+ selected = scene->selectedItems();
+
+ foreach (QGraphicsItem *item, selected) {
+ ItemBase *itemBase = dynamic_cast<ItemBase *>(item);
+ if (itemBase) {
+ itemBase->prepareGeometryChange();
+ itemBase->m_size /= 2;
+ if (itemBase->m_size < MIN_ITEM_SIZE)
+ itemBase->m_size = MIN_ITEM_SIZE;
+ }
+ }
+}
+
+void ItemBase::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (m_isResizing) {
+ int dx = int(2.0 * event->pos().x());
+ int dy = int(2.0 * event->pos().y());
+ prepareGeometryChange();
+ m_size = (dx > dy ? dx : dy);
+ if (m_size < MIN_ITEM_SIZE)
+ m_size = MIN_ITEM_SIZE;
+ else if (m_size > MAX_ITEM_SIZE)
+ m_size = MAX_ITEM_SIZE;
+ } else {
+ QGraphicsItem::mouseMoveEvent(event);
+ }
+}
+
+void ItemBase::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
+{
+ if (m_isResizing || (isInResizeArea(event->pos()) && isSelected()))
+ setCursor(Qt::SizeFDiagCursor);
+ else
+ setCursor(Qt::ArrowCursor);
+ QGraphicsItem::hoverMoveEvent(event);
+}
+
+void ItemBase::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ static qreal z = 0.0;
+ setZValue(z += 1.0);
+ if (event->button() == Qt::LeftButton && isInResizeArea(event->pos())) {
+ m_isResizing = true;
+ } else {
+ QGraphicsItem::mousePressEvent(event);
+ }
+}
+
+void ItemBase::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton && m_isResizing) {
+ m_isResizing = false;
+ } else {
+ QGraphicsItem::mouseReleaseEvent(event);
+ }
+}
+
+void ItemBase::keyPressEvent(QKeyEvent *event)
+{
+ switch (event->key()) {
+ case Qt::Key_Delete:
+ deleteSelectedItems(scene());
+ break;
+ case Qt::Key_Insert:
+ duplicateSelectedItems(scene());
+ break;
+ case Qt::Key_Plus:
+ growSelectedItems(scene());
+ break;
+ case Qt::Key_Minus:
+ shrinkSelectedItems(scene());
+ break;
+ default:
+ QGraphicsItem::keyPressEvent(event);
+ break;
+ }
+}
+
+void ItemBase::wheelEvent(QGraphicsSceneWheelEvent *event)
+{
+ prepareGeometryChange();
+ m_size = int(m_size * exp(-event->delta() / 600.0));
+ if (m_size > MAX_ITEM_SIZE)
+ m_size = MAX_ITEM_SIZE;
+ else if (m_size < MIN_ITEM_SIZE)
+ m_size = MIN_ITEM_SIZE;
+}
+
+bool ItemBase::isInResizeArea(const QPointF &pos)
+{
+ return (-pos.y() < pos.x() - m_size + 9);
+}
+
+//============================================================================//
+// QtBox //
+//============================================================================//
+
+QtBox::QtBox(int size, int x, int y) : ItemBase(size, x, y), m_texture(0)
+{
+ for (int i = 0; i < 8; ++i) {
+ m_vertices[i][0] = (i & 1 ? 0.5f : -0.5f);
+ m_vertices[i][1] = (i & 2 ? 0.5f : -0.5f);
+ m_vertices[i][2] = (i & 4 ? 0.5f : -0.5f);
+ }
+ for (int i = 0; i < 4; ++i) {
+ m_texCoords[i][0] = (i & 1 ? 1.0f : 0.0f);
+ m_texCoords[i][1] = (i & 2 ? 1.0f : 0.0f);
+ }
+ memset(m_normals, 0, sizeof(m_normals));
+ for (int i = 0; i < 3; ++i) {
+ m_normals[2 * i + 0][i] = -1.0f;
+ m_normals[2 * i + 1][i] = 1.0f;
+ }
+}
+
+QtBox::~QtBox()
+{
+ if (m_texture)
+ delete m_texture;
+}
+
+ItemBase *QtBox::createNew(int size, int x, int y)
+{
+ return new QtBox(size, x, y);
+}
+
+void QtBox::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ QRectF rect = boundingRect().translated(pos());
+ float width = float(painter->device()->width());
+ float height = float(painter->device()->height());
+
+ float left = 2.0f * float(rect.left()) / width - 1.0f;
+ float right = 2.0f * float(rect.right()) / width - 1.0f;
+ float top = 1.0f - 2.0f * float(rect.top()) / height;
+ float bottom = 1.0f - 2.0f * float(rect.bottom()) / height;
+ float moveToRectMatrix[] = {
+ 0.5f * (right - left), 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.5f * (bottom - top), 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.5f * (right + left), 0.5f * (bottom + top), 0.0f, 1.0f
+ };
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(moveToRectMatrix);
+ gluPerspective(60.0, 1.0, 0.01, 10.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ //glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_NORMALIZE);
+
+ if(m_texture == 0)
+ m_texture = new GLTexture2D(":/res/boxes/qt-logo.jpg", 64, 64);
+ m_texture->bind();
+ glEnable(GL_TEXTURE_2D);
+
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ float lightColour[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float lightDir[] = {0.0f, 0.0f, 1.0f, 0.0f};
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColour);
+ glLightfv(GL_LIGHT0, GL_POSITION, lightDir);
+ glEnable(GL_LIGHT0);
+
+ glTranslatef(0.0f, 0.0f, -1.5f);
+ glRotatef(ROTATE_SPEED_X * m_startTime.msecsTo(QTime::currentTime()), 1.0f, 0.0f, 0.0f);
+ glRotatef(ROTATE_SPEED_Y * m_startTime.msecsTo(QTime::currentTime()), 0.0f, 1.0f, 0.0f);
+ glRotatef(ROTATE_SPEED_Z * m_startTime.msecsTo(QTime::currentTime()), 0.0f, 0.0f, 1.0f);
+ int dt = m_startTime.msecsTo(QTime::currentTime());
+ if (dt < 500)
+ glScalef(dt / 500.0f, dt / 500.0f, dt / 500.0f);
+
+ for (int dir = 0; dir < 3; ++dir) {
+ glColor4f(1.0f, 1.0f, 1.0f, 1.0);
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glNormal3fv(m_normals[2 * dir + 0].bits());
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ glTexCoord2fv(m_texCoords[(j << 1) | i].bits());
+ glVertex3fv(m_vertices[(i << ((dir + 2) % 3)) | (j << ((dir + 1) % 3))].bits());
+ }
+ }
+ glEnd();
+
+ glBegin(GL_TRIANGLE_STRIP);
+ glNormal3fv(m_normals[2 * dir + 1].bits());
+ for (int i = 0; i < 2; ++i) {
+ for (int j = 0; j < 2; ++j) {
+ glTexCoord2fv(m_texCoords[(j << 1) | i].bits());
+ glVertex3fv(m_vertices[(1 << dir) | (i << ((dir + 1) % 3)) | (j << ((dir + 2) % 3))].bits());
+ }
+ }
+ glEnd();
+ }
+ m_texture->unbind();
+
+ //glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_LIGHT0);
+ glDisable(GL_NORMALIZE);
+
+ glPopMatrix();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ ItemBase::paint(painter, option, widget);
+}
+
+//============================================================================//
+// CircleItem //
+//============================================================================//
+
+CircleItem::CircleItem(int size, int x, int y) : ItemBase(size, x, y)
+{
+ m_color = QColor::fromHsv(rand() % 360, 255, 255);
+}
+
+void CircleItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ int dt = m_startTime.msecsTo(QTime::currentTime());
+
+ qreal r0 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 3800) % 4000)));
+ qreal r1 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 0) % 4000)));
+ qreal r2 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 1800) % 4000)));
+ qreal r3 = 0.5 * m_size * (1.0 - exp(-0.001 * ((dt + 2000) % 4000)));
+
+ if (r0 > r1)
+ r0 = 0.0;
+ if (r2 > r3)
+ r2 = 0.0;
+
+ QPainterPath path;
+ path.moveTo(r1, 0.0);
+ path.arcTo(-r1, -r1, 2 * r1, 2 * r1, 0.0, 360.0);
+ path.lineTo(r0, 0.0);
+ path.arcTo(-r0, -r0, 2 * r0, 2 * r0, 0.0, -360.0);
+ path.closeSubpath();
+ path.moveTo(r3, 0.0);
+ path.arcTo(-r3, -r3, 2 * r3, 2 * r3, 0.0, 360.0);
+ path.lineTo(r0, 0.0);
+ path.arcTo(-r2, -r2, 2 * r2, 2 * r2, 0.0, -360.0);
+ path.closeSubpath();
+ painter->setRenderHint(QPainter::Antialiasing, true);
+ painter->setBrush(QBrush(m_color));
+ painter->setPen(Qt::NoPen);
+ painter->drawPath(path);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(Qt::SolidLine);
+ painter->setRenderHint(QPainter::Antialiasing, false);
+
+ ItemBase::paint(painter, option, widget);
+}
+
+ItemBase *CircleItem::createNew(int size, int x, int y)
+{
+ return new CircleItem(size, x, y);
+}
+
+//============================================================================//
+// SquareItem //
+//============================================================================//
+
+SquareItem::SquareItem(int size, int x, int y) : ItemBase(size, x, y)
+{
+ m_image = QPixmap(":/res/boxes/square.jpg");
+}
+
+void SquareItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ int dt = m_startTime.msecsTo(QTime::currentTime());
+ QTransform oldTransform = painter->worldTransform();
+ int dtMod = dt % 2000;
+ qreal amp = 0.002 * (dtMod < 1000 ? dtMod : 2000 - dtMod) - 1.0;
+
+ qreal scale = 0.6 + 0.2 * amp * amp;
+ painter->setWorldTransform(QTransform().rotate(15.0 * amp).scale(scale, scale), true);
+
+ painter->drawPixmap(-m_size / 2, -m_size / 2, m_size, m_size, m_image);
+
+ painter->setWorldTransform(oldTransform, false);
+ ItemBase::paint(painter, option, widget);
+}
+
+ItemBase *SquareItem::createNew(int size, int x, int y)
+{
+ return new SquareItem(size, x, y);
+}
diff --git a/demos/boxes/qtbox.h b/demos/boxes/qtbox.h
new file mode 100644
index 0000000..aae8256
--- /dev/null
+++ b/demos/boxes/qtbox.h
@@ -0,0 +1,116 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTBOX_H
+#define QTBOX_H
+
+#include <QtGui>
+
+#include "vector.h"
+#include "glbuffers.h"
+
+class ItemBase : public QObject, public QGraphicsItem
+{
+ Q_OBJECT
+public:
+ ItemBase(int size, int x, int y);
+ virtual ~ItemBase();
+ virtual QRectF boundingRect() const;
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y) = 0;
+ virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void keyPressEvent(QKeyEvent *event);
+ virtual void wheelEvent(QGraphicsSceneWheelEvent *event);
+ bool isInResizeArea(const QPointF &pos);
+
+ static void duplicateSelectedItems(QGraphicsScene *scene);
+ static void deleteSelectedItems(QGraphicsScene *scene);
+ static void growSelectedItems(QGraphicsScene *scene);
+ static void shrinkSelectedItems(QGraphicsScene *scene);
+
+ int m_size;
+ QTime m_startTime;
+ bool m_isResizing;
+};
+
+class QtBox : public ItemBase
+{
+public:
+ QtBox(int size, int x, int y);
+ virtual ~QtBox();
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y);
+private:
+ gfx::Vector3f m_vertices[8];
+ gfx::Vector2f m_texCoords[4];
+ gfx::Vector3f m_normals[6];
+ GLTexture *m_texture;
+};
+
+class CircleItem : public ItemBase
+{
+public:
+ CircleItem(int size, int x, int y);
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y);
+
+ QColor m_color;
+};
+
+class SquareItem : public ItemBase
+{
+public:
+ SquareItem(int size, int x, int y);
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+protected:
+ virtual ItemBase *createNew(int size, int x, int y);
+
+ QPixmap m_image;
+};
+
+#endif
diff --git a/demos/boxes/reflection.fsh b/demos/boxes/reflection.fsh
new file mode 100644
index 0000000..d5807ee
--- /dev/null
+++ b/demos/boxes/reflection.fsh
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+
+void main()
+{
+ vec3 N = normalize(normal);
+ vec3 R = 2.0 * dot(-position, N) * N + position;
+ gl_FragColor = textureCube(env, R * mat3(view[0].xyz, view[1].xyz, view[2].xyz));
+}
diff --git a/demos/boxes/refraction.fsh b/demos/boxes/refraction.fsh
new file mode 100644
index 0000000..f91c24d
--- /dev/null
+++ b/demos/boxes/refraction.fsh
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform samplerCube env;
+uniform mat4 view;
+
+// Arrays don't work here on glsl < 120, apparently.
+//const float coeffs[6] = float[6](1.0/2.0, 1.0/2.1, 1.0/2.2, 1.0/2.3, 1.0/2.4, 1.0/2.5);
+float coeffs(int i)
+{
+ return 1.0 / (2.0 + 0.1 * float(i));
+}
+
+void main()
+{
+ vec3 N = normalize(normal);
+ vec3 I = -normalize(position);
+ float IdotN = dot(I, N);
+ float scales[6];
+ vec3 C[6];
+ for (int i = 0; i < 6; ++i) {
+ scales[i] = (IdotN - sqrt(1.0 - coeffs(i) + coeffs(i) * (IdotN * IdotN)));
+ C[i] = textureCube(env, (-I + coeffs(i) * N) * mat3(view[0].xyz, view[1].xyz, view[2].xyz)).xyz;
+ }
+
+ gl_FragColor = 0.25 * vec4(C[5].x + 2.0*C[0].x + C[1].x, C[1].y + 2.0*C[2].y + C[3].y,
+ C[3].z + 2.0*C[4].z + C[5].z, 4.0);
+}
diff --git a/demos/boxes/roundedbox.cpp b/demos/boxes/roundedbox.cpp
new file mode 100644
index 0000000..f238da2
--- /dev/null
+++ b/demos/boxes/roundedbox.cpp
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "roundedbox.h"
+
+//============================================================================//
+// P3T2N3Vertex //
+//============================================================================//
+
+VertexDescription P3T2N3Vertex::description[] = {
+ {VertexDescription::Position, GL_FLOAT, SIZE_OF_MEMBER(P3T2N3Vertex, position) / sizeof(float), offsetof(P3T2N3Vertex, position), 0},
+ {VertexDescription::TexCoord, GL_FLOAT, SIZE_OF_MEMBER(P3T2N3Vertex, texCoord) / sizeof(float), offsetof(P3T2N3Vertex, texCoord), 0},
+ {VertexDescription::Normal, GL_FLOAT, SIZE_OF_MEMBER(P3T2N3Vertex, normal) / sizeof(float), offsetof(P3T2N3Vertex, normal), 0},
+ {VertexDescription::Null, 0, 0, 0, 0},
+};
+
+//============================================================================//
+// GLRoundedBox //
+//============================================================================//
+
+float lerp(float a, float b, float t)
+{
+ return a * (1.0f - t) + b * t;
+}
+
+GLRoundedBox::GLRoundedBox(float r, float scale, int n)
+ : GLTriangleMesh<P3T2N3Vertex, unsigned short>((n+2)*(n+3)*4, (n+1)*(n+1)*24+36+72*(n+1))
+{
+ int vidx = 0, iidx = 0;
+ int vertexCountPerCorner = (n + 2) * (n + 3) / 2;
+
+ P3T2N3Vertex *vp = m_vb.lock();
+ unsigned short *ip = m_ib.lock();
+
+ if (!vp || !ip) {
+ qWarning("GLRoundedBox::GLRoundedBox: Failed to lock vertex buffer and/or index buffer.");
+ m_ib.unlock();
+ m_vb.unlock();
+ return;
+ }
+
+ for (int corner = 0; corner < 8; ++corner) {
+ gfx::Vector3f centre;
+ centre[0] = (corner & 1 ? 1.0f : -1.0f);
+ centre[1] = (corner & 2 ? 1.0f : -1.0f);
+ centre[2] = (corner & 4 ? 1.0f : -1.0f);
+ int winding = (corner & 1) ^ ((corner >> 1) & 1) ^ (corner >> 2);
+ int offsX = ((corner ^ 1) - corner) * vertexCountPerCorner;
+ int offsY = ((corner ^ 2) - corner) * vertexCountPerCorner;
+ int offsZ = ((corner ^ 4) - corner) * vertexCountPerCorner;
+
+ // Face polygons
+ if (winding) {
+ ip[iidx++] = vidx;
+ ip[iidx++] = vidx + offsX;
+ ip[iidx++] = vidx + offsY;
+
+ ip[iidx++] = vidx + vertexCountPerCorner - n - 2;
+ ip[iidx++] = vidx + vertexCountPerCorner - n - 2 + offsY;
+ ip[iidx++] = vidx + vertexCountPerCorner - n - 2 + offsZ;
+
+ ip[iidx++] = vidx + vertexCountPerCorner - 1;
+ ip[iidx++] = vidx + vertexCountPerCorner - 1 + offsZ;
+ ip[iidx++] = vidx + vertexCountPerCorner - 1 + offsX;
+ }
+
+ for (int i = 0; i < n + 2; ++i) {
+
+ // Edge polygons
+ if (winding && i < n + 1) {
+ ip[iidx++] = vidx + i + 1;
+ ip[iidx++] = vidx;
+ ip[iidx++] = vidx + offsY + i + 1;
+ ip[iidx++] = vidx + offsY;
+ ip[iidx++] = vidx + offsY + i + 1;
+ ip[iidx++] = vidx;
+
+ ip[iidx++] = vidx + i;
+ ip[iidx++] = vidx + 2 * i + 2;
+ ip[iidx++] = vidx + i + offsX;
+ ip[iidx++] = vidx + 2 * i + offsX + 2;
+ ip[iidx++] = vidx + i + offsX;
+ ip[iidx++] = vidx + 2 * i + 2;
+
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 1 - i;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 2 - i;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 1 - i + offsZ;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 2 - i + offsZ;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 1 - i + offsZ;
+ ip[iidx++] = (corner + 1) * vertexCountPerCorner - 2 - i;
+ }
+
+ for (int j = 0; j <= i; ++j) {
+ gfx::Vector3f normal = gfx::Vector3f::vector(i - j, j, n + 1 - i).normalized();
+ gfx::Vector3f pos = centre * (0.5f - r + r * normal);
+
+ vp[vidx].position = scale * pos;
+ vp[vidx].normal = centre * normal;
+ vp[vidx].texCoord = gfx::Vector2f::vector(pos[0], pos[1]) + 0.5f;
+
+ // Corner polygons
+ if (i < n + 1) {
+ ip[iidx++] = vidx;
+ ip[iidx++] = vidx + i + 2 - winding;
+ ip[iidx++] = vidx + i + 1 + winding;
+ }
+ if (i < n) {
+ ip[iidx++] = vidx + i + 1 + winding;
+ ip[iidx++] = vidx + i + 2 - winding;
+ ip[iidx++] = vidx + 2 * i + 4;
+ }
+
+ ++vidx;
+ }
+ }
+
+ }
+
+ m_ib.unlock();
+ m_vb.unlock();
+}
+
diff --git a/demos/boxes/roundedbox.h b/demos/boxes/roundedbox.h
new file mode 100644
index 0000000..b934ade
--- /dev/null
+++ b/demos/boxes/roundedbox.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ROUNDEDBOX_H
+#define ROUNDEDBOX_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "gltrianglemesh.h"
+#include "vector.h"
+#include "glbuffers.h"
+
+struct P3T2N3Vertex
+{
+ gfx::Vector3f position;
+ gfx::Vector2f texCoord;
+ gfx::Vector3f normal;
+ static VertexDescription description[];
+};
+
+class GLRoundedBox : public GLTriangleMesh<P3T2N3Vertex, unsigned short>
+{
+public:
+ // 0 < r < 0.5, 0 <= n <= 125
+ GLRoundedBox(float r = 0.25f, float scale = 1.0f, int n = 10);
+};
+
+
+#endif
diff --git a/demos/boxes/scene.cpp b/demos/boxes/scene.cpp
new file mode 100644
index 0000000..1040e17
--- /dev/null
+++ b/demos/boxes/scene.cpp
@@ -0,0 +1,1057 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "scene.h"
+
+#include "3rdparty/fbm.h"
+
+void checkGLErrors(const QString& prefix)
+{
+ switch (glGetError()) {
+ case GL_NO_ERROR:
+ //qDebug() << prefix << tr("No error.");
+ break;
+ case GL_INVALID_ENUM:
+ qDebug() << prefix << QObject::tr("Invalid enum.");
+ break;
+ case GL_INVALID_VALUE:
+ qDebug() << prefix << QObject::tr("Invalid value.");
+ break;
+ case GL_INVALID_OPERATION:
+ qDebug() << prefix << QObject::tr("Invalid operation.");
+ break;
+ case GL_STACK_OVERFLOW:
+ qDebug() << prefix << QObject::tr("Stack overflow.");
+ break;
+ case GL_STACK_UNDERFLOW:
+ qDebug() << prefix << QObject::tr("Stack underflow.");
+ break;
+ case GL_OUT_OF_MEMORY:
+ qDebug() << prefix << QObject::tr("Out of memory.");
+ break;
+ default:
+ qDebug() << prefix << QObject::tr("Unknown error.");
+ break;
+ }
+}
+
+//============================================================================//
+// ColorEdit //
+//============================================================================//
+
+ColorEdit::ColorEdit(QRgb initialColor, int id)
+ : m_color(initialColor), m_id(id)
+{
+ QHBoxLayout *layout = new QHBoxLayout;
+ setLayout(layout);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ m_lineEdit = new QLineEdit(QString::number(m_color, 16));
+ layout->addWidget(m_lineEdit);
+
+ m_button = new QFrame;
+ QPalette palette = m_button->palette();
+ palette.setColor(QPalette::Window, QColor(m_color));
+ m_button->setPalette(palette);
+ m_button->setAutoFillBackground(true);
+ m_button->setMinimumSize(32, 0);
+ m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ m_button->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
+ layout->addWidget(m_button);
+
+ connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
+}
+
+void ColorEdit::editDone()
+{
+ bool ok;
+ QRgb newColor = m_lineEdit->text().toUInt(&ok, 16);
+ if (ok)
+ setColor(newColor);
+}
+
+void ColorEdit::mousePressEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton) {
+ QColor color(m_color);
+ QColorDialog dialog(color, 0);
+ dialog.setOption(QColorDialog::ShowAlphaChannel, true);
+// The ifdef block is a workaround for the beta, TODO: remove when bug 238525 is fixed
+#ifdef Q_WS_MAC
+ dialog.setOption(QColorDialog::DontUseNativeDialog, true);
+#endif
+ dialog.move(280, 120);
+ if (dialog.exec() == QDialog::Rejected)
+ return;
+ QRgb newColor = dialog.selectedColor().rgba();
+ if (newColor == m_color)
+ return;
+ setColor(newColor);
+ }
+}
+
+void ColorEdit::setColor(QRgb color)
+{
+ m_color = color;
+ m_lineEdit->setText(QString::number(m_color, 16)); // "Clean up" text
+ QPalette palette = m_button->palette();
+ palette.setColor(QPalette::Window, QColor(m_color));
+ m_button->setPalette(palette);
+ emit colorChanged(m_color, m_id);
+}
+
+//============================================================================//
+// FloatEdit //
+//============================================================================//
+
+FloatEdit::FloatEdit(float initialValue, int id)
+ : m_value(initialValue), m_id(id)
+{
+ QHBoxLayout *layout = new QHBoxLayout;
+ setLayout(layout);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ m_lineEdit = new QLineEdit(QString::number(m_value));
+ layout->addWidget(m_lineEdit);
+
+ connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
+}
+
+void FloatEdit::editDone()
+{
+ bool ok;
+ float newValue = m_lineEdit->text().toFloat(&ok);
+ if (ok) {
+ m_value = newValue;
+ m_lineEdit->setText(QString::number(m_value)); // "Clean up" text
+ emit valueChanged(m_value, m_id);
+ }
+}
+
+//============================================================================//
+// TwoSidedGraphicsWidget //
+//============================================================================//
+
+TwoSidedGraphicsWidget::TwoSidedGraphicsWidget(QGraphicsScene *scene)
+ : QObject(scene)
+ , m_current(0)
+ , m_angle(0)
+ , m_delta(0)
+{
+ for (int i = 0; i < 2; ++i)
+ m_proxyWidgets[i] = 0;
+}
+
+void TwoSidedGraphicsWidget::setWidget(int index, QWidget *widget)
+{
+ if (index < 0 || index >= 2)
+ {
+ qWarning("TwoSidedGraphicsWidget::setWidget: Index out of bounds, index == %d", index);
+ return;
+ }
+
+ GraphicsWidget *proxy = new GraphicsWidget;
+ proxy->setWidget(widget);
+
+ if (m_proxyWidgets[index])
+ delete m_proxyWidgets[index];
+ m_proxyWidgets[index] = proxy;
+
+ proxy->setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ proxy->setZValue(1e30); // Make sure the dialog is drawn on top of all other (OpenGL) items
+
+ if (index != m_current)
+ proxy->setVisible(false);
+
+ qobject_cast<QGraphicsScene *>(parent())->addItem(proxy);
+}
+
+QWidget *TwoSidedGraphicsWidget::widget(int index)
+{
+ if (index < 0 || index >= 2)
+ {
+ qWarning("TwoSidedGraphicsWidget::widget: Index out of bounds, index == %d", index);
+ return 0;
+ }
+ return m_proxyWidgets[index]->widget();
+}
+
+void TwoSidedGraphicsWidget::flip()
+{
+ m_delta = (m_current == 0 ? 9 : -9);
+ animateFlip();
+}
+
+void TwoSidedGraphicsWidget::animateFlip()
+{
+ m_angle += m_delta;
+ if (m_angle == 90) {
+ int old = m_current;
+ m_current ^= 1;
+ m_proxyWidgets[old]->setVisible(false);
+ m_proxyWidgets[m_current]->setVisible(true);
+ m_proxyWidgets[m_current]->setGeometry(m_proxyWidgets[old]->geometry());
+ }
+
+ QRectF r = m_proxyWidgets[m_current]->boundingRect();
+ m_proxyWidgets[m_current]->setTransform(QTransform()
+ .translate(r.width() / 2, r.height() / 2)
+ .rotate(m_angle - 180 * m_current, Qt::YAxis)
+ .translate(-r.width() / 2, -r.height() / 2));
+
+ if ((m_current == 0 && m_angle > 0) || (m_current == 1 && m_angle < 180))
+ QTimer::singleShot(25, this, SLOT(animateFlip()));
+}
+
+QVariant GraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
+{
+ if (change == ItemPositionChange && scene()) {
+ QRectF rect = boundingRect();
+ QPointF pos = value.toPointF();
+ QRectF sceneRect = scene()->sceneRect();
+ if (pos.x() + rect.left() < sceneRect.left())
+ pos.setX(sceneRect.left() - rect.left());
+ else if (pos.x() + rect.right() >= sceneRect.right())
+ pos.setX(sceneRect.right() - rect.right());
+ if (pos.y() + rect.top() < sceneRect.top())
+ pos.setY(sceneRect.top() - rect.top());
+ else if (pos.y() + rect.bottom() >= sceneRect.bottom())
+ pos.setY(sceneRect.bottom() - rect.bottom());
+ return pos;
+ }
+ return QGraphicsProxyWidget::itemChange(change, value);
+}
+
+void GraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
+{
+ setCacheMode(QGraphicsItem::NoCache);
+ setCacheMode(QGraphicsItem::ItemCoordinateCache);
+ QGraphicsProxyWidget::resizeEvent(event);
+}
+
+void GraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ painter->setRenderHint(QPainter::Antialiasing, false);
+ QGraphicsProxyWidget::paint(painter, option, widget);
+ //painter->setRenderHint(QPainter::Antialiasing, true);
+}
+
+//============================================================================//
+// RenderOptionsDialog //
+//============================================================================//
+
+RenderOptionsDialog::RenderOptionsDialog()
+ : QDialog(0, Qt::CustomizeWindowHint | Qt::WindowTitleHint)
+{
+ setWindowOpacity(0.75);
+ setWindowTitle(tr("Options (double click to flip)"));
+ QGridLayout *layout = new QGridLayout;
+ setLayout(layout);
+ layout->setColumnStretch(1, 1);
+
+ int row = 0;
+
+ QCheckBox *check = new QCheckBox(tr("Dynamic cube map"));
+ check->setCheckState(Qt::Unchecked);
+ // Dynamic cube maps are only enabled when multi-texturing and render to texture are available.
+ check->setEnabled(glActiveTexture && glGenFramebuffersEXT);
+ connect(check, SIGNAL(stateChanged(int)), this, SIGNAL(dynamicCubemapToggled(int)));
+ layout->addWidget(check, 0, 0, 1, 2);
+ ++row;
+
+ QPalette palette;
+
+ // Load all .par files
+ // .par files have a simple syntax for specifying user adjustable uniform variables.
+ QSet<QByteArray> uniforms;
+ QList<QString> filter = QStringList("*.par");
+ QList<QFileInfo> files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
+
+ foreach (QFileInfo fileInfo, files) {
+ QFile file(fileInfo.absoluteFilePath());
+ if (file.open(QIODevice::ReadOnly)) {
+ while (!file.atEnd()) {
+ QList<QByteArray> tokens = file.readLine().simplified().split(' ');
+ QList<QByteArray>::const_iterator it = tokens.begin();
+ if (it == tokens.end())
+ continue;
+ QByteArray type = *it;
+ if (++it == tokens.end())
+ continue;
+ QByteArray name = *it;
+ bool singleElement = (tokens.size() == 3); // type, name and one value
+ char counter[10] = "000000000";
+ int counterPos = 8; // position of last digit
+ while (++it != tokens.end()) {
+ m_parameterNames << name;
+ if (!singleElement) {
+ m_parameterNames.back() += "[";
+ m_parameterNames.back() += counter + counterPos;
+ m_parameterNames.back() += "]";
+ int j = 8; // position of last digit
+ ++counter[j];
+ while (j > 0 && counter[j] > '9') {
+ counter[j] = '0';
+ ++counter[--j];
+ }
+ if (j < counterPos)
+ counterPos = j;
+ }
+
+ if (type == "color") {
+ layout->addWidget(new QLabel(m_parameterNames.back()));
+ bool ok;
+ ColorEdit *colorEdit = new ColorEdit(it->toUInt(&ok, 16), m_parameterNames.size() - 1);
+ m_parameterEdits << colorEdit;
+ layout->addWidget(colorEdit);
+ connect(colorEdit, SIGNAL(colorChanged(QRgb, int)), this, SLOT(setColorParameter(QRgb, int)));
+ ++row;
+ } else if (type == "float") {
+ layout->addWidget(new QLabel(m_parameterNames.back()));
+ bool ok;
+ FloatEdit *floatEdit = new FloatEdit(it->toFloat(&ok), m_parameterNames.size() - 1);
+ m_parameterEdits << floatEdit;
+ layout->addWidget(floatEdit);
+ connect(floatEdit, SIGNAL(valueChanged(float, int)), this, SLOT(setFloatParameter(float, int)));
+ ++row;
+ }
+ }
+ }
+ file.close();
+ }
+ }
+
+ layout->addWidget(new QLabel(tr("Texture:")));
+ m_textureCombo = new QComboBox;
+ connect(m_textureCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(textureChanged(int)));
+ layout->addWidget(m_textureCombo);
+ ++row;
+
+ layout->addWidget(new QLabel(tr("Shader:")));
+ m_shaderCombo = new QComboBox;
+ connect(m_shaderCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(shaderChanged(int)));
+ layout->addWidget(m_shaderCombo);
+ ++row;
+
+ layout->setRowStretch(row, 1);
+}
+
+int RenderOptionsDialog::addTexture(const QString &name)
+{
+ m_textureCombo->addItem(name);
+ return m_textureCombo->count() - 1;
+}
+
+int RenderOptionsDialog::addShader(const QString &name)
+{
+ m_shaderCombo->addItem(name);
+ return m_shaderCombo->count() - 1;
+}
+
+void RenderOptionsDialog::emitParameterChanged()
+{
+ foreach (ParameterEdit *edit, m_parameterEdits)
+ edit->emitChange();
+}
+
+void RenderOptionsDialog::setColorParameter(QRgb color, int id)
+{
+ emit colorParameterChanged(m_parameterNames[id], color);
+}
+
+void RenderOptionsDialog::setFloatParameter(float value, int id)
+{
+ emit floatParameterChanged(m_parameterNames[id], value);
+}
+
+void RenderOptionsDialog::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ emit doubleClicked();
+}
+
+//============================================================================//
+// ItemDialog //
+//============================================================================//
+
+ItemDialog::ItemDialog()
+ : QDialog(0, Qt::CustomizeWindowHint | Qt::WindowTitleHint)
+{
+ setWindowTitle(tr("Items (double click to flip)"));
+ setWindowOpacity(0.75);
+ resize(160, 100);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ setLayout(layout);
+ QPushButton *button;
+
+ button = new QPushButton(tr("Add Qt box"));
+ layout->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(triggerNewQtBox()));
+
+ button = new QPushButton(tr("Add circle"));
+ layout->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(triggerNewCircleItem()));
+
+ button = new QPushButton(tr("Add square"));
+ layout->addWidget(button);
+ connect(button, SIGNAL(clicked()), this, SLOT(triggerNewSquareItem()));
+
+ layout->addStretch(1);
+}
+
+void ItemDialog::triggerNewQtBox()
+{
+ emit newItemTriggered(QtBoxItem);
+}
+
+void ItemDialog::triggerNewCircleItem()
+{
+ emit newItemTriggered(CircleItem);
+}
+
+void ItemDialog::triggerNewSquareItem()
+{
+ emit newItemTriggered(SquareItem);
+}
+
+void ItemDialog::mouseDoubleClickEvent(QMouseEvent *event)
+{
+ if (event->button() == Qt::LeftButton)
+ emit doubleClicked();
+}
+
+//============================================================================//
+// Scene //
+//============================================================================//
+
+const static char environmentShaderText[] =
+ "uniform samplerCube env;"
+ "void main() {"
+ "gl_FragColor = textureCube(env, gl_TexCoord[1].xyz);"
+ "}";
+
+Scene::Scene(int width, int height, int maxTextureSize)
+ : m_distExp(600)
+ , m_frame(0)
+ , m_maxTextureSize(maxTextureSize)
+ , m_currentShader(0)
+ , m_currentTexture(0)
+ , m_dynamicCubemap(false)
+ , m_updateAllCubemaps(true)
+ , m_box(0)
+ , m_vertexShader(0)
+ , m_environmentShader(0)
+ , m_environmentProgram(0)
+{
+ setSceneRect(0, 0, width, height);
+
+ m_trackBalls[0] = TrackBall(0.0005f, gfx::Vector3f::vector(0, 1, 0), TrackBall::Sphere);
+ m_trackBalls[1] = TrackBall(0.0001f, gfx::Vector3f::vector(0, 0, 1), TrackBall::Sphere);
+ m_trackBalls[2] = TrackBall(0.0f, gfx::Vector3f::vector(0, 1, 0), TrackBall::Plane);
+
+ m_renderOptions = new RenderOptionsDialog;
+ m_renderOptions->move(20, 120);
+ m_renderOptions->resize(m_renderOptions->sizeHint());
+
+ connect(m_renderOptions, SIGNAL(dynamicCubemapToggled(int)), this, SLOT(toggleDynamicCubemap(int)));
+ connect(m_renderOptions, SIGNAL(colorParameterChanged(const QString &, QRgb)), this, SLOT(setColorParameter(const QString &, QRgb)));
+ connect(m_renderOptions, SIGNAL(floatParameterChanged(const QString &, float)), this, SLOT(setFloatParameter(const QString &, float)));
+ connect(m_renderOptions, SIGNAL(textureChanged(int)), this, SLOT(setTexture(int)));
+ connect(m_renderOptions, SIGNAL(shaderChanged(int)), this, SLOT(setShader(int)));
+
+ m_itemDialog = new ItemDialog;
+ connect(m_itemDialog, SIGNAL(newItemTriggered(ItemDialog::ItemType)), this, SLOT(newItem(ItemDialog::ItemType)));
+
+ TwoSidedGraphicsWidget *twoSided = new TwoSidedGraphicsWidget(this);
+ twoSided->setWidget(0, m_renderOptions);
+ twoSided->setWidget(1, m_itemDialog);
+
+ connect(m_renderOptions, SIGNAL(doubleClicked()), twoSided, SLOT(flip()));
+ connect(m_itemDialog, SIGNAL(doubleClicked()), twoSided, SLOT(flip()));
+
+ addItem(new QtBox(64, width - 64, height - 64));
+ addItem(new QtBox(64, width - 64, 64));
+ addItem(new QtBox(64, 64, height - 64));
+ addItem(new QtBox(64, 64, 64));
+
+ initGL();
+
+ m_timer = new QTimer(this);
+ m_timer->setInterval(20);
+ connect(m_timer, SIGNAL(timeout()), this, SLOT(update()));
+ m_timer->start();
+
+ m_time.start();
+}
+
+Scene::~Scene()
+{
+ if (m_box)
+ delete m_box;
+ foreach (GLTexture *texture, m_textures)
+ if (texture) delete texture;
+ if (m_mainCubemap)
+ delete m_mainCubemap;
+ foreach (GLProgram *program, m_programs)
+ if (program) delete program;
+ if (m_vertexShader)
+ delete m_vertexShader;
+ foreach (GLFragmentShader *shader, m_fragmentShaders)
+ if (shader) delete shader;
+ foreach (GLRenderTargetCube *rt, m_cubemaps)
+ if (rt) delete rt;
+ if (m_environmentShader)
+ delete m_environmentShader;
+ if (m_environmentProgram)
+ delete m_environmentProgram;
+}
+
+void Scene::initGL()
+{
+ m_box = new GLRoundedBox(0.25f, 1.0f, 10);
+
+ m_vertexShader = new GLVertexShader(":/res/boxes/basic.vsh");
+
+ QStringList list;
+ list << ":/res/boxes/cubemap_posx.jpg" << ":/res/boxes/cubemap_negx.jpg" << ":/res/boxes/cubemap_posy.jpg"
+ << ":/res/boxes/cubemap_negy.jpg" << ":/res/boxes/cubemap_posz.jpg" << ":/res/boxes/cubemap_negz.jpg";
+ m_environment = new GLTextureCube(list, qMin(1024, m_maxTextureSize));
+ m_environmentShader = new GLFragmentShader(environmentShaderText, strlen(environmentShaderText));
+ m_environmentProgram = new GLProgram;
+ m_environmentProgram->attach(*m_vertexShader);
+ m_environmentProgram->attach(*m_environmentShader);
+
+ const int NOISE_SIZE = 128; // for a different size, B and BM in fbm.c must also be changed
+ m_noise = new GLTexture3D(NOISE_SIZE, NOISE_SIZE, NOISE_SIZE);
+ QRgb *data = new QRgb[NOISE_SIZE * NOISE_SIZE * NOISE_SIZE];
+ memset(data, 0, NOISE_SIZE * NOISE_SIZE * NOISE_SIZE * sizeof(QRgb));
+ QRgb *p = data;
+ float pos[3];
+ for (int k = 0; k < NOISE_SIZE; ++k) {
+ pos[2] = k * (0x20 / (float)NOISE_SIZE);
+ for (int j = 0; j < NOISE_SIZE; ++j) {
+ for (int i = 0; i < NOISE_SIZE; ++i) {
+ for (int byte = 0; byte < 4; ++byte) {
+ pos[0] = (i + (byte & 1) * 16) * (0x20 / (float)NOISE_SIZE);
+ pos[1] = (j + (byte & 2) * 8) * (0x20 / (float)NOISE_SIZE);
+ *p |= (int)(128.0f * (noise3(pos) + 1.0f)) << (byte * 8);
+ }
+ ++p;
+ }
+ }
+ }
+ m_noise->load(NOISE_SIZE, NOISE_SIZE, NOISE_SIZE, data);
+ delete[] data;
+
+ m_mainCubemap = new GLRenderTargetCube(512);
+
+ QStringList filter;
+ QList<QFileInfo> files;
+
+ // Load all .png files as textures
+ m_currentTexture = 0;
+ filter = QStringList("*.png");
+ files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
+
+ foreach (QFileInfo file, files) {
+ GLTexture *texture = new GLTexture2D(file.absoluteFilePath(), qMin(256, m_maxTextureSize), qMin(256, m_maxTextureSize));
+ if (texture->failed()) {
+ delete texture;
+ continue;
+ }
+ m_textures << texture;
+ m_renderOptions->addTexture(file.baseName());
+ }
+
+ if (m_textures.size() == 0)
+ m_textures << new GLTexture2D(qMin(64, m_maxTextureSize), qMin(64, m_maxTextureSize));
+
+ // Load all .fsh files as fragment shaders
+ m_currentShader = 0;
+ filter = QStringList("*.fsh");
+ files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
+ foreach (QFileInfo file, files) {
+ GLProgram *program = new GLProgram;
+ GLFragmentShader* shader = new GLFragmentShader(file.absoluteFilePath());
+ // The program does not take ownership over the shaders, so store them in a vector so they can be deleted afterwards.
+ program->attach(*m_vertexShader);
+ program->attach(*shader);
+ if (program->failed()) {
+ qWarning("Failed to compile and link shader program");
+ qWarning("Vertex shader log:");
+ qWarning() << m_vertexShader->log();
+ qWarning() << "Fragment shader log ( file =" << file.absoluteFilePath() << "):";
+ qWarning() << shader->log();
+ qWarning("Shader program log:");
+ qWarning() << program->log();
+
+ delete shader;
+ delete program;
+ continue;
+ }
+
+ m_fragmentShaders << shader;
+ m_programs << program;
+ m_renderOptions->addShader(file.baseName());
+
+ program->bind();
+ m_cubemaps << (program->hasParameter("env") ? new GLRenderTargetCube(qMin(256, m_maxTextureSize)) : 0);
+ program->unbind();
+ }
+
+ if (m_programs.size() == 0)
+ m_programs << new GLProgram;
+
+ m_renderOptions->emitParameterChanged();
+}
+
+// If one of the boxes should not be rendered, set excludeBox to its index.
+// If the main box should not be rendered, set excludeBox to -1.
+void Scene::renderBoxes(const gfx::Matrix4x4f &view, int excludeBox)
+{
+ gfx::Matrix4x4f invView = view.inverse();
+
+ // If multi-texturing is supported, use three saplers.
+ if (glActiveTexture) {
+ glActiveTexture(GL_TEXTURE0);
+ m_textures[m_currentTexture]->bind();
+ glActiveTexture(GL_TEXTURE2);
+ m_noise->bind();
+ glActiveTexture(GL_TEXTURE1);
+ } else {
+ m_textures[m_currentTexture]->bind();
+ }
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_CULL_FACE);
+
+ gfx::Matrix4x4f viewRotation(view);
+ viewRotation(3, 0) = viewRotation(3, 1) = viewRotation(3, 2) = 0.0f;
+ viewRotation(0, 3) = viewRotation(1, 3) = viewRotation(2, 3) = 0.0f;
+ viewRotation(3, 3) = 1.0f;
+ glLoadMatrixf(viewRotation.bits());
+ glScalef(20.0f, 20.0f, 20.0f);
+
+ // Don't render the environment if the environment texture can't be set for the correct sampler.
+ if (glActiveTexture) {
+ m_environment->bind();
+ m_environmentProgram->bind();
+ m_environmentProgram->setInt("tex", 0);
+ m_environmentProgram->setInt("env", 1);
+ m_environmentProgram->setInt("noise", 2);
+ m_box->draw();
+ m_environmentProgram->unbind();
+ m_environment->unbind();
+ }
+
+ glLoadMatrixf(view.bits());
+
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+
+ for (int i = 0; i < m_programs.size(); ++i) {
+ if (i == excludeBox)
+ continue;
+
+ glPushMatrix();
+ gfx::Matrix4x4f m;
+ m_trackBalls[1].rotation().matrix(m);
+ glMultMatrixf(m.bits());
+
+ glRotatef(360.0f * i / m_programs.size(), 0.0f, 0.0f, 1.0f);
+ glTranslatef(2.0f, 0.0f, 0.0f);
+ glScalef(0.3f, 0.6f, 0.6f);
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap && m_cubemaps[i])
+ m_cubemaps[i]->bind();
+ else
+ m_environment->bind();
+ }
+ m_programs[i]->bind();
+ m_programs[i]->setInt("tex", 0);
+ m_programs[i]->setInt("env", 1);
+ m_programs[i]->setInt("noise", 2);
+ m_programs[i]->setMatrix("view", view);
+ m_programs[i]->setMatrix("invView", invView);
+ m_box->draw();
+ m_programs[i]->unbind();
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap && m_cubemaps[i])
+ m_cubemaps[i]->unbind();
+ else
+ m_environment->unbind();
+ }
+ glPopMatrix();
+ }
+
+ if (-1 != excludeBox) {
+ gfx::Matrix4x4f m;
+ m_trackBalls[0].rotation().matrix(m);
+ glMultMatrixf(m.bits());
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap)
+ m_mainCubemap->bind();
+ else
+ m_environment->bind();
+ }
+
+ m_programs[m_currentShader]->bind();
+ m_programs[m_currentShader]->setInt("tex", 0);
+ m_programs[m_currentShader]->setInt("env", 1);
+ m_programs[m_currentShader]->setInt("noise", 2);
+ m_programs[m_currentShader]->setMatrix("view", view);
+ m_programs[m_currentShader]->setMatrix("invView", invView);
+ m_box->draw();
+ m_programs[m_currentShader]->unbind();
+
+ if (glActiveTexture) {
+ if (m_dynamicCubemap)
+ m_mainCubemap->unbind();
+ else
+ m_environment->unbind();
+ }
+ }
+
+ if (glActiveTexture) {
+ glActiveTexture(GL_TEXTURE2);
+ m_noise->unbind();
+ glActiveTexture(GL_TEXTURE0);
+ }
+ m_textures[m_currentTexture]->unbind();
+}
+
+void Scene::setStates()
+{
+ //glClearColor(0.25f, 0.25f, 0.5f, 1.0f);
+
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ //glEnable(GL_COLOR_MATERIAL);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_NORMALIZE);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ setLights();
+
+ float materialSpecular[] = {0.5f, 0.5f, 0.5f, 1.0f};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, materialSpecular);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 32.0f);
+}
+
+void Scene::setLights()
+{
+ glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
+ //float lightColour[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ float lightDir[] = {0.0f, 0.0f, 1.0f, 0.0f};
+ //glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColour);
+ //glLightfv(GL_LIGHT0, GL_SPECULAR, lightColour);
+ glLightfv(GL_LIGHT0, GL_POSITION, lightDir);
+ glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 1.0f);
+ glEnable(GL_LIGHT0);
+}
+
+void Scene::defaultStates()
+{
+ //glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_LIGHTING);
+ //glDisable(GL_COLOR_MATERIAL);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_LIGHT0);
+ glDisable(GL_NORMALIZE);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ glLightModelf(GL_LIGHT_MODEL_LOCAL_VIEWER, 0.0f);
+ float defaultMaterialSpecular[] = {0.0f, 0.0f, 0.0f, 1.0f};
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, defaultMaterialSpecular);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);
+}
+
+void Scene::renderCubemaps()
+{
+ // To speed things up, only update the cubemaps for the small cubes every N frames.
+ const int N = (m_updateAllCubemaps ? 1 : 3);
+
+ gfx::Matrix4x4f mat;
+ GLRenderTargetCube::getProjectionMatrix(mat, 0.1f, 100.0f);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(mat.bits());
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+
+ gfx::Vector3f center;
+
+ for (int i = m_frame % N; i < m_cubemaps.size(); i += N) {
+ if (0 == m_cubemaps[i])
+ continue;
+
+ float angle = 2.0f * PI * i / m_cubemaps.size();
+ center = m_trackBalls[1].rotation().transform(gfx::Vector3f::vector(cos(angle), sin(angle), 0));
+
+ for (int face = 0; face < 6; ++face) {
+ m_cubemaps[i]->begin(face);
+
+ GLRenderTargetCube::getViewMatrix(mat, face);
+ gfx::Vector4f v = gfx::Vector4f::vector(-center[0], -center[1], -center[2], 1.0);
+ mat[3] = v * mat;
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ renderBoxes(mat, i);
+
+ m_cubemaps[i]->end();
+ }
+ }
+
+ for (int face = 0; face < 6; ++face) {
+ m_mainCubemap->begin(face);
+ GLRenderTargetCube::getViewMatrix(mat, face);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ renderBoxes(mat, -1);
+
+ m_mainCubemap->end();
+ }
+
+ glPopMatrix();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ m_updateAllCubemaps = false;
+}
+
+void Scene::drawBackground(QPainter *painter, const QRectF &)
+{
+ float width = float(painter->device()->width());
+ float height = float(painter->device()->height());
+
+ setStates();
+
+ if (m_dynamicCubemap)
+ renderCubemaps();
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glMatrixMode(GL_PROJECTION);
+ gluPerspective(60.0, width / height, 0.01, 15.0);
+
+ glMatrixMode(GL_MODELVIEW);
+
+ //gfx::Matrix4x4f view = gfx::Matrix4x4f::identity();
+ //view(3, 2) -= 2.0f * exp(m_distExp / 1200.0f);
+
+ gfx::Matrix4x4f view;
+ m_trackBalls[2].rotation().matrix(view);
+ view(3, 2) -= 2.0f * exp(m_distExp / 1200.0f);
+ renderBoxes(view);
+
+ defaultStates();
+ ++m_frame;
+}
+
+QPointF Scene::pixelPosToViewPos(const QPointF& p)
+{
+ return QPointF(2.0 * float(p.x()) / width() - 1.0,
+ 1.0 - 2.0 * float(p.y()) / height());
+}
+
+void Scene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsScene::mouseMoveEvent(event);
+ if (event->isAccepted())
+ return;
+
+ if (event->buttons() & Qt::LeftButton) {
+ m_trackBalls[0].move(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ } else {
+ m_trackBalls[0].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ }
+
+ if (event->buttons() & Qt::RightButton) {
+ m_trackBalls[1].move(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ } else {
+ m_trackBalls[1].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ }
+
+ if (event->buttons() & Qt::MidButton) {
+ m_trackBalls[2].move(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ event->accept();
+ } else {
+ m_trackBalls[2].release(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ }
+}
+
+void Scene::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsScene::mousePressEvent(event);
+ if (event->isAccepted())
+ return;
+
+ if (event->buttons() & Qt::LeftButton) {
+ m_trackBalls[0].push(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->buttons() & Qt::RightButton) {
+ m_trackBalls[1].push(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->buttons() & Qt::MidButton) {
+ m_trackBalls[2].push(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ event->accept();
+ }
+}
+
+void Scene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ QGraphicsScene::mouseReleaseEvent(event);
+ if (event->isAccepted())
+ return;
+
+ if (event->button() == Qt::LeftButton) {
+ m_trackBalls[0].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->button() == Qt::RightButton) {
+ m_trackBalls[1].release(pixelPosToViewPos(event->scenePos()), m_trackBalls[2].rotation().conjugate());
+ event->accept();
+ }
+
+ if (event->button() == Qt::MidButton) {
+ m_trackBalls[2].release(pixelPosToViewPos(event->scenePos()), gfx::Quaternionf::identity());
+ event->accept();
+ }
+}
+
+void Scene::wheelEvent(QGraphicsSceneWheelEvent * event)
+{
+ QGraphicsScene::wheelEvent(event);
+ if (!event->isAccepted()) {
+ m_distExp += event->delta();
+ if (m_distExp < -8 * 120)
+ m_distExp = -8 * 120;
+ if (m_distExp > 10 * 120)
+ m_distExp = 10 * 120;
+ event->accept();
+ }
+}
+
+void Scene::setShader(int index)
+{
+ if (index >= 0 && index < m_fragmentShaders.size())
+ m_currentShader = index;
+}
+
+void Scene::setTexture(int index)
+{
+ if (index >= 0 && index < m_textures.size())
+ m_currentTexture = index;
+}
+
+void Scene::toggleDynamicCubemap(int state)
+{
+ if ((m_dynamicCubemap = (state == Qt::Checked)))
+ m_updateAllCubemaps = true;
+}
+
+void Scene::setColorParameter(const QString &name, QRgb color)
+{
+ // set the color in all programs
+ foreach (GLProgram *program, m_programs) {
+ program->bind();
+ program->setColor(name, color);
+ program->unbind();
+ }
+}
+
+void Scene::setFloatParameter(const QString &name, float value)
+{
+ // set the color in all programs
+ foreach (GLProgram *program, m_programs) {
+ program->bind();
+ program->setFloat(name, value);
+ program->unbind();
+ }
+}
+
+void Scene::newItem(ItemDialog::ItemType type)
+{
+ QSize size = sceneRect().size().toSize();
+ switch (type) {
+ case ItemDialog::QtBoxItem:
+ addItem(new QtBox(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ break;
+ case ItemDialog::CircleItem:
+ addItem(new CircleItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ break;
+ case ItemDialog::SquareItem:
+ addItem(new SquareItem(64, rand() % (size.width() - 64) + 32, rand() % (size.height() - 64) + 32));
+ break;
+ default:
+ break;
+ }
+}
diff --git a/demos/boxes/scene.h b/demos/boxes/scene.h
new file mode 100644
index 0000000..2db9317
--- /dev/null
+++ b/demos/boxes/scene.h
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef SCENE_H
+#define SCENE_H
+
+//#include <GL/glew.h>
+#include "glextensions.h"
+
+#include <QtGui>
+#include <QtOpenGL>
+
+#include "roundedbox.h"
+#include "gltrianglemesh.h"
+#include "vector.h"
+#include "trackball.h"
+#include "glbuffers.h"
+#include "glshaders.h"
+#include "qtbox.h"
+
+#define PI 3.14159265358979
+
+class ParameterEdit : public QWidget
+{
+public:
+ virtual void emitChange() = 0;
+};
+
+class ColorEdit : public ParameterEdit
+{
+ Q_OBJECT
+public:
+ ColorEdit(QRgb initialColor, int id);
+ QRgb color() const {return m_color;}
+ virtual void emitChange() {emit colorChanged(m_color, m_id);}
+public slots:
+ void editDone();
+signals:
+ void colorChanged(QRgb color, int id);
+protected:
+ virtual void mousePressEvent(QMouseEvent *event);
+ void setColor(QRgb color); // also emits colorChanged()
+private:
+ QGraphicsScene *m_dialogParentScene;
+ QLineEdit *m_lineEdit;
+ QFrame *m_button;
+ QRgb m_color;
+ int m_id;
+};
+
+class FloatEdit : public ParameterEdit
+{
+ Q_OBJECT
+public:
+ FloatEdit(float initialValue, int id);
+ float value() const {return m_value;}
+ virtual void emitChange() {emit valueChanged(m_value, m_id);}
+public slots:
+ void editDone();
+signals:
+ void valueChanged(float value, int id);
+private:
+ QGraphicsScene *m_dialogParentScene;
+ QLineEdit *m_lineEdit;
+ float m_value;
+ int m_id;
+};
+
+class GraphicsWidget : public QGraphicsProxyWidget
+{
+protected:
+ virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value);
+ virtual void resizeEvent(QGraphicsSceneResizeEvent *event);
+ virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
+};
+
+class TwoSidedGraphicsWidget : public QObject
+{
+ Q_OBJECT
+public:
+ TwoSidedGraphicsWidget(QGraphicsScene *scene);
+ void setWidget(int index, QWidget *widget);
+ QWidget *widget(int index);
+public slots:
+ void flip();
+protected slots:
+ void animateFlip();
+private:
+ GraphicsWidget *m_proxyWidgets[2];
+ int m_current;
+ int m_angle; // angle in degrees
+ int m_delta;
+};
+
+class RenderOptionsDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ RenderOptionsDialog();
+ int addTexture(const QString &name);
+ int addShader(const QString &name);
+ void emitParameterChanged();
+protected slots:
+ void setColorParameter(QRgb color, int id);
+ void setFloatParameter(float value, int id);
+signals:
+ void dynamicCubemapToggled(int);
+ void colorParameterChanged(const QString &, QRgb);
+ void floatParameterChanged(const QString &, float);
+ void textureChanged(int);
+ void shaderChanged(int);
+ void doubleClicked();
+protected:
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+
+ QVector<QByteArray> m_parameterNames;
+ QComboBox *m_textureCombo;
+ QComboBox *m_shaderCombo;
+ QVector<ParameterEdit *> m_parameterEdits;
+};
+
+class ItemDialog : public QDialog
+{
+ Q_OBJECT
+public:
+ enum ItemType {
+ QtBoxItem,
+ CircleItem,
+ SquareItem,
+ };
+
+ ItemDialog();
+public slots:
+ void triggerNewQtBox();
+ void triggerNewCircleItem();
+ void triggerNewSquareItem();
+signals:
+ void doubleClicked();
+ void newItemTriggered(ItemDialog::ItemType type);
+protected:
+ virtual void mouseDoubleClickEvent(QMouseEvent *event);
+};
+
+class Scene : public QGraphicsScene
+{
+ Q_OBJECT
+public:
+ Scene(int width, int height, int maxTextureSize);
+ ~Scene();
+ virtual void drawBackground(QPainter *painter, const QRectF &rect);
+
+public slots:
+ void setShader(int index);
+ void setTexture(int index);
+ void toggleDynamicCubemap(int state);
+ void setColorParameter(const QString &name, QRgb color);
+ void setFloatParameter(const QString &name, float value);
+ void newItem(ItemDialog::ItemType type);
+protected:
+ void renderBoxes(const gfx::Matrix4x4f &view, int excludeBox = -2);
+ void setStates();
+ void setLights();
+ void defaultStates();
+ void renderCubemaps();
+
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
+ virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
+ virtual void wheelEvent(QGraphicsSceneWheelEvent * event);
+private:
+ void initGL();
+ QPointF pixelPosToViewPos(const QPointF& p);
+
+ QTime m_time;
+ int m_lastTime;
+ int m_mouseEventTime;
+ int m_distExp;
+ int m_frame;
+ int m_maxTextureSize;
+
+ int m_currentShader;
+ int m_currentTexture;
+ bool m_dynamicCubemap;
+ bool m_updateAllCubemaps;
+
+ RenderOptionsDialog *m_renderOptions;
+ ItemDialog *m_itemDialog;
+ QTimer *m_timer;
+ GLRoundedBox *m_box;
+ TrackBall m_trackBalls[3];
+ QVector<GLTexture *> m_textures;
+ GLTextureCube *m_environment;
+ GLTexture3D *m_noise;
+ GLRenderTargetCube *m_mainCubemap;
+ QVector<GLRenderTargetCube *> m_cubemaps;
+ QVector<GLProgram *> m_programs;
+ GLVertexShader *m_vertexShader;
+ QVector<GLFragmentShader *> m_fragmentShaders;
+ GLFragmentShader *m_environmentShader;
+ GLProgram *m_environmentProgram;
+};
+
+
+
+#endif
diff --git a/demos/boxes/smiley.png b/demos/boxes/smiley.png
new file mode 100644
index 0000000..41cfda6
--- /dev/null
+++ b/demos/boxes/smiley.png
Binary files differ
diff --git a/demos/boxes/square.jpg b/demos/boxes/square.jpg
new file mode 100644
index 0000000..03f53bd
--- /dev/null
+++ b/demos/boxes/square.jpg
Binary files differ
diff --git a/demos/boxes/trackball.cpp b/demos/boxes/trackball.cpp
new file mode 100644
index 0000000..980f6ed
--- /dev/null
+++ b/demos/boxes/trackball.cpp
@@ -0,0 +1,158 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "trackball.h"
+
+//============================================================================//
+// TrackBall //
+//============================================================================//
+
+TrackBall::TrackBall(TrackMode mode)
+ : m_angularVelocity(0)
+ , m_paused(false)
+ , m_pressed(false)
+ , m_mode(mode)
+{
+ m_axis = gfx::Vector3f::vector(0, 1, 0);
+ m_rotation = gfx::Quaternionf::quaternion(1.0f, 0.0f, 0.0f, 0.0f);
+ m_lastTime = QTime::currentTime();
+}
+
+TrackBall::TrackBall(float angularVelocity, const gfx::Vector3f& axis, TrackMode mode)
+ : m_axis(axis)
+ , m_angularVelocity(angularVelocity)
+ , m_paused(false)
+ , m_pressed(false)
+ , m_mode(mode)
+{
+ m_rotation = gfx::Quaternionf::quaternion(1.0f, 0.0f, 0.0f, 0.0f);
+ m_lastTime = QTime::currentTime();
+}
+
+void TrackBall::push(const QPointF& p, const gfx::Quaternionf &)
+{
+ m_rotation = rotation();
+ m_pressed = true;
+ m_lastTime = QTime::currentTime();
+ m_lastPos = p;
+ m_angularVelocity = 0.0f;
+}
+
+void TrackBall::move(const QPointF& p, const gfx::Quaternionf &transformation)
+{
+ if (!m_pressed)
+ return;
+
+ QTime currentTime = QTime::currentTime();
+ int msecs = m_lastTime.msecsTo(currentTime);
+ if (msecs <= 20)
+ return;
+
+ switch (m_mode) {
+ case Plane:
+ {
+ QLineF delta(m_lastPos, p);
+ m_angularVelocity = delta.length() / msecs;
+ m_axis = gfx::Vector3f::vector(delta.dy(), -delta.dx(), 0.0f).normalized();
+ m_axis = transformation.transform(m_axis);
+ m_rotation *= gfx::Quaternionf::rotation(delta.length(), m_axis);
+ }
+ break;
+ case Sphere:
+ {
+ gfx::Vector3f lastPos3D = gfx::Vector3f::vector(m_lastPos.x(), m_lastPos.y(), 0);
+ float sqrZ = 1 - lastPos3D.sqrNorm();
+ if (sqrZ > 0)
+ lastPos3D[2] = sqrt(sqrZ);
+ else
+ lastPos3D.normalize();
+
+ gfx::Vector3f currentPos3D = gfx::Vector3f::vector(p.x(), p.y(), 0);
+ sqrZ = 1 - currentPos3D.sqrNorm();
+ if (sqrZ > 0)
+ currentPos3D[2] = sqrt(sqrZ);
+ else
+ currentPos3D.normalize();
+
+ m_axis = gfx::Vector3f::cross(currentPos3D, lastPos3D);
+ float angle = asin(sqrt(m_axis.sqrNorm()));
+
+ m_angularVelocity = angle / msecs;
+ m_axis.normalize();
+ m_axis = transformation.transform(m_axis);
+ m_rotation *= gfx::Quaternionf::rotation(angle, m_axis);
+ }
+ break;
+ }
+
+ m_lastPos = p;
+ m_lastTime = currentTime;
+}
+
+void TrackBall::release(const QPointF& p, const gfx::Quaternionf &transformation)
+{
+ // Calling move() caused the rotation to stop if the framerate was too low.
+ move(p, transformation);
+ m_pressed = false;
+}
+
+void TrackBall::start()
+{
+ m_lastTime = QTime::currentTime();
+ m_paused = false;
+}
+
+void TrackBall::stop()
+{
+ m_rotation = rotation();
+ m_paused = true;
+}
+
+gfx::Quaternionf TrackBall::rotation() const
+{
+ if (m_paused || m_pressed)
+ return m_rotation;
+
+ QTime currentTime = QTime::currentTime();
+ float angle = m_angularVelocity * m_lastTime.msecsTo(currentTime);
+ return m_rotation * gfx::Quaternionf::rotation(angle, m_axis);
+}
+
diff --git a/demos/boxes/trackball.h b/demos/boxes/trackball.h
new file mode 100644
index 0000000..5e3f40c
--- /dev/null
+++ b/demos/boxes/trackball.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TRACKBALL_H
+#define TRACKBALL_H
+
+#include <QtGui>
+
+#include "vector.h"
+
+class TrackBall
+{
+public:
+ enum TrackMode
+ {
+ Plane,
+ Sphere,
+ };
+ TrackBall(TrackMode mode = Sphere);
+ TrackBall(float angularVelocity, const gfx::Vector3f& axis, TrackMode mode = Sphere);
+ // coordinates in [-1,1]x[-1,1]
+ void push(const QPointF& p, const gfx::Quaternionf &transformation);
+ void move(const QPointF& p, const gfx::Quaternionf &transformation);
+ void release(const QPointF& p, const gfx::Quaternionf &transformation);
+ void start(); // starts clock
+ void stop(); // stops clock
+ gfx::Quaternionf rotation() const;
+private:
+ gfx::Quaternionf m_rotation;
+ gfx::Vector3f m_axis;
+ float m_angularVelocity;
+
+ QPointF m_lastPos;
+ QTime m_lastTime;
+ bool m_paused;
+ bool m_pressed;
+ TrackMode m_mode;
+};
+
+#endif
diff --git a/demos/boxes/vector.h b/demos/boxes/vector.h
new file mode 100644
index 0000000..bb24531
--- /dev/null
+++ b/demos/boxes/vector.h
@@ -0,0 +1,602 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef VECTOR_H
+#define VECTOR_H
+
+#include <cassert>
+#include <cmath>
+#include <iostream>
+
+namespace gfx
+{
+
+template<class T, int n>
+struct Vector
+{
+ // Keep the Vector struct a plain old data (POD) struct by avoiding constructors
+
+ static Vector vector(T x)
+ {
+ Vector result;
+ for (int i = 0; i < n; ++i)
+ result.v[i] = x;
+ return result;
+ }
+
+ // Use only for 2D vectors
+ static Vector vector(T x, T y)
+ {
+ assert(n == 2);
+ Vector result;
+ result.v[0] = x;
+ result.v[1] = y;
+ return result;
+ }
+
+ // Use only for 3D vectors
+ static Vector vector(T x, T y, T z)
+ {
+ assert(n == 3);
+ Vector result;
+ result.v[0] = x;
+ result.v[1] = y;
+ result.v[2] = z;
+ return result;
+ }
+
+ // Use only for 4D vectors
+ static Vector vector(T x, T y, T z, T w)
+ {
+ assert(n == 4);
+ Vector result;
+ result.v[0] = x;
+ result.v[1] = y;
+ result.v[2] = z;
+ result.v[3] = w;
+ return result;
+ }
+
+ // Pass 'n' arguments to this function.
+ static Vector vector(T *v)
+ {
+ Vector result;
+ for (int i = 0; i < n; ++i)
+ result.v[i] = v[i];
+ return result;
+ }
+
+ T &operator [] (int i) {return v[i];}
+ T operator [] (int i) const {return v[i];}
+
+#define VECTOR_BINARY_OP(op, arg, rhs) \
+ Vector operator op (arg) const \
+ { \
+ Vector result; \
+ for (int i = 0; i < n; ++i) \
+ result.v[i] = v[i] op rhs; \
+ return result; \
+ }
+
+ VECTOR_BINARY_OP(+, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(-, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(*, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(/, const Vector &u, u.v[i])
+ VECTOR_BINARY_OP(+, T s, s)
+ VECTOR_BINARY_OP(-, T s, s)
+ VECTOR_BINARY_OP(*, T s, s)
+ VECTOR_BINARY_OP(/, T s, s)
+#undef VECTOR_BINARY_OP
+
+ Vector operator - () const
+ {
+ Vector result;
+ for (int i = 0; i < n; ++i)
+ result.v[i] = -v[i];
+ return result;
+ }
+
+#define VECTOR_ASSIGN_OP(op, arg, rhs) \
+ Vector &operator op (arg) \
+ { \
+ for (int i = 0; i < n; ++i) \
+ v[i] op rhs; \
+ return *this; \
+ }
+
+ VECTOR_ASSIGN_OP(+=, const Vector &u, u.v[i])
+ VECTOR_ASSIGN_OP(-=, const Vector &u, u.v[i])
+ VECTOR_ASSIGN_OP(=, T s, s)
+ VECTOR_ASSIGN_OP(*=, T s, s)
+ VECTOR_ASSIGN_OP(/=, T s, s)
+#undef VECTOR_ASSIGN_OP
+
+ static T dot(const Vector &u, const Vector &v)
+ {
+ T sum(0);
+ for (int i = 0; i < n; ++i)
+ sum += u.v[i] * v.v[i];
+ return sum;
+ }
+
+ static Vector cross(const Vector &u, const Vector &v)
+ {
+ assert(n == 3);
+ return vector(u.v[1] * v.v[2] - u.v[2] * v.v[1],
+ u.v[2] * v.v[0] - u.v[0] * v.v[2],
+ u.v[0] * v.v[1] - u.v[1] * v.v[0]);
+ }
+
+ T sqrNorm() const
+ {
+ return dot(*this, *this);
+ }
+
+ // requires floating point type T
+ void normalize()
+ {
+ T s = sqrNorm();
+ if (s != 0)
+ *this /= sqrt(s);
+ }
+
+ // requires floating point type T
+ Vector normalized() const
+ {
+ T s = sqrNorm();
+ if (s == 0)
+ return *this;
+ return *this / sqrt(s);
+ }
+
+ T *bits() {return v;}
+ const T *bits() const {return v;}
+
+ T v[n];
+};
+
+#define SCALAR_VECTOR_BINARY_OP(op) \
+template<class T, int n> \
+Vector<T, n> operator op (T s, const Vector<T, n>& u) \
+{ \
+ Vector<T, n> result; \
+ for (int i = 0; i < n; ++i) \
+ result[i] = s op u[i]; \
+ return result; \
+}
+
+SCALAR_VECTOR_BINARY_OP(+)
+SCALAR_VECTOR_BINARY_OP(-)
+SCALAR_VECTOR_BINARY_OP(*)
+SCALAR_VECTOR_BINARY_OP(/)
+#undef SCALAR_VECTOR_BINARY_OP
+
+template<class T, int n>
+std::ostream &operator << (std::ostream &os, const Vector<T, n> &v)
+{
+ assert(n > 0);
+ os << "[" << v[0];
+ for (int i = 1; i < n; ++i)
+ os << ", " << v[i];
+ os << "]";
+ return os;
+}
+
+typedef Vector<float, 2> Vector2f;
+typedef Vector<float, 3> Vector3f;
+typedef Vector<float, 4> Vector4f;
+
+template<class T, int rows, int cols>
+struct Matrix
+{
+ // Keep the Matrix struct a plain old data (POD) struct by avoiding constructors
+
+ static Matrix matrix(T x)
+ {
+ Matrix result;
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j)
+ result.v[i][j] = x;
+ }
+ return result;
+ }
+
+ static Matrix matrix(T *m)
+ {
+ Matrix result;
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j) {
+ result.v[i][j] = *m;
+ ++m;
+ }
+ }
+ return result;
+ }
+
+ T &operator () (int i, int j) {return v[i][j];}
+ T operator () (int i, int j) const {return v[i][j];}
+ Vector<T, cols> &operator [] (int i) {return v[i];}
+ const Vector<T, cols> &operator [] (int i) const {return v[i];}
+
+ // TODO: operators, methods
+
+ Vector<T, rows> operator * (const Vector<T, cols> &u) const
+ {
+ Vector<T, rows> result;
+ for (int i = 0; i < rows; ++i)
+ result[i] = Vector<T, cols>::dot(v[i], u);
+ return result;
+ }
+
+ template<int k>
+ Matrix<T, rows, k> operator * (const Matrix<T, cols, k> &m)
+ {
+ Matrix<T, rows, k> result;
+ for (int i = 0; i < rows; ++i)
+ result[i] = v[i] * m;
+ return result;
+ }
+
+ T* bits() {return reinterpret_cast<T *>(this);}
+ const T* bits() const {return reinterpret_cast<const T *>(this);}
+
+ // Simple Gauss elimination.
+ // TODO: Optimize and improve stability.
+ Matrix inverse(bool *ok = 0) const
+ {
+ assert(rows == cols);
+ Matrix rhs = identity();
+ Matrix lhs(*this);
+ T temp;
+ // Down
+ for (int i = 0; i < rows; ++i) {
+ // Pivoting
+ int pivot = i;
+ for (int j = i; j < rows; ++j) {
+ if (qAbs(lhs(j, i)) > lhs(pivot, i))
+ pivot = j;
+ }
+ // TODO: fuzzy compare.
+ if (lhs(pivot, i) == T(0)) {
+ if (ok)
+ *ok = false;
+ return rhs;
+ }
+ if (pivot != i) {
+ for (int j = i; j < cols; ++j) {
+ temp = lhs(pivot, j);
+ lhs(pivot, j) = lhs(i, j);
+ lhs(i, j) = temp;
+ }
+ for (int j = 0; j < cols; ++j) {
+ temp = rhs(pivot, j);
+ rhs(pivot, j) = rhs(i, j);
+ rhs(i, j) = temp;
+ }
+ }
+
+ // Normalize i-th row
+ rhs[i] /= lhs(i, i);
+ for (int j = cols - 1; j > i; --j)
+ lhs(i, j) /= lhs(i, i);
+
+ // Eliminate non-zeros in i-th column below the i-th row.
+ for (int j = i + 1; j < rows; ++j) {
+ rhs[j] -= lhs(j, i) * rhs[i];
+ for (int k = i + 1; k < cols; ++k)
+ lhs(j, k) -= lhs(j, i) * lhs(i, k);
+ }
+ }
+ // Up
+ for (int i = rows - 1; i > 0; --i) {
+ for (int j = i - 1; j >= 0; --j)
+ rhs[j] -= lhs(j, i) * rhs[i];
+ }
+ if (ok)
+ *ok = true;
+ return rhs;
+ }
+
+ Matrix<T, cols, rows> transpose() const
+ {
+ Matrix<T, cols, rows> result;
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j)
+ result.v[j][i] = v[i][j];
+ }
+ return result;
+ }
+
+ static Matrix identity()
+ {
+ Matrix result = matrix(T(0));
+ for (int i = 0; i < rows && i < cols; ++i)
+ result.v[i][i] = T(1);
+ return result;
+ }
+
+ Vector<T, cols> v[rows];
+};
+
+template<class T, int rows, int cols>
+Vector<T, cols> operator * (const Vector<T, rows> &u, const Matrix<T, rows, cols> &m)
+{
+ Vector<T, cols> result = Vector<T, cols>::vector(T(0));
+ for (int i = 0; i < rows; ++i)
+ result += m[i] * u[i];
+ return result;
+}
+
+template<class T, int rows, int cols>
+std::ostream &operator << (std::ostream &os, const Matrix<T, rows, cols> &m)
+{
+ assert(rows > 0);
+ os << "[" << m[0];
+ for (int i = 1; i < rows; ++i)
+ os << ", " << m[i];
+ os << "]";
+ return os;
+}
+
+
+typedef Matrix<float, 2, 2> Matrix2x2f;
+typedef Matrix<float, 3, 3> Matrix3x3f;
+typedef Matrix<float, 4, 4> Matrix4x4f;
+
+template<class T>
+struct Quaternion
+{
+ // Keep the Quaternion struct a plain old data (POD) struct by avoiding constructors
+
+ static Quaternion quaternion(T s, T x, T y, T z)
+ {
+ Quaternion result;
+ result.scalar = s;
+ result.vector[0] = x;
+ result.vector[1] = y;
+ result.vector[2] = z;
+ return result;
+ }
+
+ static Quaternion quaternion(T s, const Vector<T, 3> &v)
+ {
+ Quaternion result;
+ result.scalar = s;
+ result.vector = v;
+ return result;
+ }
+
+ static Quaternion identity()
+ {
+ return quaternion(T(1), T(0), T(0), T(0));
+ }
+
+ // assumes that all the elements are packed tightly
+ T& operator [] (int i) {return reinterpret_cast<T *>(this)[i];}
+ T operator [] (int i) const {return reinterpret_cast<const T *>(this)[i];}
+
+#define QUATERNION_BINARY_OP(op, arg, rhs) \
+ Quaternion operator op (arg) const \
+ { \
+ Quaternion result; \
+ for (int i = 0; i < 4; ++i) \
+ result[i] = (*this)[i] op rhs; \
+ return result; \
+ }
+
+ QUATERNION_BINARY_OP(+, const Quaternion &q, q[i])
+ QUATERNION_BINARY_OP(-, const Quaternion &q, q[i])
+ QUATERNION_BINARY_OP(*, T s, s)
+ QUATERNION_BINARY_OP(/, T s, s)
+#undef QUATERNION_BINARY_OP
+
+ Quaternion operator - () const
+ {
+ return Quaternion(-scalar, -vector);
+ }
+
+ Quaternion operator * (const Quaternion &q) const
+ {
+ Quaternion result;
+ result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector);
+ result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector);
+ return result;
+ }
+
+ Quaternion operator * (const Vector<T, 3> &v) const
+ {
+ Quaternion result;
+ result.scalar = -Vector<T, 3>::dot(vector, v);
+ result.vector = scalar * v + Vector<T, 3>::cross(vector, v);
+ return result;
+ }
+
+ friend Quaternion operator * (const Vector<T, 3> &v, const Quaternion &q)
+ {
+ Quaternion result;
+ result.scalar = -Vector<T, 3>::dot(v, q.vector);
+ result.vector = v * q.scalar + Vector<T, 3>::cross(v, q.vector);
+ return result;
+ }
+
+#define QUATERNION_ASSIGN_OP(op, arg, rhs) \
+ Quaternion &operator op (arg) \
+ { \
+ for (int i = 0; i < 4; ++i) \
+ (*this)[i] op rhs; \
+ return *this; \
+ }
+
+ QUATERNION_ASSIGN_OP(+=, const Quaternion &q, q[i])
+ QUATERNION_ASSIGN_OP(-=, const Quaternion &q, q[i])
+ QUATERNION_ASSIGN_OP(=, T s, s)
+ QUATERNION_ASSIGN_OP(*=, T s, s)
+ QUATERNION_ASSIGN_OP(/=, T s, s)
+#undef QUATERNION_ASSIGN_OP
+
+ Quaternion& operator *= (const Quaternion &q)
+ {
+ Quaternion result;
+ result.scalar = scalar * q.scalar - Vector<T, 3>::dot(vector, q.vector);
+ result.vector = scalar * q.vector + vector * q.scalar + Vector<T, 3>::cross(vector, q.vector);
+ return (*this = result);
+ }
+
+ Quaternion& operator *= (const Vector<T, 3> &v)
+ {
+ Quaternion result;
+ result.scalar = -Vector<T, 3>::dot(vector, v);
+ result.vector = scalar * v + Vector<T, 3>::cross(vector, v);
+ return (*this = result);
+ }
+
+ Quaternion conjugate() const
+ {
+ return quaternion(scalar, -vector);
+ }
+
+ T sqrNorm() const
+ {
+ return scalar * scalar + vector.sqrNorm();
+ }
+
+ Quaternion inverse() const
+ {
+ return conjugate() / sqrNorm();
+ }
+
+ // requires floating point type T
+ Quaternion normalized() const
+ {
+ T s = sqrNorm();
+ if (s == 0)
+ return *this;
+ return *this / sqrt(s);
+ }
+
+ void matrix(Matrix<T, 3, 3>& m) const
+ {
+ T bb = vector[0] * vector[0];
+ T cc = vector[1] * vector[1];
+ T dd = vector[2] * vector[2];
+ T diag = scalar * scalar - bb - cc - dd;
+ T ab = scalar * vector[0];
+ T ac = scalar * vector[1];
+ T ad = scalar * vector[2];
+ T bc = vector[0] * vector[1];
+ T cd = vector[1] * vector[2];
+ T bd = vector[2] * vector[0];
+ m(0, 0) = diag + 2 * bb;
+ m(0, 1) = 2 * (bc - ad);
+ m(0, 2) = 2 * (ac + bd);
+ m(1, 0) = 2 * (ad + bc);
+ m(1, 1) = diag + 2 * cc;
+ m(1, 2) = 2 * (cd - ab);
+ m(2, 0) = 2 * (bd - ac);
+ m(2, 1) = 2 * (ab + cd);
+ m(2, 2) = diag + 2 * dd;
+ }
+
+ void matrix(Matrix<T, 4, 4>& m) const
+ {
+ T bb = vector[0] * vector[0];
+ T cc = vector[1] * vector[1];
+ T dd = vector[2] * vector[2];
+ T diag = scalar * scalar - bb - cc - dd;
+ T ab = scalar * vector[0];
+ T ac = scalar * vector[1];
+ T ad = scalar * vector[2];
+ T bc = vector[0] * vector[1];
+ T cd = vector[1] * vector[2];
+ T bd = vector[2] * vector[0];
+ m(0, 0) = diag + 2 * bb;
+ m(0, 1) = 2 * (bc - ad);
+ m(0, 2) = 2 * (ac + bd);
+ m(0, 3) = 0;
+ m(1, 0) = 2 * (ad + bc);
+ m(1, 1) = diag + 2 * cc;
+ m(1, 2) = 2 * (cd - ab);
+ m(1, 3) = 0;
+ m(2, 0) = 2 * (bd - ac);
+ m(2, 1) = 2 * (ab + cd);
+ m(2, 2) = diag + 2 * dd;
+ m(2, 3) = 0;
+ m(3, 0) = 0;
+ m(3, 1) = 0;
+ m(3, 2) = 0;
+ m(3, 3) = 1;
+ }
+
+ // assumes that 'this' is normalized
+ Vector<T, 3> transform(const Vector<T, 3> &v) const
+ {
+ Matrix<T, 3, 3> m;
+ matrix(m);
+ return v * m;
+ }
+
+ // assumes that all the elements are packed tightly
+ T* bits() {return reinterpret_cast<T *>(this);}
+ const T* bits() const {return reinterpret_cast<const T *>(this);}
+
+ // requires floating point type T
+ static Quaternion rotation(T angle, const Vector<T, 3> &unitAxis)
+ {
+ T s = sin(angle / 2);
+ T c = cos(angle / 2);
+ return quaternion(c, unitAxis * s);
+ }
+
+ T scalar;
+ Vector<T, 3> vector;
+};
+
+template<class T>
+Quaternion<T> operator * (T s, const Quaternion<T>& q)
+{
+ return Quaternion<T>::quaternion(s * q.scalar, s * q.vector);
+}
+
+typedef Quaternion<float> Quaternionf;
+
+} // end namespace gfx
+
+#endif
diff --git a/demos/boxes/wood.fsh b/demos/boxes/wood.fsh
new file mode 100644
index 0000000..35bf7d6
--- /dev/null
+++ b/demos/boxes/wood.fsh
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 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 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+varying vec3 position, normal;
+varying vec4 specular, ambient, diffuse, lightDirection;
+
+uniform sampler2D tex;
+uniform sampler3D noise;
+
+//const vec4 woodColors[2] = {vec4(0.37,0.24,0.20,1), vec4(0.8,0.6,0.4,1)};
+uniform vec4 woodColors[2];
+//const float woodTubulence = 0.1;
+uniform float woodTubulence;
+
+void main()
+{
+ float r = length(gl_TexCoord[1].yz);
+ r += woodTubulence * texture3D(noise, 0.25 * gl_TexCoord[1].xyz).x;
+
+ vec3 N = normalize(normal);
+ // assume directional light
+
+ gl_MaterialParameters M = gl_FrontMaterial;
+
+ float NdotL = dot(N, lightDirection.xyz);
+ float RdotL = dot(reflect(normalize(position), N), lightDirection.xyz);
+
+ float f = fract(16.0 * r);
+ vec4 unlitColor = mix(woodColors[0], woodColors[1], min(1.25 * f, 5.0 - 5.0 * f));
+ gl_FragColor = (ambient + diffuse * max(NdotL, 0.0)) * unlitColor +
+ M.specular * specular * pow(max(RdotL, 0.0), M.shininess);
+}