source: trunk/demos/boxes/scene.cpp@ 352

Last change on this file since 352 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 34.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the demonstration applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "scene.h"
43
44#include "3rdparty/fbm.h"
45
46void checkGLErrors(const QString& prefix)
47{
48 switch (glGetError()) {
49 case GL_NO_ERROR:
50 //qDebug() << prefix << tr("No error.");
51 break;
52 case GL_INVALID_ENUM:
53 qDebug() << prefix << QObject::tr("Invalid enum.");
54 break;
55 case GL_INVALID_VALUE:
56 qDebug() << prefix << QObject::tr("Invalid value.");
57 break;
58 case GL_INVALID_OPERATION:
59 qDebug() << prefix << QObject::tr("Invalid operation.");
60 break;
61 case GL_STACK_OVERFLOW:
62 qDebug() << prefix << QObject::tr("Stack overflow.");
63 break;
64 case GL_STACK_UNDERFLOW:
65 qDebug() << prefix << QObject::tr("Stack underflow.");
66 break;
67 case GL_OUT_OF_MEMORY:
68 qDebug() << prefix << QObject::tr("Out of memory.");
69 break;
70 default:
71 qDebug() << prefix << QObject::tr("Unknown error.");
72 break;
73 }
74}
75
76//============================================================================//
77// ColorEdit //
78//============================================================================//
79
80ColorEdit::ColorEdit(QRgb initialColor, int id)
81 : m_color(initialColor), m_id(id)
82{
83 QHBoxLayout *layout = new QHBoxLayout;
84 setLayout(layout);
85 layout->setContentsMargins(0, 0, 0, 0);
86
87 m_lineEdit = new QLineEdit(QString::number(m_color, 16));
88 layout->addWidget(m_lineEdit);
89
90 m_button = new QFrame;
91 QPalette palette = m_button->palette();
92 palette.setColor(QPalette::Window, QColor(m_color));
93 m_button->setPalette(palette);
94 m_button->setAutoFillBackground(true);
95 m_button->setMinimumSize(32, 0);
96 m_button->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
97 m_button->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
98 layout->addWidget(m_button);
99
100 connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
101}
102
103void ColorEdit::editDone()
104{
105 bool ok;
106 QRgb newColor = m_lineEdit->text().toUInt(&ok, 16);
107 if (ok)
108 setColor(newColor);
109}
110
111void ColorEdit::mousePressEvent(QMouseEvent *event)
112{
113 if (event->button() == Qt::LeftButton) {
114 QColor color(m_color);
115 QColorDialog dialog(color, 0);
116 dialog.setOption(QColorDialog::ShowAlphaChannel, true);
117// The ifdef block is a workaround for the beta, TODO: remove when bug 238525 is fixed
118#ifdef Q_WS_MAC
119 dialog.setOption(QColorDialog::DontUseNativeDialog, true);
120#endif
121 dialog.move(280, 120);
122 if (dialog.exec() == QDialog::Rejected)
123 return;
124 QRgb newColor = dialog.selectedColor().rgba();
125 if (newColor == m_color)
126 return;
127 setColor(newColor);
128 }
129}
130
131void ColorEdit::setColor(QRgb color)
132{
133 m_color = color;
134 m_lineEdit->setText(QString::number(m_color, 16)); // "Clean up" text
135 QPalette palette = m_button->palette();
136 palette.setColor(QPalette::Window, QColor(m_color));
137 m_button->setPalette(palette);
138 emit colorChanged(m_color, m_id);
139}
140
141//============================================================================//
142// FloatEdit //
143//============================================================================//
144
145FloatEdit::FloatEdit(float initialValue, int id)
146 : m_value(initialValue), m_id(id)
147{
148 QHBoxLayout *layout = new QHBoxLayout;
149 setLayout(layout);
150 layout->setContentsMargins(0, 0, 0, 0);
151
152 m_lineEdit = new QLineEdit(QString::number(m_value));
153 layout->addWidget(m_lineEdit);
154
155 connect(m_lineEdit, SIGNAL(editingFinished()), this, SLOT(editDone()));
156}
157
158void FloatEdit::editDone()
159{
160 bool ok;
161 float newValue = m_lineEdit->text().toFloat(&ok);
162 if (ok) {
163 m_value = newValue;
164 m_lineEdit->setText(QString::number(m_value)); // "Clean up" text
165 emit valueChanged(m_value, m_id);
166 }
167}
168
169//============================================================================//
170// TwoSidedGraphicsWidget //
171//============================================================================//
172
173TwoSidedGraphicsWidget::TwoSidedGraphicsWidget(QGraphicsScene *scene)
174 : QObject(scene)
175 , m_current(0)
176 , m_angle(0)
177 , m_delta(0)
178{
179 for (int i = 0; i < 2; ++i)
180 m_proxyWidgets[i] = 0;
181}
182
183void TwoSidedGraphicsWidget::setWidget(int index, QWidget *widget)
184{
185 if (index < 0 || index >= 2)
186 {
187 qWarning("TwoSidedGraphicsWidget::setWidget: Index out of bounds, index == %d", index);
188 return;
189 }
190
191 GraphicsWidget *proxy = new GraphicsWidget;
192 proxy->setWidget(widget);
193
194 if (m_proxyWidgets[index])
195 delete m_proxyWidgets[index];
196 m_proxyWidgets[index] = proxy;
197
198 proxy->setCacheMode(QGraphicsItem::ItemCoordinateCache);
199 proxy->setZValue(1e30); // Make sure the dialog is drawn on top of all other (OpenGL) items
200
201 if (index != m_current)
202 proxy->setVisible(false);
203
204 qobject_cast<QGraphicsScene *>(parent())->addItem(proxy);
205}
206
207QWidget *TwoSidedGraphicsWidget::widget(int index)
208{
209 if (index < 0 || index >= 2)
210 {
211 qWarning("TwoSidedGraphicsWidget::widget: Index out of bounds, index == %d", index);
212 return 0;
213 }
214 return m_proxyWidgets[index]->widget();
215}
216
217void TwoSidedGraphicsWidget::flip()
218{
219 m_delta = (m_current == 0 ? 9 : -9);
220 animateFlip();
221}
222
223void TwoSidedGraphicsWidget::animateFlip()
224{
225 m_angle += m_delta;
226 if (m_angle == 90) {
227 int old = m_current;
228 m_current ^= 1;
229 m_proxyWidgets[old]->setVisible(false);
230 m_proxyWidgets[m_current]->setVisible(true);
231 m_proxyWidgets[m_current]->setGeometry(m_proxyWidgets[old]->geometry());
232 }
233
234 QRectF r = m_proxyWidgets[m_current]->boundingRect();
235 m_proxyWidgets[m_current]->setTransform(QTransform()
236 .translate(r.width() / 2, r.height() / 2)
237 .rotate(m_angle - 180 * m_current, Qt::YAxis)
238 .translate(-r.width() / 2, -r.height() / 2));
239
240 if ((m_current == 0 && m_angle > 0) || (m_current == 1 && m_angle < 180))
241 QTimer::singleShot(25, this, SLOT(animateFlip()));
242}
243
244QVariant GraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
245{
246 if (change == ItemPositionChange && scene()) {
247 QRectF rect = boundingRect();
248 QPointF pos = value.toPointF();
249 QRectF sceneRect = scene()->sceneRect();
250 if (pos.x() + rect.left() < sceneRect.left())
251 pos.setX(sceneRect.left() - rect.left());
252 else if (pos.x() + rect.right() >= sceneRect.right())
253 pos.setX(sceneRect.right() - rect.right());
254 if (pos.y() + rect.top() < sceneRect.top())
255 pos.setY(sceneRect.top() - rect.top());
256 else if (pos.y() + rect.bottom() >= sceneRect.bottom())
257 pos.setY(sceneRect.bottom() - rect.bottom());
258 return pos;
259 }
260 return QGraphicsProxyWidget::itemChange(change, value);
261}
262
263void GraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
264{
265 setCacheMode(QGraphicsItem::NoCache);
266 setCacheMode(QGraphicsItem::ItemCoordinateCache);
267 QGraphicsProxyWidget::resizeEvent(event);
268}
269
270void GraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
271{
272 painter->setRenderHint(QPainter::Antialiasing, false);
273 QGraphicsProxyWidget::paint(painter, option, widget);
274 //painter->setRenderHint(QPainter::Antialiasing, true);
275}
276
277//============================================================================//
278// RenderOptionsDialog //
279//============================================================================//
280
281RenderOptionsDialog::RenderOptionsDialog()
282 : QDialog(0, Qt::CustomizeWindowHint | Qt::WindowTitleHint)
283{
284 setWindowOpacity(0.75);
285 setWindowTitle(tr("Options (double click to flip)"));
286 QGridLayout *layout = new QGridLayout;
287 setLayout(layout);
288 layout->setColumnStretch(1, 1);
289
290 int row = 0;
291
292 QCheckBox *check = new QCheckBox(tr("Dynamic cube map"));
293 check->setCheckState(Qt::Unchecked);
294 // Dynamic cube maps are only enabled when multi-texturing and render to texture are available.
295 check->setEnabled(glActiveTexture && glGenFramebuffersEXT);
296 connect(check, SIGNAL(stateChanged(int)), this, SIGNAL(dynamicCubemapToggled(int)));
297 layout->addWidget(check, 0, 0, 1, 2);
298 ++row;
299
300 QPalette palette;
301
302 // Load all .par files
303 // .par files have a simple syntax for specifying user adjustable uniform variables.
304 QSet<QByteArray> uniforms;
305 QList<QString> filter = QStringList("*.par");
306 QList<QFileInfo> files = QDir(":/res/boxes/").entryInfoList(filter, QDir::Files | QDir::Readable);
307
308 foreach (QFileInfo fileInfo, files) {
309 QFile file(fileInfo.absoluteFilePath());
310 if (file.open(QIODevice::ReadOnly)) {
311 while (!file.atEnd()) {
312 QList<QByteArray> tokens = file.readLine().simplified().split(' ');
313 QList<QByteArray>::const_iterator it = tokens.begin();
314 if (it == tokens.end())
315 continue;
316 QByteArray type = *it;
317 if (++it == tokens.end())
318 continue;
319 QByteArray name = *it;
320 bool singleElement = (tokens.size() == 3); // type, name and one value
321 char counter[10] = "000000000";
322 int counterPos = 8; // position of last digit
323 while (++it != tokens.end()) {
324 m_parameterNames << name;
325 if (!singleElement) {
326 m_parameterNames.back() += "[";
327 m_parameterNames.back() += counter + counterPos;
328 m_parameterNames.back() += "]";
329 int j = 8; // position of last digit
330 ++counter[j];
331 while (j > 0 && counter[j] > '9') {
332 counter[j] = '0';
333 ++counter[--j];
334 }
335 if (j < counterPos)
336 counterPos = j;
337 }
338
339 if (type == "color") {
340 layout->addWidget(new QLabel(m_parameterNames.back()));
341 bool ok;
342 ColorEdit *colorEdit = new ColorEdit(it->toUInt(&ok, 16), m_parameterNames.size() - 1);
343 m_parameterEdits << colorEdit;
344 layout->addWidget(colorEdit);
345 connect(colorEdit, SIGNAL(colorChanged(QRgb, int)), this, SLOT(setColorParameter(QRgb, int)));
346 ++row;
347 } else if (type == "float") {
348 layout->addWidget(new QLabel(m_parameterNames.back()));
349 bool ok;
350 FloatEdit *floatEdit = new FloatEdit(it->toFloat(&ok), m_parameterNames.size() - 1);
351 m_parameterEdits << floatEdit;
352 layout->addWidget(floatEdit);
353 connect(floatEdit, SIGNAL(valueChanged(float, int)), this, SLOT(setFloatParameter(float, int)));
354 ++row;
355 }
356 }
357 }
358 file.close();
359 }
360 }
361
362 layout->addWidget(new QLabel(tr("Texture:")));
363 m_textureCombo = new QComboBox;
364 connect(m_textureCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(textureChanged(int)));
365 layout->addWidget(m_textureCombo);
366 ++row;
367
368 layout->addWidget(new QLabel(tr("Shader:")));
369 m_shaderCombo = new QComboBox;
370 connect(m_shaderCombo, SIGNAL(currentIndexChanged(int)), this, SIGNAL(shaderChanged(int)));
371 layout->addWidget(m_shaderCombo);
372 ++row;
373
374 layout->setRowStretch(row, 1);
375}
376
377int RenderOptionsDialog::addTexture(const QString &name)
378{
379 m_textureCombo->addItem(name);
380 return m_textureCombo->count() - 1;
381}
382
383int RenderOptionsDialog::addShader(const QString &name)
384{
385 m_shaderCombo->addItem(name);
386 return m_shaderCombo->count() - 1;
387}
388
389void RenderOptionsDialog::emitParameterChanged()
390{
391 foreach (ParameterEdit *edit, m_parameterEdits)
392 edit->emitChange();
393}
394
395void RenderOptionsDialog::setColorParameter(QRgb color, int id)
396{
397 emit colorParameterChanged(m_parameterNames[id], color);
398}
399
400void RenderOptionsDialog::setFloatParameter(float value, int id)
401{
402 emit floatParameterChanged(m_parameterNames[id], value);
403}
404
405void RenderOptionsDialog::mouseDoubleClickEvent(QMouseEvent *event)
406{