source: trunk/examples/opengl/shared/qtlogo.cpp@ 886

Last change on this file since 886 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 11.7 KB
RevLine 
[556]1/****************************************************************************
2**
[846]3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
[556]4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the examples of the Qt Toolkit.
8**
[846]9** $QT_BEGIN_LICENSE:BSD$
10** You may use this file under the terms of the BSD license as follows:
[556]11**
[846]12** "Redistribution and use in source and binary forms, with or without
13** modification, are permitted provided that the following conditions are
14** met:
15** * Redistributions of source code must retain the above copyright
16** notice, this list of conditions and the following disclaimer.
17** * Redistributions in binary form must reproduce the above copyright
18** notice, this list of conditions and the following disclaimer in
19** the documentation and/or other materials provided with the
20** distribution.
21** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
22** the names of its contributors may be used to endorse or promote
23** products derived from this software without specific prior written
24** permission.
[556]25**
[846]26** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
[556]37** $QT_END_LICENSE$
38**
39****************************************************************************/
40
41#include <QGLWidget>
42#include <QMatrix4x4>
43#include <QVector3D>
44
45#include <qmath.h>
46
47#include "qtlogo.h"
48
49static const qreal tee_height = 0.311126;
50static const qreal cross_width = 0.25;
51static const qreal bar_thickness = 0.113137;
52static const qreal inside_diam = 0.20;
53static const qreal outside_diam = 0.30;
54static const qreal logo_depth = 0.10;
55static const int num_divisions = 32;
56
57//! [0]
58struct Geometry
59{
60 QVector<GLushort> faces;
61 QVector<QVector3D> vertices;
62 QVector<QVector3D> normals;
63 void appendSmooth(const QVector3D &a, const QVector3D &n, int from);
64 void appendFaceted(const QVector3D &a, const QVector3D &n);
65 void finalize();
66 void loadArrays() const;
67};
68//! [0]
69
70//! [1]
71class Patch
72{
73public:
74 enum Smoothing { Faceted, Smooth };
75 Patch(Geometry *);
76 void setSmoothing(Smoothing s) { sm = s; }
77 void translate(const QVector3D &t);
78 void rotate(qreal deg, QVector3D axis);
79 void draw() const;
80 void addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n);
81 void addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d);
82
83 GLushort start;
84 GLushort count;
85 GLushort initv;
86
87 GLfloat faceColor[4];
88 QMatrix4x4 mat;
89 Smoothing sm;
90 Geometry *geom;
91};
92//! [1]
93
94static inline void qSetColor(float colorVec[], QColor c)
95{
96 colorVec[0] = c.redF();
97 colorVec[1] = c.greenF();
98 colorVec[2] = c.blueF();
99 colorVec[3] = c.alphaF();
100}
101
102void Geometry::loadArrays() const
103{
104 glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
105 glNormalPointer(GL_FLOAT, 0, normals.constData());
106}
107
108void Geometry::finalize()
109{
110 // TODO: add vertex buffer uploading here
111
112 // Finish smoothing normals by ensuring accumulated normals are returned
113 // to length 1.0.
114 for (int i = 0; i < normals.count(); ++i)
115 normals[i].normalize();
116}
117
118void Geometry::appendSmooth(const QVector3D &a, const QVector3D &n, int from)
119{
120 // Smooth normals are acheived by averaging the normals for faces meeting
121 // at a point. First find the point in geometry already generated
122 // (working backwards, since most often the points shared are between faces
123 // recently added).
124 int v = vertices.count() - 1;
125 for ( ; v >= from; --v)
126 if (qFuzzyCompare(vertices[v], a))
127 break;
128 if (v < from)
129 {
130 // The vert was not found so add it as a new one, and initialize
131 // its corresponding normal
132 v = vertices.count();
133 vertices.append(a);
134 normals.append(n);
135 }
136 else
137 {
138 // Vert found, accumulate normals into corresponding normal slot.
139 // Must call finalize once finished accumulating normals
140 normals[v] += n;
141 }
142 // In both cases (found or not) reference the vert via its index
143 faces.append(v);
144}
145
146void Geometry::appendFaceted(const QVector3D &a, const QVector3D &n)
147{
148 // Faceted normals are achieved by duplicating the vert for every
149 // normal, so that faces meeting at a vert get a sharp edge.
150 int v = vertices.count();
151 vertices.append(a);
152 normals.append(n);
153 faces.append(v);
154}
155
156Patch::Patch(Geometry *g)
157 : start(g->faces.count())
158 , count(0)
159 , initv(g->vertices.count())
160 , sm(Patch::Smooth)
161 , geom(g)
162{
163 qSetColor(faceColor, QColor(Qt::darkGray));
164}
165
166void Patch::rotate(qreal deg, QVector3D axis)
167{
168 mat.rotate(deg, axis);
169}
170
171void Patch::translate(const QVector3D &t)
172{
173 mat.translate(t);
174}
175
176static inline void qMultMatrix(const QMatrix4x4 &mat)
177{
178 if (sizeof(qreal) == sizeof(GLfloat))
179 glMultMatrixf((GLfloat*)mat.constData());
180#ifndef QT_OPENGL_ES
181 else if (sizeof(qreal) == sizeof(GLdouble))
182 glMultMatrixd((GLdouble*)mat.constData());
183#endif
184 else
185 {
186 GLfloat fmat[16];
187 qreal const *r = mat.constData();
188 for (int i = 0; i < 16; ++i)
189 fmat[i] = r[i];
190 glMultMatrixf(fmat);
191 }
192}
193
194//! [2]
195void Patch::draw() const
196{
197 glPushMatrix();
198 qMultMatrix(mat);
199 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, faceColor);
200
201 const GLushort *indices = geom->faces.constData();
202 glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, indices + start);
203 glPopMatrix();
204}
205//! [2]
206
207void Patch::addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n)
208{
209 QVector3D norm = n.isNull() ? QVector3D::normal(a, b, c) : n;
210 if (sm == Smooth)
211 {
212 geom->appendSmooth(a, norm, initv);
213 geom->appendSmooth(b, norm, initv);
214 geom->appendSmooth(c, norm, initv);
215 }
216 else
217 {
218 geom->appendFaceted(a, norm);
219 geom->appendFaceted(b, norm);
220 geom->appendFaceted(c, norm);
221 }
222 count += 3;
223}
224
225void Patch::addQuad(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &d)
226{
227 QVector3D norm = QVector3D::normal(a, b, c);
228 if (sm == Smooth)
229 {
230 addTri(a, b, c, norm);
231 addTri(a, c, d, norm);
232 }
233 else
234 {
235 // If faceted share the two common verts
236 addTri(a, b, c, norm);
237 int k = geom->vertices.count();
238 geom->appendSmooth(a, norm, k);
239 geom->appendSmooth(c, norm, k);
240 geom->appendFaceted(d, norm);
241 count += 3;
242 }
243}
244
245static inline QVector<QVector3D> extrude(const QVector<QVector3D> &verts, qreal depth)
246{
247 QVector<QVector3D> extr = verts;
248 for (int v = 0; v < extr.count(); ++v)
249 extr[v].setZ(extr[v].z() - depth);
250 return extr;
251}
252
253class Rectoid
254{
255public:
256 void translate(const QVector3D &t)
257 {
258 for (int i = 0; i < parts.count(); ++i)
259 parts[i]->translate(t);
260 }
261 void rotate(qreal deg, QVector3D axis)
262 {
263 for (int i = 0; i < parts.count(); ++i)
264 parts[i]->rotate(deg, axis);
265 }
266
267 // No special Rectoid destructor - the parts are fetched out of this member
268 // variable, and destroyed by the new owner
269 QList<Patch*> parts;
270};
271
272class RectPrism : public Rectoid
273{
274public:
275 RectPrism(Geometry *g, qreal width, qreal height, qreal depth);
276};
277
278RectPrism::RectPrism(Geometry *g, qreal width, qreal height, qreal depth)
279{
280 enum { bl, br, tr, tl };
281 Patch *fb = new Patch(g);
282 fb->setSmoothing(Patch::Faceted);
283
284 // front face
285 QVector<QVector3D> r(4);
286 r[br].setX(width);
287 r[tr].setX(width);
288 r[tr].setY(height);
289 r[tl].setY(height);
290 QVector3D adjToCenter(-width / 2.0, -height / 2.0, depth / 2.0);
291 for (int i = 0; i < 4; ++i)
292 r[i] += adjToCenter;
293 fb->addQuad(r[bl], r[br], r[tr], r[tl]);
294
295 // back face
296 QVector<QVector3D> s = extrude(r, depth);
297 fb->addQuad(s[tl], s[tr], s[br], s[bl]);
298
299 // side faces
300 Patch *sides = new Patch(g);
301 sides->setSmoothing(Patch::Faceted);
302 sides->addQuad(s[bl], s[br], r[br], r[bl]);
303 sides->addQuad(s[br], s[tr], r[tr], r[br]);
304 sides->addQuad(s[tr], s[tl], r[tl], r[tr]);
305 sides->addQuad(s[tl], s[bl], r[bl], r[tl]);
306
307 parts << fb << sides;
308}
309
310class RectTorus : public Rectoid
311{
312public:
313 RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int numSectors);
314};
315
316RectTorus::RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int k)
317{
318 QVector<QVector3D> inside;
319 QVector<QVector3D> outside;
320 for (int i = 0; i < k; ++i) {
321 qreal angle = (i * 2 * M_PI) / k;
322 inside << QVector3D(iRad * qSin(angle), iRad * qCos(angle), depth / 2.0);
323 outside << QVector3D(oRad * qSin(angle), oRad * qCos(angle), depth / 2.0);
324 }
325 inside << QVector3D(0.0, iRad, 0.0);
326 outside << QVector3D(0.0, oRad, 0.0);
327 QVector<QVector3D> in_back = extrude(inside, depth);
328 QVector<QVector3D> out_back = extrude(outside, depth);
329
[846]330 // Create front, back and sides as separate patches so that smooth normals
[556]331 // are generated for the curving sides, but a faceted edge is created between
332 // sides and front/back
333 Patch *front = new Patch(g);
334 for (int i = 0; i < k; ++i)
335 front->addQuad(outside[i], inside[i],
336 inside[(i + 1) % k], outside[(i + 1) % k]);
337 Patch *back = new Patch(g);
338 for (int i = 0; i < k; ++i)
339 back->addQuad(in_back[i], out_back[i],
340 out_back[(i + 1) % k], in_back[(i + 1) % k]);
341 Patch *is = new Patch(g);
342 for (int i = 0; i < k; ++i)
343 is->addQuad(in_back[i], in_back[(i + 1) % k],
344 inside[(i + 1) % k], inside[i]);
345 Patch *os = new Patch(g);
346 for (int i = 0; i < k; ++i)
347 os->addQuad(out_back[(i + 1) % k], out_back[i],
348 outside[i], outside[(i + 1) % k]);
349 parts << front << back << is << os;
350}
351
352QtLogo::QtLogo(QObject *parent, int divisions, qreal scale)
353 : QObject(parent)
354 , geom(new Geometry())
355{
356 buildGeometry(divisions, scale);
357}
358
359QtLogo::~QtLogo()
360{
361 qDeleteAll(parts);
362 delete geom;
363}
364
365void QtLogo::setColor(QColor c)
366{
367 for (int i = 0; i < parts.count(); ++i)
368 qSetColor(parts[i]->faceColor, c);
369}
370
371//! [3]
372void QtLogo::buildGeometry(int divisions, qreal scale)
373{
374 qreal cw = cross_width * scale;
375 qreal bt = bar_thickness * scale;
376 qreal ld = logo_depth * scale;
377 qreal th = tee_height *scale;
378
379 RectPrism cross(geom, cw, bt, ld);
380 RectPrism stem(geom, bt, th, ld);
381
382 QVector3D z(0.0, 0.0, 1.0);
383 cross.rotate(45.0, z);
384 stem.rotate(45.0, z);
385
386 qreal stem_downshift = (th + bt) / 2.0;
387 stem.translate(QVector3D(0.0, -stem_downshift, 0.0));
388
389 RectTorus body(geom, 0.20, 0.30, 0.1, divisions);
390
391 parts << stem.parts << cross.parts << body.parts;
392
393 geom->finalize();
394}
395//! [3]
396
397//! [4]
398void QtLogo::draw() const
399{
400 geom->loadArrays();
401
402 glEnableClientState(GL_VERTEX_ARRAY);
403 glEnableClientState(GL_NORMAL_ARRAY);
404
405 for (int i = 0; i < parts.count(); ++i)
406 parts[i]->draw();
407
408 glDisableClientState(GL_VERTEX_ARRAY);
409 glDisableClientState(GL_NORMAL_ARRAY);
410}
411//! [4]
Note: See TracBrowser for help on using the repository browser.