diff options
author | Lars Knoll <lars.knoll@nokia.com> | 2009-03-23 09:34:13 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-03-23 09:34:13 (GMT) |
commit | 67ad0519fd165acee4a4d2a94fa502e9e4847bd0 (patch) | |
tree | 1dbf50b3dff8d5ca7e9344733968c72704eb15ff /demos/boxes | |
download | Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.zip Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.gz Qt-67ad0519fd165acee4a4d2a94fa502e9e4847bd0.tar.bz2 |
Long live Qt!
Diffstat (limited to 'demos/boxes')
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 Binary files differnew file mode 100644 index 0000000..07c282e --- /dev/null +++ b/demos/boxes/cubemap_negx.jpg diff --git a/demos/boxes/cubemap_negy.jpg b/demos/boxes/cubemap_negy.jpg Binary files differnew file mode 100644 index 0000000..46cd2f9 --- /dev/null +++ b/demos/boxes/cubemap_negy.jpg diff --git a/demos/boxes/cubemap_negz.jpg b/demos/boxes/cubemap_negz.jpg Binary files differnew file mode 100644 index 0000000..40c01dd --- /dev/null +++ b/demos/boxes/cubemap_negz.jpg diff --git a/demos/boxes/cubemap_posx.jpg b/demos/boxes/cubemap_posx.jpg Binary files differnew file mode 100644 index 0000000..0b42e8a --- /dev/null +++ b/demos/boxes/cubemap_posx.jpg diff --git a/demos/boxes/cubemap_posy.jpg b/demos/boxes/cubemap_posy.jpg Binary files differnew file mode 100644 index 0000000..2aca9b1 --- /dev/null +++ b/demos/boxes/cubemap_posy.jpg diff --git a/demos/boxes/cubemap_posz.jpg b/demos/boxes/cubemap_posz.jpg Binary files differnew file mode 100644 index 0000000..2e49173 --- /dev/null +++ b/demos/boxes/cubemap_posz.jpg 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 Binary files differnew file mode 100644 index 0000000..4014b46 --- /dev/null +++ b/demos/boxes/qt-logo.jpg diff --git a/demos/boxes/qt-logo.png b/demos/boxes/qt-logo.png Binary files differnew file mode 100644 index 0000000..7d3e97e --- /dev/null +++ b/demos/boxes/qt-logo.png 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 Binary files differnew file mode 100644 index 0000000..41cfda6 --- /dev/null +++ b/demos/boxes/smiley.png diff --git a/demos/boxes/square.jpg b/demos/boxes/square.jpg Binary files differnew file mode 100644 index 0000000..03f53bd --- /dev/null +++ b/demos/boxes/square.jpg 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); +} |