examples/opengl/shared/qtlogo.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the examples of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QGLWidget>
       
    43 #include <QMatrix4x4>
       
    44 #include <QVector3D>
       
    45 
       
    46 #include <qmath.h>
       
    47 
       
    48 #include "qtlogo.h"
       
    49 
       
    50 static const qreal tee_height = 0.311126;
       
    51 static const qreal cross_width = 0.25;
       
    52 static const qreal bar_thickness = 0.113137;
       
    53 static const qreal inside_diam = 0.20;
       
    54 static const qreal outside_diam = 0.30;
       
    55 static const qreal logo_depth = 0.10;
       
    56 static const int num_divisions = 32;
       
    57 
       
    58 //! [0]
       
    59 struct Geometry
       
    60 {
       
    61     QVector<GLushort> faces;
       
    62     QVector<QVector3D> vertices;
       
    63     QVector<QVector3D> normals;
       
    64     void appendSmooth(const QVector3D &a, const QVector3D &n, int from);
       
    65     void appendFaceted(const QVector3D &a, const QVector3D &n);
       
    66     void finalize();
       
    67     void loadArrays() const;
       
    68 };
       
    69 //! [0]
       
    70 
       
    71 //! [1]
       
    72 class Patch
       
    73 {
       
    74 public:
       
    75     enum Smoothing { Faceted, Smooth };
       
    76     Patch(Geometry *);
       
    77     void setSmoothing(Smoothing s) { sm = s; }
       
    78     void translate(const QVector3D &t);
       
    79     void rotate(qreal deg, QVector3D axis);
       
    80     void draw() const;
       
    81     void addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n);
       
    82     void addQuad(const QVector3D &a, const QVector3D &b,  const QVector3D &c, const QVector3D &d);
       
    83 
       
    84     GLushort start;
       
    85     GLushort count;
       
    86     GLushort initv;
       
    87 
       
    88     GLfloat faceColor[4];
       
    89     QMatrix4x4 mat;
       
    90     Smoothing sm;
       
    91     Geometry *geom;
       
    92 };
       
    93 //! [1]
       
    94 
       
    95 static inline void qSetColor(float colorVec[], QColor c)
       
    96 {
       
    97     colorVec[0] = c.redF();
       
    98     colorVec[1] = c.greenF();
       
    99     colorVec[2] = c.blueF();
       
   100     colorVec[3] = c.alphaF();
       
   101 }
       
   102 
       
   103 void Geometry::loadArrays() const
       
   104 {
       
   105     glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
       
   106     glNormalPointer(GL_FLOAT, 0, normals.constData());
       
   107 }
       
   108 
       
   109 void Geometry::finalize()
       
   110 {
       
   111     // TODO: add vertex buffer uploading here
       
   112 
       
   113     // Finish smoothing normals by ensuring accumulated normals are returned
       
   114     // to length 1.0.
       
   115     for (int i = 0; i < normals.count(); ++i)
       
   116         normals[i].normalize();
       
   117 }
       
   118 
       
   119 void Geometry::appendSmooth(const QVector3D &a, const QVector3D &n, int from)
       
   120 {
       
   121     // Smooth normals are acheived by averaging the normals for faces meeting
       
   122     // at a point.  First find the point in geometry already generated
       
   123     // (working backwards, since most often the points shared are between faces
       
   124     // recently added).
       
   125     int v = vertices.count() - 1;
       
   126     for ( ; v >= from; --v)
       
   127         if (qFuzzyCompare(vertices[v], a))
       
   128             break;
       
   129     if (v < from)
       
   130     {
       
   131         // The vert was not found so add it as a new one, and initialize
       
   132         // its corresponding normal
       
   133         v = vertices.count();
       
   134         vertices.append(a);
       
   135         normals.append(n);
       
   136     }
       
   137     else
       
   138     {
       
   139         // Vert found, accumulate normals into corresponding normal slot.
       
   140         // Must call finalize once finished accumulating normals
       
   141         normals[v] += n;
       
   142     }
       
   143     // In both cases (found or not) reference the vert via its index
       
   144     faces.append(v);
       
   145 }
       
   146 
       
   147 void Geometry::appendFaceted(const QVector3D &a, const QVector3D &n)
       
   148 {
       
   149     // Faceted normals are achieved by duplicating the vert for every
       
   150     // normal, so that faces meeting at a vert get a sharp edge.
       
   151     int v = vertices.count();
       
   152     vertices.append(a);
       
   153     normals.append(n);
       
   154     faces.append(v);
       
   155 }
       
   156 
       
   157 Patch::Patch(Geometry *g)
       
   158    : start(g->faces.count())
       
   159    , count(0)
       
   160    , initv(g->vertices.count())
       
   161    , sm(Patch::Smooth)
       
   162    , geom(g)
       
   163 {
       
   164     qSetColor(faceColor, QColor(Qt::darkGray));
       
   165 }
       
   166 
       
   167 void Patch::rotate(qreal deg, QVector3D axis)
       
   168 {
       
   169     mat.rotate(deg, axis);
       
   170 }
       
   171 
       
   172 void Patch::translate(const QVector3D &t)
       
   173 {
       
   174     mat.translate(t);
       
   175 }
       
   176 
       
   177 static inline void qMultMatrix(const QMatrix4x4 &mat)
       
   178 {
       
   179     if (sizeof(qreal) == sizeof(GLfloat))
       
   180         glMultMatrixf((GLfloat*)mat.constData());
       
   181 #ifndef QT_OPENGL_ES
       
   182     else if (sizeof(qreal) == sizeof(GLdouble))
       
   183         glMultMatrixd((GLdouble*)mat.constData());
       
   184 #endif
       
   185     else
       
   186     {
       
   187         GLfloat fmat[16];
       
   188         qreal const *r = mat.constData();
       
   189         for (int i = 0; i < 16; ++i)
       
   190             fmat[i] = r[i];
       
   191         glMultMatrixf(fmat);
       
   192     }
       
   193 }
       
   194 
       
   195 //! [2]
       
   196 void Patch::draw() const
       
   197 {
       
   198     glPushMatrix();
       
   199     qMultMatrix(mat);
       
   200     glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor);
       
   201 
       
   202     const GLushort *indices = geom->faces.constData();
       
   203     glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indices + start);
       
   204     glPopMatrix();
       
   205 }
       
   206 //! [2]
       
   207 
       
   208 void Patch::addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n)
       
   209 {
       
   210     QVector3D norm = n.isNull() ? QVector3D::normal(a, b, c) : n;
       
   211     if (sm == Smooth)
       
   212     {
       
   213         geom->appendSmooth(a, norm, initv);
       
   214         geom->appendSmooth(b, norm, initv);
       
   215         geom->appendSmooth(c, norm, initv);
       
   216     }
       
   217     else
       
   218     {
       
   219         geom->appendFaceted(a, norm);
       
   220         geom->appendFaceted(b, norm);
       
   221         geom->appendFaceted(c, norm);
       
   222     }
       
   223     count += 3;
       
   224 }
       
   225 
       
   226 void Patch::addQuad(const QVector3D &a, const QVector3D &b,  const QVector3D &c, const QVector3D &d)
       
   227 {
       
   228     QVector3D norm = QVector3D::normal(a, b, c);
       
   229     if (sm == Smooth)
       
   230     {
       
   231         addTri(a, b, c, norm);
       
   232         addTri(a, c, d, norm);
       
   233     }
       
   234     else
       
   235     {
       
   236         // If faceted share the two common verts
       
   237         addTri(a, b, c, norm);
       
   238         int k = geom->vertices.count();
       
   239         geom->appendSmooth(a, norm, k);
       
   240         geom->appendSmooth(c, norm, k);
       
   241         geom->appendFaceted(d, norm);
       
   242         count += 3;
       
   243     }
       
   244 }
       
   245 
       
   246 static inline QVector<QVector3D> extrude(const QVector<QVector3D> &verts, qreal depth)
       
   247 {
       
   248     QVector<QVector3D> extr = verts;
       
   249     for (int v = 0; v < extr.count(); ++v)
       
   250         extr[v].setZ(extr[v].z() - depth);
       
   251     return extr;
       
   252 }
       
   253 
       
   254 class Rectoid
       
   255 {
       
   256 public:
       
   257     void translate(const QVector3D &t)
       
   258     {
       
   259         for (int i = 0; i < parts.count(); ++i)
       
   260             parts[i]->translate(t);
       
   261     }
       
   262     void rotate(qreal deg, QVector3D axis)
       
   263     {
       
   264         for (int i = 0; i < parts.count(); ++i)
       
   265             parts[i]->rotate(deg, axis);
       
   266     }
       
   267 
       
   268     // No special Rectoid destructor - the parts are fetched out of this member
       
   269     // variable, and destroyed by the new owner
       
   270     QList<Patch*> parts;
       
   271 };
       
   272 
       
   273 class RectPrism : public Rectoid
       
   274 {
       
   275 public:
       
   276     RectPrism(Geometry *g, qreal width, qreal height, qreal depth);
       
   277 };
       
   278 
       
   279 RectPrism::RectPrism(Geometry *g, qreal width, qreal height, qreal depth)
       
   280 {
       
   281     enum { bl, br, tr, tl };
       
   282     Patch *fb = new Patch(g);
       
   283     fb->setSmoothing(Patch::Faceted);
       
   284 
       
   285     // front face
       
   286     QVector<QVector3D> r(4);
       
   287     r[br].setX(width);
       
   288     r[tr].setX(width);
       
   289     r[tr].setY(height);
       
   290     r[tl].setY(height);
       
   291     QVector3D adjToCenter(-width / 2.0, -height / 2.0, depth / 2.0);
       
   292     for (int i = 0; i < 4; ++i)
       
   293         r[i] += adjToCenter;
       
   294     fb->addQuad(r[bl], r[br], r[tr], r[tl]);
       
   295 
       
   296     // back face
       
   297     QVector<QVector3D> s = extrude(r, depth);
       
   298     fb->addQuad(s[tl], s[tr], s[br], s[bl]);
       
   299 
       
   300     // side faces
       
   301     Patch *sides = new Patch(g);
       
   302     sides->setSmoothing(Patch::Faceted);
       
   303     sides->addQuad(s[bl], s[br], r[br], r[bl]);
       
   304     sides->addQuad(s[br], s[tr], r[tr], r[br]);
       
   305     sides->addQuad(s[tr], s[tl], r[tl], r[tr]);
       
   306     sides->addQuad(s[tl], s[bl], r[bl], r[tl]);
       
   307 
       
   308     parts << fb << sides;
       
   309 }
       
   310 
       
   311 class RectTorus : public Rectoid
       
   312 {
       
   313 public:
       
   314     RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int numSectors);
       
   315 };
       
   316 
       
   317 RectTorus::RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int k)
       
   318 {
       
   319     QVector<QVector3D> inside;
       
   320     QVector<QVector3D> outside;
       
   321     for (int i = 0; i < k; ++i) {
       
   322         qreal angle = (i * 2 * M_PI) / k;
       
   323         inside << QVector3D(iRad * qSin(angle), iRad * qCos(angle), depth / 2.0);
       
   324         outside << QVector3D(oRad * qSin(angle), oRad * qCos(angle), depth / 2.0);
       
   325     }
       
   326     inside << QVector3D(0.0, iRad, 0.0);
       
   327     outside << QVector3D(0.0, oRad, 0.0);
       
   328     QVector<QVector3D> in_back = extrude(inside, depth);
       
   329     QVector<QVector3D> out_back = extrude(outside, depth);
       
   330 
       
   331     // Create front, back and sides as seperate patches so that smooth normals
       
   332     // are generated for the curving sides, but a faceted edge is created between
       
   333     // sides and front/back
       
   334     Patch *front = new Patch(g);
       
   335     for (int i = 0; i < k; ++i)
       
   336         front->addQuad(outside[i], inside[i],
       
   337                        inside[(i + 1) % k], outside[(i + 1) % k]);
       
   338     Patch *back = new Patch(g);
       
   339     for (int i = 0; i < k; ++i)
       
   340         back->addQuad(in_back[i], out_back[i],
       
   341                       out_back[(i + 1) % k], in_back[(i + 1) % k]);
       
   342     Patch *is = new Patch(g);
       
   343     for (int i = 0; i < k; ++i)
       
   344         is->addQuad(in_back[i], in_back[(i + 1) % k],
       
   345                     inside[(i + 1) % k], inside[i]);
       
   346     Patch *os = new Patch(g);
       
   347     for (int i = 0; i < k; ++i)
       
   348         os->addQuad(out_back[(i + 1) % k], out_back[i],
       
   349                     outside[i], outside[(i + 1) % k]);
       
   350     parts << front << back << is << os;
       
   351 }
       
   352 
       
   353 QtLogo::QtLogo(QObject *parent, int divisions, qreal scale)
       
   354     : QObject(parent)
       
   355     , geom(new Geometry())
       
   356 {
       
   357     buildGeometry(divisions, scale);
       
   358 }
       
   359 
       
   360 QtLogo::~QtLogo()
       
   361 {
       
   362     qDeleteAll(parts);
       
   363     delete geom;
       
   364 }
       
   365 
       
   366 void QtLogo::setColor(QColor c)
       
   367 {
       
   368     for (int i = 0; i < parts.count(); ++i)
       
   369         qSetColor(parts[i]->faceColor, c);
       
   370 }
       
   371 
       
   372 //! [3]
       
   373 void QtLogo::buildGeometry(int divisions, qreal scale)
       
   374 {
       
   375     qreal cw = cross_width * scale;
       
   376     qreal bt = bar_thickness * scale;
       
   377     qreal ld = logo_depth * scale;
       
   378     qreal th = tee_height *scale;
       
   379 
       
   380     RectPrism cross(geom, cw, bt, ld);
       
   381     RectPrism stem(geom, bt, th, ld);
       
   382 
       
   383     QVector3D z(0.0, 0.0, 1.0);
       
   384     cross.rotate(45.0, z);
       
   385     stem.rotate(45.0, z);
       
   386 
       
   387     qreal stem_downshift = (th + bt) / 2.0;
       
   388     stem.translate(QVector3D(0.0, -stem_downshift, 0.0));
       
   389 
       
   390     RectTorus body(geom, 0.20, 0.30, 0.1, divisions);
       
   391 
       
   392     parts << stem.parts << cross.parts << body.parts;
       
   393 
       
   394     geom->finalize();
       
   395 }
       
   396 //! [3]
       
   397 
       
   398 //! [4]
       
   399 void QtLogo::draw() const
       
   400 {
       
   401     geom->loadArrays();
       
   402 
       
   403     glEnableClientState(GL_VERTEX_ARRAY);
       
   404     glEnableClientState(GL_NORMAL_ARRAY);
       
   405 
       
   406     for (int i = 0; i < parts.count(); ++i)
       
   407         parts[i]->draw();
       
   408 
       
   409     glDisableClientState(GL_VERTEX_ARRAY);
       
   410     glDisableClientState(GL_NORMAL_ARRAY);
       
   411 }
       
   412 //! [4]