diff options
author | Sarah Smith <sarah.j.smith@nokia.com> | 2009-09-21 01:23:06 (GMT) |
---|---|---|
committer | Sarah Smith <sarah.j.smith@nokia.com> | 2009-09-21 01:23:06 (GMT) |
commit | 11fed1f64f43593a2890e0a3f27b4e2e7ebde783 (patch) | |
tree | 99f57336eafe2403af7526154d8d4743f416333e /examples/opengl/shared | |
parent | 1b8d92b1ae453bd2d395658c7086d0049916e88f (diff) | |
download | Qt-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/shared')
-rw-r--r-- | examples/opengl/shared/qtlogo.cpp | 403 | ||||
-rw-r--r-- | examples/opengl/shared/qtlogo.h | 67 |
2 files changed, 470 insertions, 0 deletions
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 |