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

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

  • Property svn:eol-style set to native
File size: 11.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 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** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
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
50static const qreal tee_height = 0.311126;
51static const qreal cross_width = 0.25;
52static const qreal bar_thickness = 0.113137;
53static const qreal inside_diam = 0.20;
54static const qreal outside_diam = 0.30;
55static const qreal logo_depth = 0.10;
56static const int num_divisions = 32;
57
58//! [0]
59struct 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]
72class Patch
73{
74public:
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
95static 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
103void Geometry::loadArrays() const
104{
105 glVertexPointer(3, GL_FLOAT, 0, vertices.constData());
106 glNormalPointer(GL_FLOAT, 0, normals.constData());
107}
108
109void 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
119void 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
147void 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
157Patch::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
167void Patch::rotate(qreal deg, QVector3D axis)
168{
169 mat.rotate(deg, axis);
170}
171
172void Patch::translate(const QVector3D &t)
173{
174 mat.translate(t);
175}
176
177static 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]
196void 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
208void 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
226void 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
246static 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
254class Rectoid
255{
256public:
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
273class RectPrism : public Rectoid
274{
275public:
276 RectPrism(Geometry *g, qreal width, qreal height, qreal depth);
277};
278
279RectPrism::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
311class RectTorus : public Rectoid
312{
313public:
314 RectTorus(Geometry *g, qreal iRad, qreal oRad, qreal depth, int numSectors);
315};
316
317RectTorus::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
353QtLogo::QtLogo(QObject *parent, int divisions, qreal scale)
354 : QObject(parent)
355 , geom(new Geometry())
356{
357 buildGeometry(divisions, scale);
358}
359
360QtLogo::~QtLogo()
361{
362 qDeleteAll(parts);
363 delete geom;
364}
365
366void QtLogo::setColor(QColor c)
367{
368 for (int i = 0; i < parts.count(); ++i)
369 qSetColor(parts[i]->faceColor, c);
370}
371
372//! [3]
373void 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]
399void 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]
Note: See TracBrowser for help on using the repository browser.