Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-1 into master-integration
[qt-netbsd.git] / examples / opengl / framebufferobject / glwidget.cpp
blobe7c048cd29a722aa51065d47ff6d90fa25882bfa
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 ** 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.
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.
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.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
42 #include <QtGui/QImage>
43 #include "glwidget.h"
45 #include <math.h>
47 #ifndef GL_MULTISAMPLE
48 #define GL_MULTISAMPLE 0x809D
49 #endif
51 GLWidget::GLWidget(QWidget *parent)
52 : QGLWidget(QGLFormat(QGL::SampleBuffers|QGL::AlphaChannel), parent)
54 setWindowTitle(tr("OpenGL framebuffer objects"));
55 makeCurrent();
57 if (QGLFramebufferObject::hasOpenGLFramebufferBlit()) {
58 QGLFramebufferObjectFormat format;
59 format.setSamples(4);
60 format.setAttachment(QGLFramebufferObject::CombinedDepthStencil);
62 render_fbo = new QGLFramebufferObject(512, 512, format);
63 texture_fbo = new QGLFramebufferObject(512, 512);
64 } else {
65 render_fbo = new QGLFramebufferObject(1024, 1024);
66 texture_fbo = render_fbo;
69 rot_x = rot_y = rot_z = 0.0f;
70 scale = 0.1f;
71 anim = new QTimeLine(750, this);
72 anim->setUpdateInterval(20);
73 connect(anim, SIGNAL(valueChanged(qreal)), SLOT(animate(qreal)));
74 connect(anim, SIGNAL(finished()), SLOT(animFinished()));
76 svg_renderer = new QSvgRenderer(QLatin1String(":/res/bubbles.svg"), this);
77 connect(svg_renderer, SIGNAL(repaintNeeded()), this, SLOT(draw()));
79 logo = QImage(":/res/designer.png");
80 logo = logo.convertToFormat(QImage::Format_ARGB32);
82 tile_list = glGenLists(1);
83 glNewList(tile_list, GL_COMPILE);
84 glBegin(GL_QUADS);
86 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
87 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
88 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
89 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
91 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
92 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
93 glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
94 glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
96 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
97 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
98 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
99 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
101 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
102 glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
103 glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
104 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
106 glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);
107 glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f);
108 glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
109 glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f);
111 glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);
112 glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f);
113 glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
114 glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f);
116 glEnd();
117 glEndList();
119 wave = new GLfloat[logo.width()*logo.height()];
120 memset(wave, 0, logo.width()*logo.height());
121 startTimer(30); // wave timer
124 GLWidget::~GLWidget()
126 delete[] wave;
127 glDeleteLists(tile_list, 1);
128 delete texture_fbo;
129 if (render_fbo != texture_fbo)
130 delete render_fbo;
133 void GLWidget::paintEvent(QPaintEvent *)
135 draw();
138 void GLWidget::draw()
140 QPainter p(this); // used for text overlay
142 // save the GL state set for QPainter
143 saveGLState();
145 // render the 'bubbles.svg' file into our framebuffer object
146 QPainter fbo_painter(render_fbo);
147 svg_renderer->render(&fbo_painter);
148 fbo_painter.end();
150 if (render_fbo != texture_fbo) {
151 QRect rect(0, 0, render_fbo->width(), render_fbo->height());
152 QGLFramebufferObject::blitFramebuffer(texture_fbo, rect,
153 render_fbo, rect);
156 // draw into the GL widget
157 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
158 glMatrixMode(GL_PROJECTION);
159 glLoadIdentity();
160 glFrustum(-1, 1, -1, 1, 10, 100);
161 glTranslatef(0.0f, 0.0f, -15.0f);
162 glMatrixMode(GL_MODELVIEW);
163 glLoadIdentity();
164 glViewport(0, 0, width(), height());
165 glEnable(GL_BLEND);
166 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
168 glBindTexture(GL_TEXTURE_2D, texture_fbo->texture());
169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
171 glEnable(GL_TEXTURE_2D);
172 glEnable(GL_MULTISAMPLE);
173 glEnable(GL_CULL_FACE);
175 // draw background
176 glPushMatrix();
177 glScalef(1.7f, 1.7f, 1.7f);
178 glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
179 glCallList(tile_list);
180 glPopMatrix();
182 const int w = logo.width();
183 const int h = logo.height();
185 glRotatef(rot_x, 1.0f, 0.0f, 0.0f);
186 glRotatef(rot_y, 0.0f, 1.0f, 0.0f);
187 glRotatef(rot_z, 0.0f, 0.0f, 1.0f);
188 glScalef(scale/w, scale/w, scale/w);
190 glDepthFunc(GL_LESS);
191 glEnable(GL_DEPTH_TEST);
192 // draw the Qt icon
193 glTranslatef(-w+1, -h+1, 0.0f);
194 for (int y=h-1; y>=0; --y) {
195 uint *p = (uint*) logo.scanLine(y);
196 uint *end = p + w;
197 int x = 0;
198 while (p < end) {
199 glColor4ub(qRed(*p), qGreen(*p), qBlue(*p), uchar(qAlpha(*p)*.9));
200 glTranslatef(0.0f, 0.0f, wave[y*w+x]);
201 if (qAlpha(*p) > 128)
202 glCallList(tile_list);
203 glTranslatef(0.0f, 0.0f, -wave[y*w+x]);
204 glTranslatef(2.0f, 0.0f, 0.0f);
205 ++x;
206 ++p;
208 glTranslatef(-w*2.0f, 2.0f, 0.0f);
211 // restore the GL state that QPainter expects
212 restoreGLState();
214 // draw the overlayed text using QPainter
215 p.setPen(QColor(197, 197, 197, 157));
216 p.setBrush(QColor(197, 197, 197, 127));
217 p.drawRect(QRect(0, 0, width(), 50));
218 p.setPen(Qt::black);
219 p.setBrush(Qt::NoBrush);
220 const QString str1(tr("A simple OpenGL framebuffer object example."));
221 const QString str2(tr("Use the mouse wheel to zoom, press buttons and move mouse to rotate, double-click to flip."));
222 QFontMetrics fm(p.font());
223 p.drawText(width()/2 - fm.width(str1)/2, 20, str1);
224 p.drawText(width()/2 - fm.width(str2)/2, 20 + fm.lineSpacing(), str2);
227 void GLWidget::mousePressEvent(QMouseEvent *e)
229 anchor = e->pos();
232 void GLWidget::mouseMoveEvent(QMouseEvent *e)
234 QPoint diff = e->pos() - anchor;
235 if (e->buttons() & Qt::LeftButton) {
236 rot_x += diff.y()/5.0f;
237 rot_y += diff.x()/5.0f;
238 } else if (e->buttons() & Qt::RightButton) {
239 rot_z += diff.x()/5.0f;
242 anchor = e->pos();
243 draw();
246 void GLWidget::wheelEvent(QWheelEvent *e)
248 e->delta() > 0 ? scale += scale*0.1f : scale -= scale*0.1f;
249 draw();
252 void GLWidget::mouseDoubleClickEvent(QMouseEvent *)
254 anim->start();
257 void GLWidget::animate(qreal val)
259 rot_y = val * 180;
260 draw();
263 void GLWidget::animFinished()
265 if (anim->direction() == QTimeLine::Forward)
266 anim->setDirection(QTimeLine::Backward);
267 else
268 anim->setDirection(QTimeLine::Forward);
271 void GLWidget::saveGLState()
273 glPushAttrib(GL_ALL_ATTRIB_BITS);
274 glMatrixMode(GL_PROJECTION);
275 glPushMatrix();
276 glMatrixMode(GL_MODELVIEW);
277 glPushMatrix();
280 void GLWidget::restoreGLState()
282 glMatrixMode(GL_PROJECTION);
283 glPopMatrix();
284 glMatrixMode(GL_MODELVIEW);
285 glPopMatrix();
286 glPopAttrib();
289 #define PI 3.14159
291 void GLWidget::timerEvent(QTimerEvent *)
293 if (QApplication::mouseButtons() != 0)
294 return;
296 static bool scale_in = true;
298 if (scale_in && scale > 35.0f)
299 scale_in = false;
300 else if (!scale_in && scale < .5f)
301 scale_in = true;
303 scale = scale_in ? scale + scale*0.01f : scale-scale*0.01f;
304 rot_z += 0.3f;
305 rot_x += 0.1f;
307 int dx, dy; // disturbance point
308 float s, v, W, t;
309 int i, j;
310 static float wt[128][128];
311 const int width = logo.width();
312 const int AMP = 5;
314 dx = dy = width >> 1;
316 W = .3f;
317 v = -4; // wave speed
319 for (i = 0; i < width; ++i) {
320 for ( j = 0; j < width; ++j) {
321 s = sqrt((double) ((j - dx) * (j - dx) + (i - dy) * (i - dy)));
322 wt[i][j] += 0.1f;
323 t = s / v;
324 if (s != 0)
325 wave[i*width + j] = AMP * sin(2 * PI * W * (wt[i][j] + t)) / (0.2*(s + 2));
326 else
327 wave[i*width + j] = AMP * sin(2 * PI * W * (wt[i][j] + t));