summaryrefslogtreecommitdiffstats
path: root/demos/glhypnotizer
diff options
context:
space:
mode:
authorJason Barron <jason.barron@nokia.com>2011-06-01 08:50:56 (GMT)
committerJason Barron <jason.barron@nokia.com>2011-06-03 06:43:47 (GMT)
commit8339121e0942e3e3b81af551a47be7b4a347608c (patch)
treece476390a04e359efafcfdc84e5733aca5fcb65a /demos/glhypnotizer
parent43ce5bab32e0d28366317be99df5e6df70787826 (diff)
downloadQt-8339121e0942e3e3b81af551a47be7b4a347608c.zip
Qt-8339121e0942e3e3b81af551a47be7b4a347608c.tar.gz
Qt-8339121e0942e3e3b81af551a47be7b4a347608c.tar.bz2
Add the new 'glhypnotizer' demo.
Introduce a new demo to demonstrate the usage of OpenGL from a separate thread. Reviewed-by: Samuel
Diffstat (limited to 'demos/glhypnotizer')
-rw-r--r--demos/glhypnotizer/glhypnotizer.pro21
-rw-r--r--demos/glhypnotizer/hypnotizer.qrc6
-rw-r--r--demos/glhypnotizer/main.cpp315
-rw-r--r--demos/glhypnotizer/qt-logo.pngbin0 -> 2493 bytes
-rw-r--r--demos/glhypnotizer/spiral.svg100
5 files changed, 442 insertions, 0 deletions
diff --git a/demos/glhypnotizer/glhypnotizer.pro b/demos/glhypnotizer/glhypnotizer.pro
new file mode 100644
index 0000000..a7fdf5e
--- /dev/null
+++ b/demos/glhypnotizer/glhypnotizer.pro
@@ -0,0 +1,21 @@
+TEMPLATE = app
+CONFIG -= moc
+INCLUDEPATH += .
+
+# Input
+SOURCES += main.cpp
+QT += opengl svg
+RESOURCES = hypnotizer.qrc
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/glhypnotizer
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.png *.pro *.svg
+sources.path = $$[QT_INSTALL_DEMOS]/glhypnotizer
+INSTALLS += target sources
+
+symbian: include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri)
diff --git a/demos/glhypnotizer/hypnotizer.qrc b/demos/glhypnotizer/hypnotizer.qrc
new file mode 100644
index 0000000..97ba159
--- /dev/null
+++ b/demos/glhypnotizer/hypnotizer.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qt-logo.png</file>
+ <file>spiral.svg</file>
+</qresource>
+</RCC> \ No newline at end of file
diff --git a/demos/glhypnotizer/main.cpp b/demos/glhypnotizer/main.cpp
new file mode 100644
index 0000000..d6f3dc9
--- /dev/null
+++ b/demos/glhypnotizer/main.cpp
@@ -0,0 +1,315 @@
+#include <QtGui>
+#include <QtOpenGL>
+#include <QtSvg>
+
+#define NUM_SWIRLY_ITEMS 10
+
+class GLPainter : public QObject
+{
+ Q_OBJECT
+public:
+ GLPainter(QGLWidget *widget);
+ void stop();
+ void resizeViewport(const QSize &size);
+
+public slots:
+ void start();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+ void paint();
+ void initSwirlyItems();
+ void updateSwirlyItems();
+ void drawSuggestiveMessages(QPainter *p);
+
+private:
+ QMutex mutex;
+ QGLWidget *glWidget;
+ int viewportWidth;
+ int viewportHeight;
+ bool doRendering;
+ qreal rotationAngle;
+ bool swirlClockwise;
+ QSvgRenderer svgRenderer;
+ QPixmap logo;
+ QPainter::PixmapFragment swirlyItems[NUM_SWIRLY_ITEMS];
+ int swirlyCounter;
+ int textCounter;
+ int messageYPos;
+ qreal scaleFactor;
+};
+
+
+GLPainter::GLPainter(QGLWidget *widget)
+ : glWidget(widget)
+ , doRendering(true)
+ , rotationAngle(rand() % 360)
+ , swirlClockwise((rand() % 2) == 1)
+ , svgRenderer(QLatin1String(":/spiral.svg"), this)
+ , logo(QLatin1String(":/qt-logo.png"))
+{
+}
+
+void GLPainter::start()
+{
+ glWidget->makeCurrent();
+ startTimer(20);
+}
+
+void GLPainter::stop()
+{
+ QMutexLocker locker(&mutex);
+ doRendering = false;
+}
+
+void GLPainter::resizeViewport(const QSize &size)
+{
+ QMutexLocker locker(&mutex);
+ viewportWidth = size.width();
+ viewportHeight = size.height();
+ initSwirlyItems();
+ textCounter = 0;
+ messageYPos = -1;
+}
+
+void GLPainter::timerEvent(QTimerEvent *event)
+{
+ QMutexLocker locker(&mutex);
+ if (!doRendering) {
+ killTimer(event->timerId());
+ QThread::currentThread()->quit();
+ return;
+ }
+ updateSwirlyItems();
+ paint();
+}
+
+void GLPainter::paint()
+{
+ QPainter p(glWidget);
+ p.fillRect(QRect(0, 0, viewportWidth, viewportHeight), Qt::white);
+ p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ p.translate(viewportWidth / 2, viewportHeight / 2);
+ p.rotate(rotationAngle * (swirlClockwise ? 1 : -1));
+ p.scale(svgRenderer.viewBox().width() / 200.0 * 0.65,
+ svgRenderer.viewBox().height() / 200.0 * 0.65);
+ p.translate(-viewportWidth / 2, -viewportHeight / 2);
+ svgRenderer.render(&p);
+ p.resetTransform();
+ p.drawPixmapFragments(swirlyItems, NUM_SWIRLY_ITEMS, logo);
+ drawSuggestiveMessages(&p);
+ p.end();
+ rotationAngle += 1.2;
+}
+
+void GLPainter::drawSuggestiveMessages(QPainter *p)
+{
+ const int numSuggestiveMessages = 7;
+ const char *texts[numSuggestiveMessages] = {" You feel relaxed.. ",
+ " Let your mind wander.. ",
+ " Look deep into the swirls.. ",
+ " Even deeper.. ",
+ " Qt is good! ",
+ " Qt is good for you! ",
+ " You MUST use Qt! "};
+ QFont font(p->font());
+ font.setPointSizeF(font.pointSizeF() * viewportWidth/200.0);
+ p->setFont(font);
+ QFontMetrics fm(font);
+ int messageNo = textCounter/314;
+ if (messageNo > 6 || messageNo < 0) {
+ qFatal("This should not happen: %d - %d", messageNo, textCounter);
+ }
+ QLatin1String text(texts[textCounter / 314]);
+ qreal textWidth = fm.width(text);
+ int alpha = 255 * qAbs(qSin(textCounter * 0.01));
+ if (messageYPos < 0 || (textCounter % 314 == 0)) {
+ messageYPos = qBound(fm.height(), rand() % viewportHeight,
+ viewportHeight - fm.height());
+ }
+ p->setPen(QColor(255, 255, 255, alpha));
+ p->setBackground(QColor(50, 50, 50, qBound(0, alpha, 50)));
+ p->setBackgroundMode(Qt::OpaqueMode);
+ p->drawText((viewportWidth / 2) - (textWidth/ 2), messageYPos, text);
+ ++textCounter;
+ if (textCounter >= (314 * numSuggestiveMessages))
+ textCounter = 0;
+}
+
+void GLPainter::initSwirlyItems()
+{
+ swirlyCounter = swirlClockwise ? 0 : 360;
+ scaleFactor = viewportWidth / 200.0;
+ QRectF logoRect(0, 0, logo.width(), logo.height());
+
+ for (int i=0; i<NUM_SWIRLY_ITEMS; ++i) {
+ if (swirlClockwise) {
+ swirlyItems[i] = QPainter::PixmapFragment::create(QPointF(0, 0), logoRect,
+ scaleFactor,
+ scaleFactor);
+ } else {
+ swirlyItems[i] = QPainter::PixmapFragment::create(QPointF(0, 0), logoRect,
+ scaleFactor * 1 / 360.0,
+ scaleFactor * 1 / 360.0);
+ }
+ }
+}
+
+void GLPainter::updateSwirlyItems()
+{
+ swirlyCounter += swirlClockwise ? 1 : -1;
+
+ for (int i=0; i<NUM_SWIRLY_ITEMS; ++i) {
+ int factor;
+ factor = swirlClockwise ? (swirlyCounter - i * 20) : (swirlyCounter + i * 20);
+ if (factor > 0 && factor <= 360) {
+ swirlyItems[i].x = viewportWidth / 2.0 + qSin(factor * 0.05) * (viewportWidth / 2.0) * (100.0 / factor);
+ swirlyItems[i].y = viewportHeight / 2.0 + qCos(factor * 0.05) * (viewportHeight / 2.0) * (100.0 / factor);
+ swirlyItems[i].rotation += -swirlyCounter * 0.01;
+ swirlyItems[i].scaleX += swirlClockwise ? -scaleFactor * 1 / 360.0 : scaleFactor * 1 / 360.0;
+ if (swirlClockwise) {
+ if (swirlyItems[i].scaleX < 0)
+ swirlyItems[i].scaleX = scaleFactor;
+ } else {
+ if (swirlyItems[i].scaleX > scaleFactor)
+ swirlyItems[i].scaleX = scaleFactor * 1 / 360.0;
+ }
+ swirlyItems[i].scaleY = swirlyItems[i].scaleX;
+ } else {
+ swirlyItems[i].scaleX = swirlyItems[i].scaleY = 0;
+ }
+ }
+ if (swirlClockwise) {
+ if (swirlyCounter > (360 + NUM_SWIRLY_ITEMS * 20))
+ swirlyCounter = 0;
+ } else {
+ if (swirlyCounter < -NUM_SWIRLY_ITEMS * 20)
+ swirlyCounter = 360;
+ }
+}
+
+class GLWidget : public QGLWidget
+{
+public:
+ GLWidget(QWidget *parent, QGLWidget *shareWidget = 0);
+ ~GLWidget();
+ void startRendering();
+ void stopRendering();
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+ QSize sizeHint() const { return QSize(200, 200); }
+
+private:
+ GLPainter glPainter;
+ QThread glThread;
+};
+
+GLWidget::GLWidget(QWidget *parent, QGLWidget *share)
+ : QGLWidget(QGLFormat(QGL::SampleBuffers), parent, share)
+ , glPainter(this)
+ , glThread(this)
+{
+ setAttribute(Qt::WA_PaintOutsidePaintEvent);
+ setAttribute(Qt::WA_DeleteOnClose);
+}
+
+GLWidget::~GLWidget()
+{
+ stopRendering();
+}
+
+void GLWidget::startRendering()
+{
+ glPainter.moveToThread(&glThread);
+ connect(&glThread, SIGNAL(started()), &glPainter, SLOT(start()));
+ glThread.start();
+}
+
+void GLWidget::stopRendering()
+{
+ glPainter.stop();
+ glThread.wait();
+}
+
+void GLWidget::resizeEvent(QResizeEvent *event)
+{
+ glPainter.resizeViewport(event->size());
+}
+
+void GLWidget::paintEvent(QPaintEvent *)
+{
+ // Handled by GLPainter.
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow();
+
+private slots:
+ void newThread();
+ void killThread();
+
+private:
+ QMdiArea mdiArea;
+ QGLWidget shareWidget;
+};
+
+MainWindow::MainWindow()
+ : QMainWindow(0)
+ , mdiArea(this)
+ , shareWidget(this)
+{
+ setWindowTitle("Qt GL Hypnotizer");
+ QMenu *menu = menuBar()->addMenu("&Hypnotizers");
+ menu->addAction("&New hypnotizer thread", this, SLOT(newThread()), QKeySequence("Ctrl+N"));
+ menu->addAction("&End current hypnotizer thread", this, SLOT(killThread()), QKeySequence("Ctrl+K"));
+ menu->addSeparator();
+ menu->addAction("E&xit", qApp, SLOT(quit()), QKeySequence("Ctrl+Q"));
+
+ setCentralWidget(&mdiArea);
+ shareWidget.resize(1, 1);
+ newThread();
+}
+
+void MainWindow::newThread()
+{
+ static int windowCount = 1;
+ if (mdiArea.subWindowList().count() > 9)
+ return;
+ GLWidget *widget = new GLWidget(&mdiArea, &shareWidget);
+ mdiArea.addSubWindow(widget);
+ widget->setWindowTitle("Thread #" + QString::number(windowCount++));
+ widget->show();
+ widget->startRendering();
+}
+
+void MainWindow::killThread()
+{
+ delete mdiArea.activeSubWindow();
+}
+
+int main(int argc, char *argv[])
+{
+ // Make Xlib and GLX thread safe under X11
+ QApplication::setAttribute(Qt::AA_X11InitThreads);
+ QApplication application(argc, argv);
+
+ // Using QPainter to draw into QGLWidgets is only supported with GL 2.0
+ if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) ||
+ (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) {
+ QMessageBox::information(0, "Qt GL Hypnotizer",
+ "This system does not support OpenGL 2.0 or OpenGL ES 2.0, "
+ "which is required for this example to work.");
+ return 0;
+ }
+
+ MainWindow mainWindow;
+ mainWindow.show();
+ return application.exec();
+}
+
+#include "main.moc"
diff --git a/demos/glhypnotizer/qt-logo.png b/demos/glhypnotizer/qt-logo.png
new file mode 100644
index 0000000..eaea344
--- /dev/null
+++ b/demos/glhypnotizer/qt-logo.png
Binary files differ
diff --git a/demos/glhypnotizer/spiral.svg b/demos/glhypnotizer/spiral.svg
new file mode 100644
index 0000000..ff1f047
--- /dev/null
+++ b/demos/glhypnotizer/spiral.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="512"
+ height="512"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="spiral.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient5046">
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0"
+ id="stop5048" />
+ <stop
+ style="stop-color:#6c90da;stop-opacity:1;"
+ offset="1"
+ id="stop5050" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5046"
+ id="radialGradient5052"
+ cx="359.38702"
+ cy="438.07581"
+ fx="359.38702"
+ fy="438.07581"
+ r="304.44159"
+ gradientTransform="matrix(1,0,0,0.91551877,0,37.009184)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.99232897"
+ inkscape:cx="267.31099"
+ inkscape:cy="295.6491"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="963"
+ inkscape:window-height="1024"
+ inkscape:window-x="286"
+ inkscape:window-y="74"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-540.36218)">
+ <path
+ sodipodi:type="spiral"
+ style="fill:url(#radialGradient5052);fill-opacity:1;stroke:#000000;stroke-width:20.29999924;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2816"
+ sodipodi:cx="331.42856"
+ sodipodi:cy="463.79074"
+ sodipodi:expansion="1"
+ sodipodi:revolution="3"
+ sodipodi:radius="337.44537"
+ sodipodi:argument="-18.046196"
+ sodipodi:t0="0"
+ d="m 331.42856,463.79074 c 11.74672,12.17647 -10.61822,21.84178 -20.23809,19.52382 -26.06925,-6.28154 -29.6746,-39.8823 -18.80954,-59.99999 19.43502,-35.98584 68.28562,-39.36493 99.76189,-18.09528 46.19269,31.21408 49.35062,97.07722 17.381,139.5238 -42.61047,56.57461 -126.00702,59.46265 -179.2857,16.66673 -67.04578,-53.85429 -69.64012,-155.00279 -15.95246,-219.0476 65.02296,-77.56686 184.03573,-79.85552 258.80951,-15.23819 88.11831,76.14929 90.09472,213.09185 14.52392,298.57141 C 400.3696,724.38498 245.45564,726.04525 149.28577,639.50509 40.011453,541.17265 38.669765,368.25918 136.1904,261.40987 245.59381,141.54108 436.52669,140.5196 554.04752,249.02876 684.51792,369.4945 685.21808,578.4614 565.71435,706.64779"
+ transform="matrix(0.9291373,0,0,0.91940263,-79.040559,394.33975)" />
+ </g>
+</svg>