summaryrefslogtreecommitdiffstats
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
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
-rw-r--r--doc/src/examples/hellogl.qdoc77
-rw-r--r--doc/src/examples/overpainting.qdoc19
-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
10 files changed, 624 insertions, 252 deletions
diff --git a/doc/src/examples/hellogl.qdoc b/doc/src/examples/hellogl.qdoc
index 6dc9e26..77deefe 100644
--- a/doc/src/examples/hellogl.qdoc
+++ b/doc/src/examples/hellogl.qdoc
@@ -65,7 +65,8 @@
\snippet examples/opengl/hellogl/glwidget.h 0
We use a destructor to ensure that any OpenGL-specific data structures
- are deleted when the widget is no longer needed.
+ are deleted when the widget is no longer needed (although in this case nothing
+ needs cleaning up).
\snippet examples/opengl/hellogl/glwidget.h 1
@@ -84,8 +85,8 @@
The rest of the class contains utility functions and variables that are
used to construct and hold orientation information for the scene. The
- \c object variable will be used to hold an identifier for an OpenGL
- display list.
+ \c logo variable will be used to hold a pointer to the QtLogo object which
+ contains all the geometry.
\section1 GLWidget Class Implementation
@@ -95,8 +96,9 @@
\section2 Widget Construction and Sizing
- The constructor provides default rotation angles for the scene, initializes
- the variable used for the display list, and sets up some colors for later use.
+ The constructor provides default rotation angles for the scene, sets
+ the pointer to the QtLogo object to null, and sets up some colors for
+ later use.
\snippet examples/opengl/hellogl/glwidget.cpp 0
@@ -105,7 +107,7 @@
\snippet examples/opengl/hellogl/glwidget.cpp 1
- The destructor ensures that the display list is deleted properly.
+ In this case nothing requires cleaning up.
We provide size hint functions to ensure that the widget is shown at a
reasonable size:
@@ -139,9 +141,9 @@
\snippet examples/opengl/hellogl/glwidget.cpp 6
In this example, we reimplement the function to set the background color,
- create a display list containing information about the object we want to
+ create a QtLogo object instance which will contain all the geometry to
display, and set up the rendering process to use a particular shading model
- and rendering flags:
+ and rendering flags.
\section2 Resizing the Viewport
@@ -172,8 +174,8 @@
In this example, we clear the widget using the background color that
we defined in the \l{QGLWidget::initializeGL()}{initializeGL()} function,
- set up the frame of reference for the object we want to display, and call
- the display list containing the rendering commands for the object.
+ set up the frame of reference for the geometry we want to display, and
+ call the draw method of the QtLogo object to render the scene.
\section2 Mouse Handling
@@ -196,12 +198,57 @@
cursor to rotate the object, the cursor's position is updated every time
a move event is received.
- \section2 Utility Functions
+ \section1 QtLogo Class
- We have omitted the utility functions, \c makeObject(), \c quad(),
- \c extrude(), and \c normalizeAngle() from our discussion. These can be
- viewed in the quoted source for \c glwidget.cpp via the link at the
- start of this document.
+ This class encapsulates the OpenGL geometry data which will be rendered
+ in the basic 3D scene.
+
+ \snippet examples/opengl/hellogl/qtlogo.h 0
+
+ The geometry is divided into a list of parts which may be rendered in
+ different ways. The data itself is contained in a Geometry structure that
+ includes the vertices, their lighting normals and index values which
+ point into the vertices, grouping them into faces.
+
+ \snippet examples/opengl/hellogl/qtlogo.cpp 0
+
+ The data in the Geometry class is stored in QVector<QVector3D> members
+ which are convenient for use with OpenGL because they expose raw
+ contiguous floating point values via the constData() method. Methods
+ are included for adding new vertex data, either with smooth normals, or
+ facetted normals; and for enabling the geometry ready for rendering.
+
+ \snippet examples/opengl/hellogl/qtlogo.cpp 1
+
+ The higher level Patch class has methods for accumulating the geometry
+ one face at a time, and treating collections of faces or "patches" with
+ transformations, applying different colors or smoothing. Although faces
+ may be added as triangles or quads, at the OpenGL level all data is
+ treated as triangles for compatibility with OpenGL/ES.
+
+ \snippet examples/opengl/hellogl/qtlogo.cpp 2
+
+ Drawing a Patch is simply acheived by applying any transformation,
+ and material effect, then drawing the data using the index range for
+ the patch. The model-view matrix is saved and then restored so that
+ any transformation does not affect other parts of the scene.
+
+ \snippet examples/opengl/hellogl/qtlogo.cpp 3
+
+ The geometry is built once on construction of the QtLogo, and it is
+ paramaterized on a number of divisions - which controls how "chunky" the
+ curved section of the logo looks - and on a scale, so larger and smaller
+ QtLogo objects can be created without having to use OpenGL scaling
+ (which would force normal recalculation).
+
+ The building process is done by helper classes (read the source for full
+ details) which only exist during the build phase, to assemble the parts
+ of the scene.
+
+ \snippet examples/opengl/hellogl/qtlogo.cpp 4
+
+ Finally the complete QtLogo scene is simply drawn by enabling the data arrays
+ and then iterating over the parts, calling draw() on each one.
\section1 Window Class Definition
diff --git a/doc/src/examples/overpainting.qdoc b/doc/src/examples/overpainting.qdoc
index 52bb160..e00ec91 100644
--- a/doc/src/examples/overpainting.qdoc
+++ b/doc/src/examples/overpainting.qdoc
@@ -53,7 +53,7 @@
yet also behaves like any other standard Qt widget with support for
signals and slots, properties, and Qt's action system.
- Usually, QGLWidget is subclassed to display a pure 3D scene; the
+ Usually, QGLWidget is subclassed to display a pure 3D scene. The
developer reimplements \l{QGLWidget::initializeGL()}{initializeGL()}
to initialize any required resources, \l{QGLWidget::resizeGL()}{resizeGL()}
to set up the projection and viewport, and
@@ -83,7 +83,7 @@
\snippet examples/opengl/overpainting/glwidget.h 4
As usual, the widget uses \l{QGLWidget::initializeGL()}{initializeGL()}
- to set up objects for our scene and perform other OpenGL initialization tasks.
+ to set up geometry for our scene and perform OpenGL initialization tasks.
The \l{QGLWidget::resizeGL()}{resizeGL()} function is used to ensure that
the 3D graphics in the scene are transformed correctly to the 2D viewport
displayed in the widget.
@@ -100,7 +100,7 @@
\c animationTimer to update the widget; the \c createBubbles() function
initializes the \c bubbles list with instances of a helper class used to
draw the animation; the \c drawInstructions() function is responsible for
- a semi-transparent messages that is also overpainted onto the OpenGL scene.
+ a semi-transparent message that is also overpainted onto the OpenGL scene.
\section1 GLWidget Class Implementation
@@ -119,8 +119,9 @@
\snippet examples/opengl/overpainting/glwidget.cpp 1
- The \c initializeGL() function is fairly minimal, only setting up the display
- list used in the scene.
+ The \c initializeGL() function is fairly minimal, only setting up the QtLogo
+ object used in the scene. See the \l{Hello GL Example}{Hello GL} example
+ for details of the QtLogo class.
\snippet examples/opengl/overpainting/glwidget.cpp 2
@@ -159,7 +160,7 @@
\snippet examples/opengl/overpainting/glwidget.cpp 7
- Once the list containing the object has been executed, the GL
+ Once the QtLogo object's draw method has been executed, the GL
states we changed and the matrix stack needs to be restored to its
original state at the start of this function before we can begin
overpainting:
@@ -176,6 +177,12 @@
When QPainter::end() is called, suitable OpenGL-specific calls are made to
write the scene, and its additional contents, onto the widget.
+ With \l{QGLWidget::paintGL()}{paintGL()} the
+ \l{QGLWidget::swapBuffers()}{swapBuffers()} call is done for us. But an explicit
+ call to swapBuffers() is still not required because in the
+ \l{QWidget::paintEvent()}{paintEvent()} method the QPainter on the OpenGL
+ widget takes care of this for us.
+
The implementation of the \l{QGLWidget::resizeGL()}{resizeGL()} function
sets up the dimensions of the viewport and defines a projection
transformation:
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