diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2010-02-26 10:54:01 +1000 |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2010-02-26 14:23:14 +1000 |
commit | 8a3b2bf5795fe62626f20062727ea1649994b110 (patch) | |
tree | afa9c117e1f5f5c53a1799c32f03d16f03c336d6 /examples | |
parent | e6ae07b804a2ca4dfe11504c9aa95507fcbd5f0d (diff) |
Bezier patch subdivision example.
Diffstat (limited to 'examples')
-rw-r--r-- | examples/opencl/bezierpatch/beziermainwindow.cpp | 73 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/beziermainwindow.h | 70 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/beziermainwindow.ui | 113 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/bezierpatch.cl | 74 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/bezierpatch.pro | 24 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/bezierpatch.qrc | 6 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/bezierwidget.cpp | 449 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/bezierwidget.h | 122 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/main.cpp | 51 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/qglcamera.cpp | 1025 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/qglcamera.h | 166 | ||||
-rw-r--r-- | examples/opencl/bezierpatch/qtlogo.png | bin | 0 -> 14201 bytes | |||
-rw-r--r-- | examples/opencl/opencl.pro | 2 |
13 files changed, 2174 insertions, 1 deletions
diff --git a/examples/opencl/bezierpatch/beziermainwindow.cpp b/examples/opencl/bezierpatch/beziermainwindow.cpp new file mode 100644 index 0000000..e6f1ee1 --- /dev/null +++ b/examples/opencl/bezierpatch/beziermainwindow.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "beziermainwindow.h" + +BezierMainWindow::BezierMainWindow(QWidget *parent) + : QWidget(parent) +{ + setupUi(this); + + useOpenCL->setChecked(true); + localWorkSize8x8->setChecked(true); + + connect(useOpenCL, SIGNAL(toggled(bool)), + bezierWidget, SLOT(setUseOpenCL(bool))); + connect(useOpenCL, SIGNAL(toggled(bool)), + localWorkSize, SLOT(setEnabled(bool))); + + connect(localWorkSizeDefault, SIGNAL(toggled(bool)), + this, SLOT(selectLocalWorkSizeDefault(bool))); + connect(localWorkSize1x1, SIGNAL(toggled(bool)), + this, SLOT(selectLocalWorkSize1x1(bool))); + connect(localWorkSize1x8, SIGNAL(toggled(bool)), + this, SLOT(selectLocalWorkSize1x8(bool))); + connect(localWorkSize8x1, SIGNAL(toggled(bool)), + this, SLOT(selectLocalWorkSize8x1(bool))); + connect(localWorkSize8x8, SIGNAL(toggled(bool)), + this, SLOT(selectLocalWorkSize8x8(bool))); + connect(localWorkSize16x16, SIGNAL(toggled(bool)), + this, SLOT(selectLocalWorkSize16x16(bool))); +} + +BezierMainWindow::~BezierMainWindow() +{ +} diff --git a/examples/opencl/bezierpatch/beziermainwindow.h b/examples/opencl/bezierpatch/beziermainwindow.h new file mode 100644 index 0000000..96ebe0d --- /dev/null +++ b/examples/opencl/bezierpatch/beziermainwindow.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BEZIERMAINWINDOW_H +#define BEZIERMAINWINDOW_H + +#include <QtGui/qwidget.h> +#include "ui_beziermainwindow.h" + +class BezierMainWindow : public QWidget, public Ui_BezierMainWindow +{ + Q_OBJECT +public: + BezierMainWindow(QWidget *parent = 0); + ~BezierMainWindow(); + +private slots: + void selectLocalWorkSizeDefault(bool checked) + { if (checked) bezierWidget->setLocalWorkSize(0, 0); } + void selectLocalWorkSize1x1(bool checked) + { if (checked) bezierWidget->setLocalWorkSize(1, 1); } + void selectLocalWorkSize1x8(bool checked) + { if (checked) bezierWidget->setLocalWorkSize(1, 8); } + void selectLocalWorkSize8x1(bool checked) + { if (checked) bezierWidget->setLocalWorkSize(8, 1); } + void selectLocalWorkSize8x8(bool checked) + { if (checked) bezierWidget->setLocalWorkSize(8, 8); } + void selectLocalWorkSize16x16(bool checked) + { if (checked) bezierWidget->setLocalWorkSize(16, 16); } +}; + +#endif diff --git a/examples/opencl/bezierpatch/beziermainwindow.ui b/examples/opencl/bezierpatch/beziermainwindow.ui new file mode 100644 index 0000000..fba7a3c --- /dev/null +++ b/examples/opencl/bezierpatch/beziermainwindow.ui @@ -0,0 +1,113 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BezierMainWindow</class> + <widget class="QWidget" name="BezierMainWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>619</width> + <height>405</height> + </rect> + </property> + <property name="windowTitle"> + <string>BezierMainWindow</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="BezierWidget" name="bezierWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QCheckBox" name="useOpenCL"> + <property name="text"> + <string>Use OpenCL</string> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="localWorkSize"> + <property name="title"> + <string>Local Work Size</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QRadioButton" name="localWorkSizeDefault"> + <property name="text"> + <string>Default</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="localWorkSize1x1"> + <property name="text"> + <string>1x1</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="localWorkSize1x8"> + <property name="text"> + <string>1x8</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="localWorkSize8x1"> + <property name="text"> + <string>8x1</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="localWorkSize8x8"> + <property name="text"> + <string>8x8</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="localWorkSize16x16"> + <property name="text"> + <string>16x16</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>BezierWidget</class> + <extends>QWidget</extends> + <header>bezierwidget.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/examples/opencl/bezierpatch/bezierpatch.cl b/examples/opencl/bezierpatch/bezierpatch.cl new file mode 100644 index 0000000..7bca1a6 --- /dev/null +++ b/examples/opencl/bezierpatch/bezierpatch.cl @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// Evaluate a Bezier patch at a (s, t) determined by the global work item. +__kernel void evaluateBezier + (__global __write_only float4 *positions, + __global __write_only float2 *texCoords, + float16 matrixX, float16 matrixY, float16 matrixZ, + int size) +{ + float s = ((float)(get_global_id(0))) / (size - 1); + float s2 = s * s; + float t = ((float)(get_global_id(1))) / (size - 1); + float t2 = t * t; + float4 S = (float4)(s2 * s, s2, s, 1); + float4 T = (float4)(t2 * t, t2, t, 1); + + // Calculate the position of the item at (s, t). + float4 smx = (float4)(dot(S, matrixX.lo.lo), + dot(S, matrixX.lo.hi), + dot(S, matrixX.hi.lo), + dot(S, matrixX.hi.hi)); + float4 smy = (float4)(dot(S, matrixY.lo.lo), + dot(S, matrixY.lo.hi), + dot(S, matrixY.hi.lo), + dot(S, matrixY.hi.hi)); + float4 smz = (float4)(dot(S, matrixZ.lo.lo), + dot(S, matrixZ.lo.hi), + dot(S, matrixZ.hi.lo), + dot(S, matrixZ.hi.hi)); + + // Output the results. + int offset = get_global_id(0) + get_global_id(1) * size; + positions[offset] = (float4)(dot(smx, T), dot(smy, T), dot(smz, T), 1); + texCoords[offset] = (float2)(s, t); +} diff --git a/examples/opencl/bezierpatch/bezierpatch.pro b/examples/opencl/bezierpatch/bezierpatch.pro new file mode 100644 index 0000000..ca56dae --- /dev/null +++ b/examples/opencl/bezierpatch/bezierpatch.pro @@ -0,0 +1,24 @@ +TEMPLATE = app +TARGET = bezierpatch +DEPENDPATH += . +INCLUDEPATH += . +QT += opengl + +VPATH += ../../../demos/mandelbrot +INCLUDEPATH += ../../../demos/mandelbrot + +# Input +SOURCES += main.cpp \ + beziermainwindow.cpp \ + bezierwidget.cpp \ + qglcamera.cpp \ + framerate.cpp +HEADERS += bezierwidget.h \ + beziermainwindow.h \ + qglcamera.h \ + framerate.h +RESOURCES += bezierpatch.qrc +FORMS += beziermainwindow.ui + +LIBS += -L../../../lib -L../../../bin +include(../../../src/opencl/opencl_dep.pri) diff --git a/examples/opencl/bezierpatch/bezierpatch.qrc b/examples/opencl/bezierpatch/bezierpatch.qrc new file mode 100644 index 0000000..a55ea7f --- /dev/null +++ b/examples/opencl/bezierpatch/bezierpatch.qrc @@ -0,0 +1,6 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>bezierpatch.cl</file> + <file>qtlogo.png</file> +</qresource> +</RCC> diff --git a/examples/opencl/bezierpatch/bezierwidget.cpp b/examples/opencl/bezierpatch/bezierwidget.cpp new file mode 100644 index 0000000..96a1d80 --- /dev/null +++ b/examples/opencl/bezierpatch/bezierwidget.cpp @@ -0,0 +1,449 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "bezierwidget.h" +#include <QtCore/qtimer.h> +#include <QtCore/qdatetime.h> +#include <QtGui/qpainter.h> +#if QT_VERSION >= 0x040700 +#define USE_VBOS 1 +#include <QtOpenGL/qglbuffer.h> +#endif + +/* + The Bezier patch equation is: + + x(s, t) = S . M . Gx . transpose(M) . transpose(T) + y(s, t) = S . M . Gy . transpose(M) . transpose(T) + z(s, t) = S . M . Gz . transpose(M) . transpose(T) + + where: + + S = [s^3 s^2 s 1] + T = [t^3 t^2 t 1] + M = |-1 3 -3 1| + | 3 -6 3 0] + |-3 3 0 0| + | 1 0 0 0| + Gx = | x11 x12 x13 x14 | i.e. x components of the control points + | x21 x22 x23 x24 | + | x31 x32 x33 x34 | + | x41 x42 x43 x44 | + Gy, Gz are similar + + Note: transpose(M) = M + + From "Computer Graphics: Principles and Practice", Foley, van Dam, + et al, Second Edition, Addison Wesley, 1996. +*/ + +BezierWidget::BezierWidget(QWidget *parent) + : QGLWidget(parent) + , useOpenCL(true) + , matrixM(-1, 3, -3, 1, + 3, -6, 3, 0, + -3, 3, 0, 0, + 1, 0, 0, 0) + , positions(0) + , texCoords(0) + , indices(0) + , numVertices(0) + , numIndices(0) +#ifdef QT_OPENGL_ES + // We need a value that is a multiple of 16, but less than + // sqrt(65535 / 6) = 104.5 because we cannot use more than + // 65535 indices under OpenGL/ES. + , subdivisionSize(96) +#else + , subdivisionSize(512) +#endif + , lastSubdivisionSize(-1) + , textureId(0) + , vertexBuffer(0) + , indexBuffer(0) +{ + setAutoFillBackground(false); + + // Patch is in the X-Z plane from x = 0, z = 0, to x = 3, z = 3. + // The height of the patch at each control point is adjusted in Y. + cp[0] = QVector3D(0, 0, 0); + cp[1] = QVector3D(1, 1, 0); + cp[2] = QVector3D(2, -1, 0); + cp[3] = QVector3D(3, 0, 0); + cp[4] = QVector3D(0, 0, 1); + cp[5] = QVector3D(1, 1, 1); + cp[6] = QVector3D(2, -1, 1); + cp[7] = QVector3D(3, 0, 1); + cp[8] = QVector3D(0, 0, 2); + cp[9] = QVector3D(1, 1, 2); + cp[10] = QVector3D(2, -1, 2); + cp[11] = QVector3D(3, 0, 2); + cp[12] = QVector3D(0, 0, 3); + cp[13] = QVector3D(1, 1, 3); + cp[14] = QVector3D(2, -1, 3); + cp[15] = QVector3D(3, 0, 3); + + camera.setCenter(QVector3D(1.5f, 0.0f, 1.5f)); + camera.setEye(QVector3D(-6.0f, 5.0f, 6.0f)); + + if (!context.create()) + qFatal("Could not create OpenCL context"); + + program = context.buildProgramFromSourceFile(QLatin1String(":/bezierpatch.cl")); + evaluateBezier = program.createKernel("evaluateBezier"); + evaluateBezier.setLocalWorkSize(8, 8); + + QTimer *timer = new QTimer(this); + connect(timer, SIGNAL(timeout()), this, SLOT(animate())); + timer->start(0); + + qsrand(QDateTime::currentDateTime().toTime_t()); +} + +BezierWidget::~BezierWidget() +{ +} + +void BezierWidget::resizeGL(int width, int height) +{ + glViewport(0, 0, width, height); +} + +void BezierWidget::initializeGL() +{ + glEnable(GL_DEPTH_TEST); + + textureImage = QImage(QLatin1String(":/qtlogo.png")); + textureId = bindTexture(textureImage); +} + +#if !defined(QT_OPENGL_ES_2) + +static void setGLMatrix(GLenum type, const QMatrix4x4& m) +{ + glMatrixMode(type); + if (sizeof(qreal) == sizeof(GLfloat)) { + glLoadMatrixf(reinterpret_cast<const GLfloat *>(m.constData())); + } else { + GLfloat mat[16]; + const qreal *data = m.constData(); + for (int index = 0; index < 16; ++index) + mat[index] = data[index]; + glLoadMatrixf(mat); + } +} + +#endif + +void BezierWidget::paintGL() +{ +#if !defined(QT_OPENGL_ES_2) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + if (useOpenCL) + computeVerticesCL(); + else + computeVerticesNative(); + + QMatrix4x4 proj = camera.projectionMatrix(qreal(width()) / height()); + QMatrix4x4 mv = camera.modelViewMatrix(); + + setGLMatrix(GL_PROJECTION, proj); + setGLMatrix(GL_MODELVIEW, mv); + +#ifdef USE_VBOS + if (vertexBuffer) { + vertexBuffer->bind(); + glVertexPointer(4, GL_FLOAT, 0, 0); + glTexCoordPointer(2, GL_FLOAT, 0, (void *)(sizeof(GLfloat) * 4 * numVertices)); + vertexBuffer->release(); + } else { + glVertexPointer(4, GL_FLOAT, 0, positions); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + } +#else + glVertexPointer(4, GL_FLOAT, 0, positions); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); +#endif + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + + glBindTexture(GL_TEXTURE_2D, textureId); + glEnable(GL_TEXTURE_2D); + +#ifdef USE_VBOS + if (indexBuffer) { + indexBuffer->bind(); + glDrawElements(GL_TRIANGLES, numIndices, IndexTypeEnum, 0); + indexBuffer->release(); + } else { + glDrawElements(GL_TRIANGLES, numIndices, IndexTypeEnum, indices); + } +#else + glDrawElements(GL_TRIANGLES, numIndices, IndexTypeEnum, indices); +#endif + + glDisable(GL_TEXTURE_2D); +#endif + + qreal fps = frameRate.fps(); + if (fps > 0.0f) { + QPainter painter(this); + QString str = QString::number(numIndices / 3) + QLatin1String(" triangles, "); + str += QString::number(fps) + QLatin1String(" fps"); + painter.setPen(Qt::white); + painter.drawText(rect(), str); + } +} + +void BezierWidget::setUseOpenCL(bool value) +{ + useOpenCL = value; + frameRate.start(); +} + +void BezierWidget::setLocalWorkSize(int x, int y) +{ + evaluateBezier.setLocalWorkSize(x, y); + frameRate.start(); +} + +static inline qreal clamp(qreal value, qreal lower, qreal upper) +{ + if (value < lower) + return lower; + else if (value > upper) + return upper; + else + return value; +} + +void BezierWidget::animate() +{ + // Move several of the non-corner control points up or down. + static int mapPoints[12] = {1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14}; + for (int move = 0; move < 4; ++move) { + int index = mapPoints[qrand() % 12]; + qreal amt = (qrand() & 1) ? 0.2f : -0.2f; + qreal y = clamp(cp[index].y() + amt, -3.0f, 3.0f); + cp[index].setY(y); + } + frameRate.newFrame(); + updateGL(); +} + +void BezierWidget::computeMatrices() +{ + QMatrix4x4 xm(cp[0].x(), cp[1].x(), cp[2].x(), cp[3].x(), + cp[4].x(), cp[5].x(), cp[6].x(), cp[7].x(), + cp[8].x(), cp[9].x(), cp[10].x(), cp[11].x(), + cp[12].x(), cp[13].x(), cp[14].x(), cp[15].x()); + QMatrix4x4 ym(cp[0].y(), cp[1].y(), cp[2].y(), cp[3].y(), + cp[4].y(), cp[5].y(), cp[6].y(), cp[7].y(), + cp[8].y(), cp[9].y(), cp[10].y(), cp[11].y(), + cp[12].y(), cp[13].y(), cp[14].y(), cp[15].y()); + QMatrix4x4 zm(cp[0].z(), cp[1].z(), cp[2].z(), cp[3].z(), + cp[4].z(), cp[5].z(), cp[6].z(), cp[7].z(), + cp[8].z(), cp[9].z(), cp[10].z(), cp[11].z(), + cp[12].z(), cp[13].z(), cp[14].z(), cp[15].z()); + + matrixX = matrixM * xm * matrixM; + matrixY = matrixM * ym * matrixM; + matrixZ = matrixM * zm * matrixM; +} + +void BezierWidget::computeVerticesNative() +{ + computeMatrices(); + allocVertices(); + +#ifdef USE_VBOS + QVector4D *posns; + QVector2D *texcs; + if (vertexBuffer) { + vertexBuffer->bind(); + void *mapped = vertexBuffer->map(QGLBuffer::WriteOnly); + posns = (QVector4D *)mapped; + texcs = (QVector2D *)(((uchar *)mapped) + + numVertices * sizeof(GLfloat) * 4); + } else { + posns = positions; + texcs = texCoords; + } +#else + posns = positions; + texcs = texCoords; +#endif + + for (int sint = 0; sint < subdivisionSize; ++sint) { + qreal s = qreal(sint) / (subdivisionSize - 1); + QVector4D svec = QVector4D(s * s * s, s * s, s, 1); + for (int tint = 0; tint < subdivisionSize; ++tint) { + qreal t = qreal(tint) / (subdivisionSize - 1); + QVector4D tvec = QVector4D(t * t * t, t * t, t, 1); + qreal x = QVector4D::dotProduct(svec * matrixX, tvec); + qreal y = QVector4D::dotProduct(svec * matrixY, tvec); + qreal z = QVector4D::dotProduct(svec * matrixZ, tvec); + int offset = sint + tint * subdivisionSize; + posns[offset] = QVector4D(x, y, z, 1); + texcs[offset] = QVector2D(s, t); + } + } + +#ifdef USE_VBOS + if (vertexBuffer) { + vertexBuffer->unmap(); + vertexBuffer->release(); + } +#endif +} + +void BezierWidget::computeVerticesCL() +{ + computeMatrices(); + allocVertices(); + + evaluateBezier.setGlobalWorkSize(subdivisionSize, subdivisionSize); + evaluateBezier(positionBuffer, texCoordBuffer, + matrixX, matrixY, matrixZ, subdivisionSize); + +#ifdef USE_VBOS + if (vertexBuffer) { + // Read the results directly into the vertex buffer. + vertexBuffer->bind(); + GLfloat *mapped = (GLfloat *)vertexBuffer->map(QGLBuffer::WriteOnly); + GLfloat *posns = mapped; + GLfloat *texcs = mapped + numVertices * 4; + positionBuffer.read(posns, numVertices * sizeof(GLfloat) * 4); + texCoordBuffer.read(texcs, numVertices * sizeof(GLfloat) * 2); + vertexBuffer->unmap(); + vertexBuffer->release(); + } else { + positionBuffer.read(positions, numVertices * sizeof(GLfloat) * 4); + texCoordBuffer.read(texCoords, numVertices * sizeof(GLfloat) * 2); + } +#else + positionBuffer.read(positions, numVertices * sizeof(GLfloat) * 4); + texCoordBuffer.read(texCoords, numVertices * sizeof(GLfloat) * 2); +#endif +} + +void BezierWidget::allocVertices() +{ + if (subdivisionSize == lastSubdivisionSize) + return; + lastSubdivisionSize = subdivisionSize; + + // Expand the vertex and index arrays. + int num = subdivisionSize * subdivisionSize; + if (num > numVertices) { + positions = (QVector4D *)qRealloc(positions, num * sizeof(GLfloat) * 4); + texCoords = (QVector2D *)qRealloc(texCoords, num * sizeof(GLfloat) * 2); + + int maxIndices = num * 6; + indices = (IndexType *)qRealloc(indices, maxIndices * sizeof(IndexType)); + } + numVertices = num; +#ifdef USE_VBOS + // Create a vertex buffer in the server. + if (!vertexBuffer) { + vertexBuffer = new QGLBuffer(QGLBuffer::VertexBuffer); + vertexBuffer->setUsagePattern(QGLBuffer::DynamicDraw); + if (!vertexBuffer->create()) { + delete vertexBuffer; + vertexBuffer = 0; + } + } + if (vertexBuffer) { + vertexBuffer->bind(); + vertexBuffer->allocate(sizeof(GLfloat) * 6 * num); + if (!vertexBuffer->map(QGLBuffer::WriteOnly)) { + // No point using a vertex buffer if we cannot map it. + vertexBuffer->unmap(); + vertexBuffer->release(); + delete vertexBuffer; + vertexBuffer = 0; + } else { + vertexBuffer->unmap(); + vertexBuffer->release(); + } + } +#endif + + // Generate a new index array for drawing the triangles. + numIndices = 0; + for (int sint = 0; sint < (subdivisionSize - 1); ++sint) { + for (int tint = 0; tint < (subdivisionSize - 1); ++tint) { + int corner1 = sint + tint * subdivisionSize; + int corner2 = sint + (tint + 1) * subdivisionSize; + int corner3 = (sint + 1) + (tint + 1) * subdivisionSize; + int corner4 = (sint + 1) + tint * subdivisionSize; + indices[numIndices++] = corner1; + indices[numIndices++] = corner2; + indices[numIndices++] = corner3; + indices[numIndices++] = corner1; + indices[numIndices++] = corner3; + indices[numIndices++] = corner4; + } + } +#ifdef USE_VBOS + // Upload the indices into a server-side buffer. + if (!indexBuffer) { + indexBuffer = new QGLBuffer(QGLBuffer::IndexBuffer); + if (!indexBuffer->create()) { + delete indexBuffer; + indexBuffer = 0; + } + } + if (indexBuffer) { + indexBuffer->bind(); + indexBuffer->allocate(indices, sizeof(IndexType) * numIndices); + indexBuffer->release(); + } +#endif + + // Allocate OpenCL buffers of the right size. + positionBuffer = context.createBufferDevice + (num * sizeof(GLfloat) * 4, QCL::WriteOnly); + texCoordBuffer = context.createBufferDevice + (num * sizeof(GLfloat) * 2, QCL::WriteOnly); +} diff --git a/examples/opencl/bezierpatch/bezierwidget.h b/examples/opencl/bezierpatch/bezierwidget.h new file mode 100644 index 0000000..e8836dc --- /dev/null +++ b/examples/opencl/bezierpatch/bezierwidget.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef BEZIERWIDGET_H +#define BEZIERWIDGET_H + +#include <QtOpenGL/qgl.h> +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qvector2d.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qvector4d.h> +#include "qclcontext.h" +#include "qglcamera.h" +#include "framerate.h" + +class QGLBuffer; + +class BezierWidget : public QGLWidget +{ + Q_OBJECT +public: + BezierWidget(QWidget *parent = 0); + ~BezierWidget(); + +protected: + void resizeGL(int width, int height); + void initializeGL(); + void paintGL(); + +public slots: + void setUseOpenCL(bool value); + void setLocalWorkSize(int x, int y); + +private slots: + void animate(); + +private: + bool useOpenCL; + + QCLContext context; + + QCLProgram program; + QCLKernel evaluateBezier; + QCLBuffer positionBuffer; + QCLBuffer texCoordBuffer; + + QGLCamera camera; + FrameRate frameRate; + + QMatrix4x4 matrixM; + QMatrix4x4 matrixX; + QMatrix4x4 matrixY; + QMatrix4x4 matrixZ; + QVector3D cp[16]; + + QVector4D *positions; + QVector2D *texCoords; +#ifdef QT_OPENGL_ES + typedef ushort IndexType; + static const GLenum IndexTypeEnum = GL_UNSIGNED_SHORT; +#else + typedef uint IndexType; + static const GLenum IndexTypeEnum = GL_UNSIGNED_INT; +#endif + IndexType *indices; + int numVertices; + int numIndices; + int subdivisionSize; + int lastSubdivisionSize; + + QImage textureImage; + GLuint textureId; + + QGLBuffer *vertexBuffer; + QGLBuffer *indexBuffer; + + void computeMatrices(); + void computeVerticesNative(); + void computeVerticesCL(); + + void allocVertices(); +}; + +#endif diff --git a/examples/opencl/bezierpatch/main.cpp b/examples/opencl/bezierpatch/main.cpp new file mode 100644 index 0000000..46d2a40 --- /dev/null +++ b/examples/opencl/bezierpatch/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include "beziermainwindow.h" + +int main(int argc, char *argv[]) +{ + QApplication app(argc, argv); + BezierMainWindow w; + w.show(); + return app.exec(); +} diff --git a/examples/opencl/bezierpatch/qglcamera.cpp b/examples/opencl/bezierpatch/qglcamera.cpp new file mode 100644 index 0000000..ddadeb0 --- /dev/null +++ b/examples/opencl/bezierpatch/qglcamera.cpp @@ -0,0 +1,1025 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qglcamera.h" +#include <QtGui/qquaternion.h> +#include <QtCore/qmath.h> + +QT_BEGIN_NAMESPACE + +/*! + \class QGLCamera + \brief The QGLCamera class defines the projection to apply to simulate a camera's position, orientation, and optics. + \since 4.7 + \ingroup qt3d + \ingroup qt3d::viewing + + \section1 Modelview and projection transformations + + A QGLCamera instance is applied to the scene in two phases: + modelview transformation and projection transformation. + + During the modelview transformation, the eye(), center(), and + upVector() are used to generate a 4x4 transformation matrix that + reflects the viewer's current position and orientation. + + During the projection transformation, the projectionType(), + nearPlane(), farPlane(), fieldOfView(), and viewSize() are used + to define a viewing volume as a 4x4 transformation matrix. + + The modelview transformation matrix is returned by modelViewMatrix(). + The projection transformation matrix is returned by projectionMatrix(). + + \section1 Positioning and orienting the view + + The viewer position and orientation are defined by eye(), center(), + and upVector(). The location of the viewer in world co-ordinates is + given by eye(), the viewer is looking at the object of interest located + at center(), and the upVector() specifies the direction that should + be considered "up" with respect to the viewer. + + The vector from the eye() to the center() is called the "view vector", + and the cross-product of the view vector and upVector() is called + the "side vector". The view vector specifies the direction the + viewer is looking, and the side vector points off to the right of + the viewer. + + It is recommended that the view vector and upVector() be at right angles + to each other, but this is not required as long as the angle between + them is close to 90 degrees. + + The most common use of view and up vectors that are not at right angles + is to simulate a human eye at a specific height above the ground looking + down at a lower object or up at a higher object. In this case, the + the view vector will not be true horizontal, but the upVector() indicating + the human's upright stance will be true vertical. + + \section1 Zooming the camera image + + There are two ways to zoom the image seen through the camera: either + the camera eye() position can be moved closer to the object of interest, + or the field of view of the camera lens can be changed to make it appear + as though the object is moving closer. + + Changing the eye() position changes the lighting calculation in the + scene because the viewer is in a different position, changing the + angle of light reflection on the object's surface. + + The setFieldOfView() function can be used to simulate the effect of a + camera lens. The smaller the fieldOfView(), the closer the object + will appear. The lighting calculation will be the same as for the + unzoomed scene. + + If fieldOfView() is zero, then a standard perspective frustum of + viewSize() is used to define the viewing volume. The viewSize() + can be adjusted with setViewSize() to zoom the view. A smaller + viewSize() will make the the object appear closer. + + The fieldOfView() or viewSize() is applied as part of the + projectionMatrix(). + + \section1 Rotating the viewer or object of interest + + Rotating a viewer in 3D space is a very delicate process. It is very + easy to construct the rotation incorrectly and end up in a "gimbal lock" + state where further rotations are impossible in certain directions. + + To help alleviate this problem, QGLCamera uses a quaternion-based + approach to generate rotations. A quaternion is a compact representation + of a rotation in 3D space. Rotations can be combined through quaternion + multiplication. More information on quaternions can be found in the + documentation for QQuaternion. + + Before rotating the view, you should first decide the type + of rotation you want to perform: + + \list + \i Tilting or panning a fixed eye to reveal the scene in different + directions and orientations. This is equivalent to mounting a camera + on a fixed tripod and then adjusting the direction of view and + orientation with the tripod controls. + \i Rotating a moving viewer about the object of interest. This is + equivalent to moving the viewer around the object at a fixed distance, + but with the viewer always pointing at the object. + \endlist + + In the QGLCamera class, the first type of rotation is performed with + rotateEye() and the second with rotateCenter(). Each of these functions + take a quaternion argument that defines the type of rotation to perform. + + The tilt(), pan(), and roll() functions return values that can help with + constructing the rotation quaternions to pass to rotateEye() and + rotateCenter(). Tilt and pan are also known as "pitch" and "yaw" in + flight dynamics. + + Three axes of rotation are used to compute the quaternions. The tilt() + quaternion is computed with respect to the side vector, the pan() + quaterion is computed with respect to the upVector(), and the roll() + quaternion is computed with respect to the view vector. + + The following example tilts the direction the eye() is pointing + by 5 degrees, and then pans by 45 degrees: + + \code + camera.rotateEye(camera.tilt(5)); + camera.rotateEye(camera.pan(45)); + \endcode + + The next example performs the two rotations in a single fluid step + (note that the rotation to be performed first is multiplied last): + + \code + camera.rotateEye(camera.pan(45) * camera.tilt(5)); + \endcode + + These two examples will not produce the same visual result, even though + it looks like they might. In the first example, the upVector() is tilted + before the pan() quaternion is computed. In the second example, the pan() + quaternion is computed using the original upVector(). + + This difference in behavior is useful in different situations. Some + applications may wish to perform all rotations relative to the original + viewer orientation, and other applications may wish to perform rotations + relative to the current viewer orientation. These application types + correspond to the second and first examples above. + + \section1 Moving the viewer or object of interest + + The simplest way to move the viewer or object of interest is to call + setEye() or setCenter() respectively and supply a new position in + world co-ordinates. However, this can lead to non-intuitive movements + if the viewer orientation is not aligned with the world co-ordinate axes. + + For example, subtracting 3 from the eye() x co-ordinate will appear to + move the eye left 3 units if the viewer orientation is aligned with the + world co-ordinate axes. But it will not appear to move the eye left 3 + units in any other orientation. + + The translation() function can be used to construct a translation + vector that is aligned with the viewer's current orientation. + Movement in the x direction will move along the side vector, movement in + the y direction will move along upVector(), and movement in the z + direction will move along the view vector. + + The translation() function is useful when implementing operations such + as "step left", "jump up", and so on where the movement should be + interpreted relative to the viewer's current orientation, not the + world co-ordinate axes, + + In other words, the following two lines of code are not equivalent + unless the view is oriented with the world co-ordinate axes: + + \code + camera.translateEye(camera.translation(x, y, z)); + + camera.translateEye(QVector3D(x, y, z)); + \endcode + + The following example translates the eye() position while + keeping the object of interest at the original center(): + + \code + camera.translateEye(camera.translation(x, y, z)); + \endcode + + The following example translates the object of interest at + center() while keeping the eye() position fixed: + + \code + camera.translateCenter(camera.translation(x, y, z)); + \endcode + + The following example translates both the eye() and the center() + by the same amount, which will maintain the original view vector. + + \code + QVector3D vector = camera.translation(x, y, z); + camera.translateEye(vector); + camera.translateCenter(vector); + \endcode + + It is important that the translation vector for center() be computed + before eye() is translated if both eye() and center() must move by the + same amount. The following code translates center() in the viewer + orientation after the eye() is translated: + + \code + camera.translateEye(camera.translation(x, y, z)); + camera.translateCenter(camera.translation(x, y, z)); + \endcode + + Translating both eye() and center() by the same amount can be used + to simulate sliding a viewer past a scene while always looking in the + same direction (for example, filming a scene from a moving vehicle). + An alternative is to fix the viewer and move the scene itself: + the negation of the translation() vector can be applied to the + scene's modelview transformation. + + \section1 Motion tracking + + Viewing of 3D scenes can be enhanced if there is some way to track + the motion of the viewer or the orientation of the display device. + + Applications can use setMotionAdjustment() to alter the position + of the camera to account for the viewer's motion. This indicates + the viewer's position relative to the center of the screen. + The motionAdjustment() vector is used to determine by how much + the camera position should be adjusted. The distance of the viewer + from the screen is ignored. + + On handheld devices that use accelerometers to determine the + orientation of the device, the down vector due to gravity + can be adjusted to serve as a motion tracking vector. + + The output of motion tracking hardware can be very noisy, + with minor fluctuations due to viewer twitch movements or + environmental factors. The application is responsible for + cleaning up the signal and removing these fluctuations before + setMotionAdjustment() is called. +*/ + +class QGLCameraPrivate +{ +public: + QGLCameraPrivate(); + + QGLCamera::ProjectionType projectionType; + qreal fieldOfView; + qreal nearPlane; + qreal farPlane; + QSizeF viewSize; + QSizeF minViewSize; + int screenRotation; + QVector3D eye; + QVector3D upVector; + QVector3D center; + QVector3D viewVector; + qreal eyeSeparation; + QVector3D motionAdjustment; + QQuaternion motionQuaternion; +}; + +QGLCameraPrivate::QGLCameraPrivate() + : projectionType(QGLCamera::Perspective), + fieldOfView(0.0f), + nearPlane(5.0f), + farPlane(1000.0f), + viewSize(2.0f, 2.0f), + minViewSize(0.0001f, 0.0001f), + screenRotation(0), + eye(0.0f, 0.0f, 10.0f), + upVector(0.0f, 1.0f, 0.0f), + center(0.0f, 0.0f, 0.0f), + viewVector(0.0f, 0.0f, -10.0f), + eyeSeparation(0.0f), + motionAdjustment(0.0f, 0.0f, 1.0f) +{ +} + +/*! + Constructs a QGLCamera with the default properties and + attaches it to \a parent. +*/ +QGLCamera::QGLCamera(QObject *parent) + : QObject(parent), d_ptr(new QGLCameraPrivate) +{ +} + +/*! + Destroys this QGLCamera object. +*/ +QGLCamera::~QGLCamera() +{ + delete d_ptr; +} + +/*! + \enum QGLCamera::ProjectionType + This enum defines the type of view projection to use for a QGLCamera. + + \value Perspective Use a perspective view. + \value Orthographic Use an ortographic view. +*/ + +/*! + \property QGLCamera::projectionType + \brief the projection type for this camera. The default is Perspective. +*/ +QGLCamera::ProjectionType QGLCamera::projectionType() const +{ + Q_D(const QGLCamera); + return d->projectionType; +} + +void QGLCamera::setProjectionType(QGLCamera::ProjectionType value) +{ + Q_D(QGLCamera); + if (d->projectionType != value) { + d->projectionType = value; + emit projectionChanged(); + } +} + +/*! + \property QGLCamera::fieldOfView + \brief the field of view in degrees for a perspective projection. + + The default value is zero, which indicates a standard perspective + frustum view volume of viewSize() in size. If the value is not + zero, then viewSize() is ignored. + + This value is ignored if projectionType() is Orthographic. + + \sa viewSize() +*/ +qreal QGLCamera::fieldOfView() const +{ + Q_D(const QGLCamera); + return d->fieldOfView; +} + +void QGLCamera::setFieldOfView(qreal angle) +{ + Q_D(QGLCamera); + if (d->fieldOfView != angle) { + d->fieldOfView = angle; + emit projectionChanged(); + } +} + +/*! + \property QGLCamera::nearPlane + \brief the distance from the eye to the near clipping plane. + The default value is 5. + + \sa farPlane() +*/ +qreal QGLCamera::nearPlane() const +{ + Q_D(const QGLCamera); + return d->nearPlane; +} + +void QGLCamera::setNearPlane(qreal value) +{ + Q_D(QGLCamera); + if (d->nearPlane != value) { + d->nearPlane = value; + emit projectionChanged(); + } +} + +/*! + \property QGLCamera::farPlane + \brief the distance from the eye to the far clipping plane. + The default value is 1000. + + \sa nearPlane() +*/ +qreal QGLCamera::farPlane() const +{ + Q_D(const QGLCamera); + return d->farPlane; +} + +void QGLCamera::setFarPlane(qreal value) +{ + Q_D(QGLCamera); + if (d->farPlane != value) { + d->farPlane = value; + emit projectionChanged(); + } +} + +/*! + \property QGLCamera::viewSize + \brief the size of the front of the projection viewing volume. + The viewing volume is assumed to be centered on the origin. + + The default value is (2, 2), which indicates a viewing volume front + from (-1, -1) to (1, 1). + + If the width or height of the viewing volume is negative, then the + co-ordinates will be swapped. For example, a size of (2, -2) will + flip the vertical axis upside down for a viewing volume from + (-1, 1) to (1, -1). + + The view size will be further adjusted by the window's aspect ratio + when projectionMatrix() is called. For best results, the width and + height of the view size should be the same to define an ideal square + viewing volume, which is then extended to the final viewing volume + width and height based on the window's aspect ratio. + + \sa projectionMatrix(), minViewSize() +*/ +QSizeF QGLCamera::viewSize() const +{ + Q_D(const QGLCamera); + return d->viewSize; +} + +void QGLCamera::setViewSize(const QSizeF& size) +{ + Q_D(QGLCamera); + QSizeF sz(size); + if (sz.width() < d->minViewSize.width()) + sz.setWidth(d->minViewSize.width()); + if (sz.height() < d->minViewSize.height()) + sz.setHeight(d->minViewSize.height()); + if (d->viewSize != sz) { + d->viewSize = sz; + emit projectionChanged(); + } +} + +/*! + \property QGLCamera::minViewSize + \brief the minimum size of the front of the projection viewing volume. + + The minimum view size is used to clamp viewSize() when zooming + the camera closer to an object to prevent it "passing through" + the object and causing the scale factor to become infinite. + + The default value is (0.0001, 0.0001). + + \sa projectionMatrix(), viewSize() +*/ +QSizeF QGLCamera::minViewSize() const +{ + Q_D(const QGLCamera); + return d->minViewSize; +} + +void QGLCamera::setMinViewSize(const QSizeF& size) +{ + Q_D(QGLCamera); + if (d->viewSize != size) { + d->viewSize = size; + emit projectionChanged(); + } +} + +/*! + \property QGLCamera::screenRotation + \brief the screen rotation angle in degrees. The default + value is 0. If this value is 90 or 270, then the view + will be flipped width for height. The only supported values + are 0, 90, 180, and 270. The screen is rotated around the + positive z axis. + + This setting is intended for simple screen rotations on handheld + devices that can be held in either portrait or landscape orientations. + The entire screen image is rotated so that it can be viewed in a + different device orientation. + + Use rotateEye() or rotateCenter() for more complex rotations + that are not aligned with 0, 90, 180, or 270 degrees. +*/ +int QGLCamera::screenRotation() const +{ + Q_D(const QGLCamera); + return d->screenRotation; +} + +void QGLCamera::setScreenRotation(int angle) +{ + Q_D(QGLCamera); + if (d->screenRotation != angle) { + d->screenRotation = angle; + emit projectionChanged(); + } +} + +/*! + \property QGLCamera::xEye + \brief the x position of the viewer's eye. The default value is 0. + + \sa eye(), translateEye(), upVector(), center(), eyeSeparation() + \sa motionAdjustment() +*/ +qreal QGLCamera::xEye() const +{ + Q_D(QGLCamera); + return d->eye.x(); +} + +void QGLCamera::setXEye(qreal value) +{ + Q_D(QGLCamera); + d->eye.setX(value); + emit viewChanged(); +} + +/*! + \property QGLCamera::yEye + \brief the y position of the viewer's eye. The default value is 0. + + \sa eye(), translateEye(), upVector(), center(), eyeSeparation() + \sa motionAdjustment() +*/ +qreal QGLCamera::yEye() const +{ + Q_D(QGLCamera); + return d->eye.y(); +} + +void QGLCamera::setYEye(qreal value) +{ + Q_D(QGLCamera); + d->eye.setY(value); + emit viewChanged(); +} + +/*! + \property QGLCamera::zEye + \brief the z position of the viewer's eye. The default value is 10. + + \sa eye(), translateEye(), upVector(), center(), eyeSeparation() + \sa motionAdjustment() +*/ +qreal QGLCamera::zEye() const +{ + Q_D(QGLCamera); + return d->eye.z(); +} + +void QGLCamera::setZEye(qreal value) +{ + Q_D(QGLCamera); + d->eye.setZ(value); + emit viewChanged(); +} + +/*! + \property QGLCamera::eye + \brief the position of the viewer's eye. The default value is (0, 0, 10). + + \sa translateEye(), upVector(), center(), eyeSeparation() + \sa motionAdjustment() +*/ +QVector3D QGLCamera::eye() const +{ + Q_D(const QGLCamera); + return d->eye; +} + +void QGLCamera::setEye(const QVector3D& vertex) +{ + Q_D(QGLCamera); + if (d->eye != vertex) { + d->eye = vertex; + d->viewVector = d->center - d->eye; + emit viewChanged(); + } +} + +/*! + Adjusts the position of the viewer's eye by the components of \a vector. + The final position is eye() + \a vector. + + \sa eye(), setEye(), translateCenter() +*/ +void QGLCamera::translateEye(const QVector3D& vector) +{ + Q_D(QGLCamera); + d->eye += vector; + d->viewVector = d->center - d->eye; + emit viewChanged(); +} + +/*! + \property QGLCamera::upVector + \brief the up vector for the viewer. The default value is (0, 1, 0). + + \sa eye(), center() +*/ +QVector3D QGLCamera::upVector() const +{ + Q_D(const QGLCamera); + return d->upVector; +} + +void QGLCamera::setUpVector(const QVector3D& vector) +{ + Q_D(QGLCamera); + if (d->upVector != vector) { + d->upVector = vector; + emit viewChanged(); + } +} + +/*! + \property QGLCamera::xCentre + \brief the x position of the center of the view visible from the viewer's + position. The default value is 0. + + \sa eye(), translateEye(), upVector(), center(), eyeSeparation() + \sa motionAdjustment() +*/ +qreal QGLCamera::xCentre() const +{ + Q_D(QGLCamera); + return d->center.x(); +} + +void QGLCamera::setXCentre(qreal value) +{ + Q_D(QGLCamera); + d->center.setX(value); + emit viewChanged(); +} + +/*! + \property QGLCamera::yCentre + \brief the y position of the center of the view visible from the + viewer's position. The default value is 0. + + \sa eye(), translateEye(), upVector(), center(), eyeSeparation() + \sa motionAdjustment() +*/ +qreal QGLCamera::yCentre() const +{ + Q_D(QGLCamera); + return d->center.y(); +} + +void QGLCamera::setYCentre(qreal value) +{ + Q_D(QGLCamera); + d->center.setY(value); + emit viewChanged(); +} + +/*! + \property QGLCamera::zCentre + \brief the z position of the center of the view visible from the + viewer's position. The default value is 0. + + \sa eye(), translateEye(), upVector(), center(), eyeSeparation() + \sa motionAdjustment() +*/ +qreal QGLCamera::zCentre() const +{ + Q_D(QGLCamera); + return d->center.z(); +} + +void QGLCamera::setZCentre(qreal value) +{ + Q_D(QGLCamera); + d->center.setZ(value); + emit viewChanged(); +} + +/*! + \property QGLCamera::center + \brief the center of the view visible from the viewer's position. + The default value is (0, 0, 0). + + \sa translateCenter(), eye(), upVector() +*/ +QVector3D QGLCamera::center() const +{ + Q_D(const QGLCamera); + return d->center; +} + +void QGLCamera::setCenter(const QVector3D& vertex) +{ + Q_D(QGLCamera); + if (d->center != vertex) { + d->center = vertex; + d->viewVector = d->center - d->eye; + emit viewChanged(); + } +} + +/*! + Adjusts the center of the view by the components of \a vector. + The final position is center() + \a vector. + + \sa center(), setCenter(), translateEye() +*/ +void QGLCamera::translateCenter(const QVector3D& vector) +{ + Q_D(QGLCamera); + d->center += vector; + d->viewVector = d->center - d->eye; + emit viewChanged(); +} + +/*! + \property QGLCamera::eyeSeparation + \brief the separation between the eyes when stereo viewing is in use, + with eye() specifying the mid-point between the eyes. The default + value is 0. + + \sa eye() +*/ +qreal QGLCamera::eyeSeparation() const +{ + Q_D(const QGLCamera); + return d->eyeSeparation; +} + +void QGLCamera::setEyeSeparation(qreal value) +{ + Q_D(QGLCamera); + if (d->eyeSeparation != value) { + d->eyeSeparation = value; + emit viewChanged(); + } +} + +/*! + \property QGLCamera::motionAdjustment + \brief the adjustment vector to apply to the eye() for user motion. + + This property is typically used to implement motion tracking. + It is interpreted as a vector from the center of the screen to the + current position of the viewer. The angle between the motion + adjustment vector and the screen center is used to adjust the + position of the eye() when apply() is called. + + The default value is (0, 0, 1), which indicates a viewer + directly in front of the center of the screen. + + The units for the vector are unspecified. They could be + meters, centimeters, or the force due to gravity in various + directions from an accelerometer. The angle defined + by the vector is used to perform the adjustment, not its + magnitude. + + The output of motion tracking hardware can be very noisy, + with minor fluctuations due to viewer twitch movements or + environmental factors. The application is responsible for + cleaning up the signal and removing these fluctuations before + altering this property. + + \sa eye(), apply() +*/ + +QVector3D QGLCamera::motionAdjustment() const +{ + Q_D(const QGLCamera); + return d->motionAdjustment; +} + +void QGLCamera::setMotionAdjustment(const QVector3D& vector) +{ + Q_D(QGLCamera); + if (d->motionAdjustment != vector) { + d->motionAdjustment = vector; + if (vector.x() == 0.0f && vector.y() == 0.0f) { + // If the vector is centered, then don't perform any rotations. + d->motionQuaternion = QQuaternion(); + } else { + // Determine the pan and tilt angles from the vector. + QVector3D view = -vector.normalized(); + if (view.z() < 0.0f) + view = -view; + qreal xangle = asin(view.x()) * 180.0f / M_PI; + qreal yangle = asin(-view.y()) * 180.0f / M_PI; + + // Construct the pan and tilt quaternions. + if (qFuzzyIsNull(xangle)) + d->motionQuaternion = tilt(yangle); + else if (qFuzzyIsNull(yangle)) + d->motionQuaternion = pan(xangle); + else + d->motionQuaternion = tilt(yangle) * pan(xangle); + } + emit viewChanged(); + } +} + +/*! + Returns the quaternion corresponding to tilting the view up or + down by \a angle degrees. The returned quaternion can be applied to + the eye() position with rotateEye() or to the center() position with + rotateCenter(). + + \sa pan(), roll(), rotateEye(), rotateCenter() +*/ +QQuaternion QGLCamera::tilt(qreal angle) const +{ + Q_D(const QGLCamera); + QVector3D side = QVector3D::crossProduct(d->viewVector, d->upVector); + return QQuaternion::fromAxisAndAngle(side, angle); +} + +/*! + Returns the quaternion corresponding to panning the view left or + right by \a angle degrees. The returned quaternion can be applied to + the eye() position with rotateEye() or to the center() position with + rotateCenter(). + + \sa tilt(), roll(), rotateEye(), rotateCenter() +*/ +QQuaternion QGLCamera::pan(qreal angle) const +{ + Q_D(const QGLCamera); + return QQuaternion::fromAxisAndAngle(d->upVector, angle); +} + +/*! + Returns the quaternion corresponding to rolling the view left or + right by \a angle degrees. The returned quaternion can be applied to + the eye() position with rotateEye() or to the center() position with + rotateCenter(). + + \sa tilt(), pan(), rotateEye(), rotateCenter() +*/ +QQuaternion QGLCamera::roll(qreal angle) const +{ + Q_D(const QGLCamera); + return QQuaternion::fromAxisAndAngle(d->viewVector, angle); +} + +/*! + Rotates the orientation of the eye() according to the quaternion \a q. + The eye() will remain in the same position, but the upVector() and + center() may be altered by the rotation. + + \sa rotateCenter(), tilt(), pan(), roll() +*/ +void QGLCamera::rotateEye(const QQuaternion& q) +{ + Q_D(QGLCamera); + d->upVector = q.rotatedVector(d->upVector); + d->viewVector = q.rotatedVector(d->viewVector); + d->center = d->eye + d->viewVector; + emit viewChanged(); +} + +/*! + Rotates the position and orientation of the eye() around center() + according to the quaternion \a q. The center() will remain in the + same position, but the upVector() and eye() may be altered by + the rotation. + + \sa rotateEye(), tilt(), pan(), roll() +*/ +void QGLCamera::rotateCenter(const QQuaternion& q) +{ + Q_D(QGLCamera); + d->upVector = q.rotatedVector(d->upVector); + d->viewVector = q.rotatedVector(d->viewVector); + d->eye = d->center - d->viewVector; + emit viewChanged(); +} + +/*! + Returns a translation vector that can be used to adjust the eye() + or center() by \a x units side-ways, \a y units up, + and \a z units forwards. + + This function is useful when implementing operations such as + "step left", "jump up", and so on where the movement should be + interpreted relative to the viewer's current orientation, not the + world co-ordinate axes, + + The translation vector can be applied to eye() or center() by + calling translateEye() or translateCenter() respectively. + + \sa translateEye(), translateCenter() +*/ +QVector3D QGLCamera::translation(qreal x, qreal y, qreal z) const +{ + Q_D(const QGLCamera); + QVector3D vector(0.0f, 0.0f, 0.0f); + if (x != 0.0f) + vector += QVector3D::normal(d->viewVector, d->upVector) * x; + if (y != 0.0f) + vector += d->upVector.normalized() * y; + if (z != 0.0f) + vector += d->viewVector.normalized() * z; + return vector; +} + +/*! + Returns the transformation matrix to apply to the projection matrix + to present the scene as viewed from the camera position. + + The \a aspectRatio specifies the aspect ratio of the window the + camera view is being displayed in. An \a aspectRatio of 1 indicates that + the window is square. An \a aspectRatio greater than 1 indicates that + the window is wider than it is high. An \a aspectRatio less than 1 + indicates that the window is higher than it is wide. + + \sa apply(), modelViewMatrix() +*/ +QMatrix4x4 QGLCamera::projectionMatrix(qreal aspectRatio) const +{ + Q_D(const QGLCamera); + QMatrix4x4 m; + if (d->screenRotation != 0) { + m.rotate((qreal)(d->screenRotation), 0.0f, 0.0f, 1.0f); + if (d->screenRotation == 90 || d->screenRotation == 270) { + if (aspectRatio != 0.0f) + aspectRatio = 1.0f / aspectRatio; + } + } + if (d->projectionType == Perspective && d->fieldOfView != 0.0f) { + m.perspective(d->fieldOfView, aspectRatio, + d->nearPlane, d->farPlane); + } else { + qreal halfWidth = d->viewSize.width() / 2.0f; + qreal halfHeight = d->viewSize.height() / 2.0f; + if (aspectRatio > 1.0f) { + halfWidth *= aspectRatio; + } else if (aspectRatio > 0.0f && aspectRatio < 1.0f) { + halfHeight /= aspectRatio; + } + if (d->projectionType == Perspective) { + m.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight, + d->nearPlane, d->farPlane); + } else { + m.ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, + d->nearPlane, d->farPlane); + } + } + return m; +} + +/*! + Returns the transformation to apply to the modelview matrix + to present the scene as viewed from the eye() position. + + \sa apply(), projectionMatrix() +*/ +QMatrix4x4 QGLCamera::modelViewMatrix() const +{ + Q_D(const QGLCamera); + QMatrix4x4 m; + if (d->motionQuaternion.isIdentity()) { + m.lookAt(d->eye, d->center, d->upVector); + } else { + QVector3D up = d->motionQuaternion.rotatedVector(d->upVector); + QVector3D view = d->motionQuaternion.rotatedVector(d->viewVector); + QVector3D eye = d->center - view; + m.lookAt(eye, d->center, up); + } + return m; +} + +/*! + \fn void QGLCamera::projectionChanged() + + This signal is emitted when one of projectionType(), fieldOfView(), + nearPlane(), farPlane(), viewSize(), or screenRotation() changes, + indicating a modification to the optical properties of the camera + looking at the scene. + + \sa viewChanged() +*/ + +/*! + \fn void QGLCamera::viewChanged() + + This signal is emitted when one of eye(), upVector(), or center() + changes, indicating a modification to the viewer's position or + orientation. + + \sa projectionChanged() +*/ + +QT_END_NAMESPACE diff --git a/examples/opencl/bezierpatch/qglcamera.h b/examples/opencl/bezierpatch/qglcamera.h new file mode 100644 index 0000000..1fb93e6 --- /dev/null +++ b/examples/opencl/bezierpatch/qglcamera.h @@ -0,0 +1,166 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QGLCAMERA_H +#define QGLCAMERA_H + +#include <QtCore/qobject.h> +#include <QtCore/qsize.h> +#include <QtGui/qvector3d.h> +#include <QtGui/qmatrix4x4.h> +#include <QtGui/qquaternion.h> + +QT_BEGIN_HEADER + +class QGLCameraPrivate; + +class QGLCamera : public QObject +{ + Q_OBJECT + Q_ENUMS(ProjectionType) + Q_PROPERTY(ProjectionType projectionType READ projectionType WRITE setProjectionType NOTIFY projectionChanged) + Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY projectionChanged) + Q_PROPERTY(qreal nearPlane READ nearPlane WRITE setNearPlane NOTIFY projectionChanged) + Q_PROPERTY(qreal farPlane READ farPlane WRITE setFarPlane NOTIFY projectionChanged) + Q_PROPERTY(QSizeF viewSize READ viewSize WRITE setViewSize NOTIFY projectionChanged) + Q_PROPERTY(QSizeF minViewSize READ minViewSize WRITE setMinViewSize NOTIFY projectionChanged) + Q_PROPERTY(int screenRotation READ screenRotation WRITE setScreenRotation NOTIFY projectionChanged) + Q_PROPERTY(qreal xEye READ xEye WRITE setXEye NOTIFY viewChanged) + Q_PROPERTY(qreal yEye READ yEye WRITE setYEye NOTIFY viewChanged) + Q_PROPERTY(qreal zEye READ zEye WRITE setZEye NOTIFY viewChanged) + Q_PROPERTY(QVector3D eye READ eye WRITE setEye NOTIFY viewChanged) + Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector NOTIFY viewChanged) + Q_PROPERTY(qreal xCentre READ xCentre WRITE setXCentre NOTIFY viewChanged) + Q_PROPERTY(qreal yCentre READ yCentre WRITE setYCentre NOTIFY viewChanged) + Q_PROPERTY(qreal zCentre READ zCentre WRITE setZCentre NOTIFY viewChanged) + Q_PROPERTY(QVector3D center READ center WRITE setCenter NOTIFY viewChanged) + Q_PROPERTY(qreal eyeSeparation READ eyeSeparation WRITE setEyeSeparation NOTIFY viewChanged) + Q_PROPERTY(QVector3D motionAdjustment READ motionAdjustment WRITE setMotionAdjustment DESIGNABLE false NOTIFY viewChanged) +public: + explicit QGLCamera(QObject *parent = 0); + ~QGLCamera(); + + enum ProjectionType + { + Perspective, + Orthographic + }; + + QGLCamera::ProjectionType projectionType() const; + void setProjectionType(QGLCamera::ProjectionType value); + + qreal fieldOfView() const; + void setFieldOfView(qreal angle); + + qreal nearPlane() const; + void setNearPlane(qreal value); + + qreal farPlane() const; + void setFarPlane(qreal value); + + QSizeF viewSize() const; + void setViewSize(const QSizeF& size); + + QSizeF minViewSize() const; + void setMinViewSize(const QSizeF& size); + + int screenRotation() const; + void setScreenRotation(int angle); + + qreal xEye() const; + void setXEye(qreal value); + qreal yEye() const; + void setYEye(qreal value); + qreal zEye() const; + void setZEye(qreal value); + + QVector3D eye() const; + void setEye(const QVector3D& vertex); + + QVector3D upVector() const; + void setUpVector(const QVector3D& vector); + + qreal xCentre() const; + void setXCentre(qreal value); + qreal yCentre() const; + void setYCentre(qreal value); + qreal zCentre() const; + void setZCentre(qreal value); + + QVector3D center() const; + void setCenter(const QVector3D& vertex); + + qreal eyeSeparation() const; + void setEyeSeparation(qreal value); + + QVector3D motionAdjustment() const; + void setMotionAdjustment(const QVector3D& vector); + + QQuaternion tilt(qreal angle) const; + QQuaternion pan(qreal angle) const; + QQuaternion roll(qreal angle) const; + + void rotateEye(const QQuaternion& q); + void rotateCenter(const QQuaternion& q); + + QVector3D translation(qreal x, qreal y, qreal z) const; + + void translateEye(const QVector3D& vector); + void translateCenter(const QVector3D& vector); + + QMatrix4x4 projectionMatrix(qreal aspectRatio) const; + QMatrix4x4 modelViewMatrix() const; + +Q_SIGNALS: + void projectionChanged(); + void viewChanged(); + +private: + QGLCameraPrivate *d_ptr; + + QGLCameraPrivate *d_func() const { return d_ptr; } + + Q_DISABLE_COPY(QGLCamera) +}; + +QT_END_HEADER + +#endif diff --git a/examples/opencl/bezierpatch/qtlogo.png b/examples/opencl/bezierpatch/qtlogo.png Binary files differnew file mode 100644 index 0000000..aa24072 --- /dev/null +++ b/examples/opencl/bezierpatch/qtlogo.png diff --git a/examples/opencl/opencl.pro b/examples/opencl/opencl.pro index 57abaa8..558760f 100644 --- a/examples/opencl/opencl.pro +++ b/examples/opencl/opencl.pro @@ -1,2 +1,2 @@ TEMPLATE = subdirs -SUBDIRS = vectoradd blur pathdrawing +SUBDIRS = vectoradd blur pathdrawing bezierpatch |