summaryrefslogtreecommitdiffstats
path: root/examples/opengl
diff options
context:
space:
mode:
authorSarah Smith <sarah.j.smith@nokia.com>2009-09-21 01:23:06 (GMT)
committerSarah Smith <sarah.j.smith@nokia.com>2009-09-21 01:23:06 (GMT)
commit11fed1f64f43593a2890e0a3f27b4e2e7ebde783 (patch)
tree99f57336eafe2403af7526154d8d4743f416333e /examples/opengl
parent1b8d92b1ae453bd2d395658c7086d0049916e88f (diff)
downloadQt-11fed1f64f43593a2890e0a3f27b4e2e7ebde783.zip
Qt-11fed1f64f43593a2890e0a3f27b4e2e7ebde783.tar.gz
Qt-11fed1f64f43593a2890e0a3f27b4e2e7ebde783.tar.bz2
remove display lists and qt3d-ize overpainting/hellogl example
On the way to making opengl examples portable, remove display lists and go to triangles only. Use QMatrix4x4. While on the job use Qt/3D stylee to make the QtLogo as an example of 3D programming more Qt-like. Reviewed-by: Rhys Weatherley
Diffstat (limited to 'examples/opengl')
-rw-r--r--examples/opengl/hellogl/glwidget.cpp124
-rw-r--r--examples/opengl/hellogl/glwidget.h10
-rw-r--r--examples/opengl/hellogl/hellogl.pro9
-rw-r--r--examples/opengl/overpainting/glwidget.cpp125
-rw-r--r--examples/opengl/overpainting/glwidget.h14
-rw-r--r--examples/opengl/overpainting/overpainting.pro28
-rw-r--r--examples/opengl/shared/qtlogo.cpp403
-rw-r--r--examples/opengl/shared/qtlogo.h67
8 files changed, 549 insertions, 231 deletions
diff --git a/examples/opengl/hellogl/glwidget.cpp b/examples/opengl/hellogl/glwidget.cpp
index 64e14ea..b0c3ba4 100644
--- a/examples/opengl/hellogl/glwidget.cpp
+++ b/examples/opengl/hellogl/glwidget.cpp
@@ -45,12 +45,13 @@
#include <math.h>
#include "glwidget.h"
+#include "qtlogo.h"
//! [0]
GLWidget::GLWidget(QWidget *parent)
: QGLWidget(parent)
{
- object = 0;
+ logo = 0;
xRot = 0;
yRot = 0;
zRot = 0;
@@ -63,8 +64,6 @@ GLWidget::GLWidget(QWidget *parent)
//! [1]
GLWidget::~GLWidget()
{
- makeCurrent();
- glDeleteLists(object, 1);
}
//! [1]
@@ -83,10 +82,18 @@ QSize GLWidget::sizeHint() const
}
//! [4]
+static void qNormalizeAngle(int &angle)
+{
+ while (angle < 0)
+ angle += 360 * 16;
+ while (angle > 360 * 16)
+ angle -= 360 * 16;
+}
+
//! [5]
void GLWidget::setXRotation(int angle)
{
- normalizeAngle(&angle);
+ qNormalizeAngle(angle);
if (angle != xRot) {
xRot = angle;
emit xRotationChanged(angle);
@@ -97,7 +104,7 @@ void GLWidget::setXRotation(int angle)
void GLWidget::setYRotation(int angle)
{
- normalizeAngle(&angle);
+ qNormalizeAngle(angle);
if (angle != yRot) {
yRot = angle;
emit yRotationChanged(angle);
@@ -107,7 +114,7 @@ void GLWidget::setYRotation(int angle)
void GLWidget::setZRotation(int angle)
{
- normalizeAngle(&angle);
+ qNormalizeAngle(angle);
if (angle != zRot) {
zRot = angle;
emit zRotationChanged(angle);
@@ -119,10 +126,18 @@ void GLWidget::setZRotation(int angle)
void GLWidget::initializeGL()
{
qglClearColor(qtPurple.dark());
- object = makeObject();
- glShadeModel(GL_FLAT);
+
+ logo = new QtLogo(this, 64);
+ logo->setColor(qtGreen.dark());
+
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
+ glShadeModel(GL_SMOOTH);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_MULTISAMPLE);
+ static GLfloat lightPosition[4] = { 0.5, 5.0, 7.0, 1.0 };
+ glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
}
//! [6]
@@ -135,7 +150,7 @@ void GLWidget::paintGL()
glRotated(xRot / 16.0, 1.0, 0.0, 0.0);
glRotated(yRot / 16.0, 0.0, 1.0, 0.0);
glRotated(zRot / 16.0, 0.0, 0.0, 1.0);
- glCallList(object);
+ logo->draw();
}
//! [7]
@@ -147,7 +162,7 @@ void GLWidget::resizeGL(int width, int height)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0);
+ glOrtho(-0.5, +0.5, -0.5, +0.5, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
}
//! [8]
@@ -175,92 +190,3 @@ void GLWidget::mouseMoveEvent(QMouseEvent *event)
lastPos = event->pos();
}
//! [10]
-
-GLuint GLWidget::makeObject()
-{
- GLuint list = glGenLists(1);
- glNewList(list, GL_COMPILE);
-
- glBegin(GL_QUADS);
-
- GLdouble x1 = +0.06;
- GLdouble y1 = -0.14;
- GLdouble x2 = +0.14;
- GLdouble y2 = -0.06;
- GLdouble x3 = +0.08;
- GLdouble y3 = +0.00;
- GLdouble x4 = +0.30;
- GLdouble y4 = +0.22;
-
- quad(x1, y1, x2, y2, y2, x2, y1, x1);
- quad(x3, y3, x4, y4, y4, x4, y3, x3);
-
- extrude(x1, y1, x2, y2);
- extrude(x2, y2, y2, x2);
- extrude(y2, x2, y1, x1);
- extrude(y1, x1, x1, y1);
- extrude(x3, y3, x4, y4);
- extrude(x4, y4, y4, x4);
- extrude(y4, x4, y3, x3);
-
- const double Pi = 3.14159265358979323846;
- const int NumSectors = 200;
-
- for (int i = 0; i < NumSectors; ++i) {
- double angle1 = (i * 2 * Pi) / NumSectors;
- GLdouble x5 = 0.30 * sin(angle1);
- GLdouble y5 = 0.30 * cos(angle1);
- GLdouble x6 = 0.20 * sin(angle1);
- GLdouble y6 = 0.20 * cos(angle1);
-
- double angle2 = ((i + 1) * 2 * Pi) / NumSectors;
- GLdouble x7 = 0.20 * sin(angle2);
- GLdouble y7 = 0.20 * cos(angle2);
- GLdouble x8 = 0.30 * sin(angle2);
- GLdouble y8 = 0.30 * cos(angle2);
-
- quad(x5, y5, x6, y6, x7, y7, x8, y8);
-
- extrude(x6, y6, x7, y7);
- extrude(x8, y8, x5, y5);
- }
-
- glEnd();
-
- glEndList();
- return list;
-}
-
-void GLWidget::quad(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2,
- GLdouble x3, GLdouble y3, GLdouble x4, GLdouble y4)
-{
- qglColor(qtGreen);
-
- glVertex3d(x1, y1, -0.05);
- glVertex3d(x2, y2, -0.05);
- glVertex3d(x3, y3, -0.05);
- glVertex3d(x4, y4, -0.05);
-
- glVertex3d(x4, y4, +0.05);
- glVertex3d(x3, y3, +0.05);
- glVertex3d(x2, y2, +0.05);
- glVertex3d(x1, y1, +0.05);
-}
-
-void GLWidget::extrude(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
-{
- qglColor(qtGreen.dark(250 + int(100 * x1)));
-
- glVertex3d(x1, y1, +0.05);
- glVertex3d(x2, y2, +0.05);
- glVertex3d(x2, y2, -0.05);
- glVertex3d(x1, y1, -0.05);
-}
-
-void GLWidget::normalizeAngle(int *angle)
-{
- while (*angle < 0)
- *angle += 360 * 16;
- while (*angle > 360 * 16)
- *angle -= 360 * 16;
-}
diff --git a/examples/opengl/hellogl/glwidget.h b/examples/opengl/hellogl/glwidget.h
index b202a61..4ffd4d7 100644
--- a/examples/opengl/hellogl/glwidget.h
+++ b/examples/opengl/hellogl/glwidget.h
@@ -44,6 +44,8 @@
#include <QGLWidget>
+class QtLogo;
+
//! [0]
class GLWidget : public QGLWidget
{
@@ -80,13 +82,7 @@ protected:
//! [3]
private:
- GLuint makeObject();
- void quad(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2,
- GLdouble x3, GLdouble y3, GLdouble x4, GLdouble y4);
- void extrude(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
- void normalizeAngle(int *angle);
-
- GLuint object;
+ QtLogo *logo;
int xRot;
int yRot;
int zRot;
diff --git a/examples/opengl/hellogl/hellogl.pro b/examples/opengl/hellogl/hellogl.pro
index 6d57c19..0e3209a 100644
--- a/examples/opengl/hellogl/hellogl.pro
+++ b/examples/opengl/hellogl/hellogl.pro
@@ -1,8 +1,13 @@
+VPATH += ../shared
+INCLUDEPATH += ../shared
+
HEADERS = glwidget.h \
- window.h
+ window.h \
+ qtlogo.h
SOURCES = glwidget.cpp \
main.cpp \
- window.cpp
+ window.cpp \
+ qtlogo.cpp
QT += opengl
# install
diff --git a/examples/opengl/overpainting/glwidget.cpp b/examples/opengl/overpainting/glwidget.cpp
index 30d3266..0dcccbf 100644
--- a/examples/opengl/overpainting/glwidget.cpp
+++ b/examples/opengl/overpainting/glwidget.cpp
@@ -46,6 +46,7 @@
#include <math.h>
#include "bubble.h"
+#include "qtlogo.h"
#include "glwidget.h"
#ifndef GL_MULTISAMPLE
@@ -59,7 +60,7 @@ GLWidget::GLWidget(QWidget *parent)
QTime midnight(0, 0, 0);
qsrand(midnight.secsTo(QTime::currentTime()));
- object = 0;
+ logo = 0;
xRot = 0;
yRot = 0;
zRot = 0;
@@ -80,28 +81,34 @@ GLWidget::GLWidget(QWidget *parent)
//! [1]
GLWidget::~GLWidget()
{
- makeCurrent();
- glDeleteLists(object, 1);
}
//! [1]
+static void qNormalizeAngle(int &angle)
+{
+ while (angle < 0)
+ angle += 360 * 16;
+ while (angle > 360 * 16)
+ angle -= 360 * 16;
+}
+
void GLWidget::setXRotation(int angle)
{
- normalizeAngle(&angle);
+ qNormalizeAngle(angle);
if (angle != xRot)
xRot = angle;
}
void GLWidget::setYRotation(int angle)
{
- normalizeAngle(&angle);
+ qNormalizeAngle(angle);
if (angle != yRot)
yRot = angle;
}
void GLWidget::setZRotation(int angle)
{
- normalizeAngle(&angle);
+ qNormalizeAngle(angle);
if (angle != zRot)
zRot = angle;
}
@@ -109,7 +116,10 @@ void GLWidget::setZRotation(int angle)
//! [2]
void GLWidget::initializeGL()
{
- object = makeObject();
+ glEnable(GL_MULTISAMPLE);
+
+ logo = new QtLogo(this);
+ logo->setColor(qtGreen.dark());
}
//! [2]
@@ -162,7 +172,8 @@ void GLWidget::paintEvent(QPaintEvent *event)
glRotated(xRot / 16.0, 1.0, 0.0, 0.0);
glRotated(yRot / 16.0, 0.0, 1.0, 0.0);
glRotated(zRot / 16.0, 0.0, 0.0, 1.0);
- glCallList(object);
+
+ logo->draw();
//! [7]
//! [8]
@@ -207,102 +218,6 @@ QSize GLWidget::sizeHint() const
return QSize(400, 400);
}
-GLuint GLWidget::makeObject()
-{
- GLuint list = glGenLists(1);
- glNewList(list, GL_COMPILE);
-
- glEnable(GL_NORMALIZE);
- glBegin(GL_QUADS);
-
- static GLfloat logoDiffuseColor[4] = {qtGreen.red()/255.0,
- qtGreen.green()/255.0,
- qtGreen.blue()/255.0, 1.0};
- glMaterialfv(GL_FRONT, GL_DIFFUSE, logoDiffuseColor);
-
- GLdouble x1 = +0.06;
- GLdouble y1 = -0.14;
- GLdouble x2 = +0.14;
- GLdouble y2 = -0.06;
- GLdouble x3 = +0.08;
- GLdouble y3 = +0.00;
- GLdouble x4 = +0.30;
- GLdouble y4 = +0.22;
-
- quad(x1, y1, x2, y2, y2, x2, y1, x1);
- quad(x3, y3, x4, y4, y4, x4, y3, x3);
-
- extrude(x1, y1, x2, y2);
- extrude(x2, y2, y2, x2);
- extrude(y2, x2, y1, x1);
- extrude(y1, x1, x1, y1);
- extrude(x3, y3, x4, y4);
- extrude(x4, y4, y4, x4);
- extrude(y4, x4, y3, x3);
-
- const double Pi = 3.14159265358979323846;
- const int NumSectors = 200;
-
- for (int i = 0; i < NumSectors; ++i) {
- double angle1 = (i * 2 * Pi) / NumSectors;
- GLdouble x5 = 0.30 * sin(angle1);
- GLdouble y5 = 0.30 * cos(angle1);
- GLdouble x6 = 0.20 * sin(angle1);
- GLdouble y6 = 0.20 * cos(angle1);
-
- double angle2 = ((i + 1) * 2 * Pi) / NumSectors;
- GLdouble x7 = 0.20 * sin(angle2);
- GLdouble y7 = 0.20 * cos(angle2);
- GLdouble x8 = 0.30 * sin(angle2);
- GLdouble y8 = 0.30 * cos(angle2);
-
- quad(x5, y5, x6, y6, x7, y7, x8, y8);
-
- extrude(x6, y6, x7, y7);
- extrude(x8, y8, x5, y5);
- }
-
- glEnd();
-
- glEndList();
- return list;
-}
-
-void GLWidget::quad(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2,
- GLdouble x3, GLdouble y3, GLdouble x4, GLdouble y4)
-{
- glNormal3d(0.0, 0.0, -1.0);
- glVertex3d(x1, y1, -0.05);
- glVertex3d(x2, y2, -0.05);
- glVertex3d(x3, y3, -0.05);
- glVertex3d(x4, y4, -0.05);
-
- glNormal3d(0.0, 0.0, 1.0);
- glVertex3d(x4, y4, +0.05);
- glVertex3d(x3, y3, +0.05);
- glVertex3d(x2, y2, +0.05);
- glVertex3d(x1, y1, +0.05);
-}
-
-void GLWidget::extrude(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2)
-{
- qglColor(qtGreen.dark(250 + int(100 * x1)));
-
- glNormal3d((x1 + x2)/2.0, (y1 + y2)/2.0, 0.0);
- glVertex3d(x1, y1, +0.05);
- glVertex3d(x2, y2, +0.05);
- glVertex3d(x2, y2, -0.05);
- glVertex3d(x1, y1, -0.05);
-}
-
-void GLWidget::normalizeAngle(int *angle)
-{
- while (*angle < 0)
- *angle += 360 * 16;
- while (*angle > 360 * 16)
- *angle -= 360 * 16;
-}
-
void GLWidget::createBubbles(int number)
{
for (int i = 0; i < number; ++i) {
@@ -337,7 +252,7 @@ void GLWidget::setupViewport(int width, int height)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
- glOrtho(-0.5, +0.5, +0.5, -0.5, 4.0, 15.0);
+ glOrtho(-0.5, +0.5, -0.5, 0.5, 4.0, 15.0);
glMatrixMode(GL_MODELVIEW);
}
//! [14]
diff --git a/examples/opengl/overpainting/glwidget.h b/examples/opengl/overpainting/glwidget.h
index 5323a6f..6c9f7e0 100644
--- a/examples/opengl/overpainting/glwidget.h
+++ b/examples/opengl/overpainting/glwidget.h
@@ -50,6 +50,7 @@
#include <QTimer>
class Bubble;
+class QtLogo;
QT_BEGIN_NAMESPACE
class QPaintEvent;
class QWidget;
@@ -88,27 +89,24 @@ private slots:
void animate();
private:
- GLuint makeObject();
void createBubbles(int number);
void drawInstructions(QPainter *painter);
//! [1]
- void extrude(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2);
- void normalizeAngle(int *angle);
- void quad(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2,
- GLdouble x3, GLdouble y3, GLdouble x4, GLdouble y4);
void setupViewport(int width, int height);
+ QColor qtGreen;
+ QColor qtPurple;
+
GLuint object;
int xRot;
int yRot;
int zRot;
QPoint lastPos;
- QColor qtGreen;
- QColor qtPurple;
//! [4]
+ QtLogo *logo;
QList<Bubble*> bubbles;
QTimer animationTimer;
-};
//! [4]
+};
#endif
diff --git a/examples/opengl/overpainting/overpainting.pro b/examples/opengl/overpainting/overpainting.pro
index 10b6bd3..f9ba245 100644
--- a/examples/opengl/overpainting/overpainting.pro
+++ b/examples/opengl/overpainting/overpainting.pro
@@ -1,15 +1,23 @@
-QT += opengl
+VPATH += ../shared
+INCLUDEPATH += ../shared
-HEADERS = bubble.h \
- glwidget.h
-SOURCES = bubble.cpp \
- glwidget.cpp \
- main.cpp
+QT += opengl
+HEADERS = bubble.h \
+ glwidget.h \
+ qtlogo.h
+SOURCES = bubble.cpp \
+ glwidget.cpp \
+ main.cpp \
+ qtlogo.cpp
# install
target.path = $$[QT_INSTALL_EXAMPLES]/opengl/overpainting
-sources.files = $$SOURCES $$HEADERS $$RESOURCES $$FORMS overpainting.pro
+sources.files = $$SOURCES \
+ $$HEADERS \
+ $$RESOURCES \
+ $$FORMS \
+ overpainting.pro
sources.path = $$[QT_INSTALL_EXAMPLES]/opengl/overpainting
-INSTALLS += target sources
-
-symbian: include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
+INSTALLS += target \
+ sources
+symbian:include($$QT_SOURCE_TREE/examples/symbianpkgrules.pri)
diff --git a/examples/opengl/shared/qtlogo.cpp b/examples/opengl/shared/qtlogo.cpp
new file mode 100644
index 0000000..3294da1
--- /dev/null
+++ b/examples/opengl/shared/qtlogo.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtlogo.h"
+
+static const qreal tee_height = 0.311126;
+static const qreal cross_width = 0.25;
+static const qreal bar_thickness = 0.113137;
+static const qreal inside_diam = 0.20;
+static const qreal outside_diam = 0.30;
+static const qreal logo_depth = 0.10;
+static const int num_divisions = 32;
+
+//! [0]
+struct Geometry
+{
+ QVector<GLushort> faces;
+ QVector<QVector3D> vertices;
+ QVector<QVector3D> normals;
+ void appendSmooth(const QVector3D &a, const QVector3D &n, int from);
+ void appendFaceted(const QVector3D &a, const QVector3D &n);
+ void finalize();
+ void loadArrays() const;
+};
+//! [0]
+
+//! [1]
+class Patch
+{
+public:
+ enum Smoothing { Faceted, Smooth };
+ Patch(Geometry *);
+ void setSmoothing(Smoothing s) { sm = s; }
+ void translate(const QVector3D &t);
+ void rotate(qreal deg, QVector3D axis);
+ void draw() const;
+ void addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n);
+ void addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d);
+
+ GLushort start;
+ GLushort count;
+ GLushort initv;
+
+ GLfloat faceColor[4];
+ QMatrix4x4 mat;
+ Smoothing sm;
+ Geometry *geom;
+};
+//! [1]
+
+static inline void qSetColor(float colorVec[], QColor c)
+{
+ colorVec[0] = c.redF();
+ colorVec[1] = c.greenF();
+ colorVec[2] = c.blueF();
+ colorVec[3] = c.alphaF();
+}
+
+void Geometry::loadArrays() const
+{
+ glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
+ glNormalPointer(GL_FLOAT, 0, normals.constData());
+}
+
+void Geometry::finalize()
+{
+ // TODO: add vertex buffer uploading here
+
+ // Finish smoothing normals by ensuring accumulated normals are returned
+ // to length 1.0.
+ for (int i = 0; i < normals.count(); ++i)
+ normals[i].normalize();
+}
+
+void Geometry::appendSmooth(const QVector3D &a, const QVector3D &n, int from)
+{
+ // Smooth normals are acheived by averaging the normals for faces meeting
+ // at a point. First find the point in geometry already generated
+ // (working backwards, since most often the points shared are between faces
+ // recently added).
+ int v = vertices.count() - 1;
+ for ( ; v >= from; --v)
+ if (qFuzzyCompare(vertices[v], a))
+ break;
+ if (v < from)
+ {
+ // The vert was not found so add it as a new one, and initialize
+ // its corresponding normal
+ v = vertices.count();
+ vertices.append(a);
+ normals.append(n);
+ }
+ else
+ {
+ // Vert found, accumulate normals into corresponding normal slot.
+ // Must call finalize once finished accumulating normals
+ normals[v] += n;
+ }
+ // In both cases (found or not) reference the vert via its index
+ faces.append(v);
+}
+
+void Geometry::appendFaceted(const QVector3D &a, const QVector3D &n)
+{
+ // Faceted normals are achieved by duplicating the vert for every
+ // normal, so that faces meeting at a vert get a sharp edge.
+ int v = vertices.count();
+ vertices.append(a);
+ normals.append(n);
+ faces.append(v);
+}
+
+Patch::Patch(Geometry *g)
+ : start(g->faces.count())
+ , count(0)
+ , initv(g->vertices.count())
+ , sm(Patch::Smooth)
+ , geom(g)
+{
+ qSetColor(faceColor, QColor(Qt::darkGray));
+}
+
+void Patch::rotate(qreal deg, QVector3D axis)
+{
+ mat.rotate(deg, axis);
+}
+
+void Patch::translate(const QVector3D &t)
+{
+ mat.translate(t);
+}
+
+static inline void qMultMatrix(const QMatrix4x4 &mat)
+{
+ if (sizeof(qreal) == sizeof(GLfloat))
+ glMultMatrixf((GLfloat*)mat.constData());
+ else if (sizeof(qreal) == sizeof(GLdouble))
+ glMultMatrixd((GLdouble*)mat.constData());
+ else
+ {
+ GLfloat fmat[16];
+ qreal const *r = mat.constData();
+ for (int i = 0; i < 16; ++i)
+ fmat[i] = r[i];
+ }
+}
+
+//! [2]
+void Patch::draw() const
+{
+ glPushMatrix();
+ qMultMatrix(mat);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, faceColor);
+
+ const GLushort *indices = geom->faces.constData();
+ glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indices + start);
+ glPopMatrix();
+}
+//! [2]
+
+void Patch::addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n)
+{
+ QVector3D norm = n.isNull() ? QVector3D::normal(a, b, c) : n;
+ if (sm == Smooth)
+ {
+ geom->appendSmooth(a, norm, initv);
+ geom->appendSmooth(b, norm, initv);
+ geom->appendSmooth(c, norm, initv);
+ }
+ else
+ {
+ geom->appendFaceted(a, norm);
+ geom->appendFaceted(b, norm);
+ geom->appendFaceted(c, norm);
+ }
+ count += 3;
+}
+
+void Patch::addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d)
+{
+ QVector3D norm = QVector3D::normal(a, b, c);
+ if (sm == Smooth)
+ {
+ addTri(a, b, c, norm);
+ addTri(a, c, d, norm);
+ }
+ else
+ {
+ // If faceted share the two common verts
+ addTri(a, b, c, norm);
+ int k = geom->vertices.count();
+ geom->appendSmooth(a, norm, k);
+ geom->appendSmooth(c, norm, k);
+ geom->appendFaceted(d, norm);
+ count += 3;
+ }
+}
+
+static inline QVector<QVector3D> extrude(const QVector<QVector3D> &verts, qreal depth)
+{
+ QVector<QVector3D> extr = verts;
+ for (int v = 0; v < extr.count(); ++v)
+ extr[v].setZ(extr[v].z() - depth);
+ return extr;
+}
+
+class Rectoid
+{
+public:
+ void translate(const QVector3D &t)
+ {
+ for (int i = 0; i < parts.count(); ++i)
+ parts[i]->translate(t);
+ }
+ void rotate(qreal deg, QVector3D axis)
+ {
+ for (int i = 0; i < parts.count(); ++i)
+ parts[i]->rotate(deg, axis);
+ }
+
+ // No special Rectoid destructor - the parts are fetched out of this member
+ // variable, and destroyed by the new owner
+ QList<Patch*> parts;
+};
+
+class RectPrism : public Rectoid
+{
+public:
+ RectPrism(Geometry *g, qreal width, qreal height, qreal depth);
+};
+
+RectPrism::RectPrism(Geometry *g, qreal width, qreal height, qreal depth)
+{
+ enum { bl, br, tr, tl };
+ Patch *fb = new Patch(g);
+ fb->setSmoothing(Patch::Faceted);
+
+ // front face
+ QVector<QVector3D> r(4);
+ r[br].setX(width);
+ r[tr].setX(width);
+ r[tr].setY(height);
+ r[tl].setY(height);
+ QVector3D adjToCenter(-width / 2.0, -height / 2.0, depth / 2.0);
+ for (int i = 0; i < 4; ++i)
+ r[i] += adjToCenter;
+ fb->addQuad(r[bl], r[br], r[tr], r[tl]);
+
+ // back face
+ QVector<QVector3D> s = extrude(r, depth);
+ fb->addQuad(s[tl], s[tr], s[br], s[bl]);
+
+ // side faces
+ Patch *sides = new Patch(g);
+ sides->setSmoothing(Patch::Faceted);
+ sides->addQuad(s[bl], s[br], r[br], r[bl]);
+ sides->addQuad(s[br], s[tr], r[tr], r[br]);
+ sides->addQuad(s[tr], s[tl], r[tl], r[tr]);
+ sides->addQuad(s[tl], s[bl], r[bl], r[tl]);
+
+ parts << fb << sides;
+}
+
+class RectTorus : public Rectoid
+{
+public:
+ RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int numSectors);
+};
+
+RectTorus::RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int k)
+{
+ QVector<QVector3D> inside;
+ QVector<QVector3D> outside;
+ for (int i = 0; i < k; ++i) {
+ qreal angle = (i * 2 * M_PI) / k;
+ inside << QVector3D(iRad * qSin(angle), iRad * qCos(angle), depth / 2.0);
+ outside << QVector3D(oRad * qSin(angle), oRad * qCos(angle), depth / 2.0);
+ }
+ inside << QVector3D(0.0, iRad, 0.0);
+ outside << QVector3D(0.0, oRad, 0.0);
+ QVector<QVector3D> in_back = extrude(inside, depth);
+ QVector<QVector3D> out_back = extrude(outside, depth);
+
+ // Create front, back and sides as seperate patches so that smooth normals
+ // are generated for the curving sides, but a faceted edge is created between
+ // sides and front/back
+ Patch *front = new Patch(g);
+ for (int i = 0; i < k; ++i)
+ front->addQuad(outside[i], inside[i],
+ inside[(i + 1) % k], outside[(i + 1) % k]);
+ Patch *back = new Patch(g);
+ for (int i = 0; i < k; ++i)
+ back->addQuad(in_back[i], out_back[i],
+ out_back[(i + 1) % k], in_back[(i + 1) % k]);
+ Patch *is = new Patch(g);
+ for (int i = 0; i < k; ++i)
+ is->addQuad(in_back[i], in_back[(i + 1) % k],
+ inside[(i + 1) % k], inside[i]);
+ Patch *os = new Patch(g);
+ for (int i = 0; i < k; ++i)
+ os->addQuad(out_back[(i + 1) % k], out_back[i],
+ outside[i], outside[(i + 1) % k]);
+ parts << front << back << is << os;
+}
+
+QtLogo::QtLogo(QObject *parent, int divisions, qreal scale)
+ : QObject(parent)
+ , geom(new Geometry())
+{
+ buildGeometry(divisions, scale);
+}
+
+QtLogo::~QtLogo()
+{
+ qDeleteAll(parts);
+ delete geom;
+}
+
+void QtLogo::setColor(QColor c)
+{
+ for (int i = 0; i < parts.count(); ++i)
+ qSetColor(parts[i]->faceColor, c);
+}
+
+//! [3]
+void QtLogo::buildGeometry(int divisions, qreal scale)
+{
+ qreal cw = cross_width * scale;
+ qreal bt = bar_thickness * scale;
+ qreal ld = logo_depth * scale;
+ qreal th = tee_height *scale;
+
+ RectPrism cross(geom, cw, bt, ld);
+ RectPrism stem(geom, bt, th, ld);
+
+ QVector3D z(0.0, 0.0, 1.0);
+ cross.rotate(45.0, z);
+ stem.rotate(45.0, z);
+
+ qreal stem_downshift = (th + bt) / 2.0;
+ stem.translate(QVector3D(0.0, -stem_downshift, 0.0));
+
+ RectTorus body(geom, 0.20, 0.30, 0.1, divisions);
+
+ parts << stem.parts << cross.parts << body.parts;
+
+ geom->finalize();
+}
+//! [3]
+
+//! [4]
+void QtLogo::draw() const
+{
+ geom->loadArrays();
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glEnableClientState(GL_NORMAL_ARRAY);
+
+ for (int i = 0; i < parts.count(); ++i)
+ parts[i]->draw();
+
+ glDisableClientState(GL_VERTEX_ARRAY);
+ glDisableClientState(GL_NORMAL_ARRAY);
+}
+//! [4]
diff --git a/examples/opengl/shared/qtlogo.h b/examples/opengl/shared/qtlogo.h
new file mode 100644
index 0000000..26508e1
--- /dev/null
+++ b/examples/opengl/shared/qtlogo.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the examples 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 Technology Preview License Agreement accompanying
+** this package.
+**
+** 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.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTLOGO_H
+#define QTLOGO_H
+
+#include <QObject>
+#include <QtOpenGL>
+
+class Patch;
+class Geometry;
+
+//! [0]
+class QtLogo : public QObject
+{
+public:
+ QtLogo(QObject *parent, int d = 64, qreal s = 1.0);
+ ~QtLogo();
+ void setColor(QColor c);
+ void draw() const;
+private:
+ void buildGeometry(int d, qreal s);
+
+ QList<Patch *> parts;
+ Geometry *geom;
+};
+//! [0]
+
+#endif // QTLOGO_H