From f940e3207433b19f06c52646a5c29bed46c11d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20R=C3=B8dal?= Date: Mon, 23 Jun 2008 12:00:09 +0200 Subject: Move GraphicsScene and Controls to graphicsscene.cpp --- graphicsscene.cpp | 332 ++++++++++++++++++++++++++++++++++++++++++++++++ graphicsscene.h | 57 +++++++++ main.cpp | 371 +----------------------------------------------------- openglexample.pro | 3 +- point3d.h | 2 + 5 files changed, 394 insertions(+), 371 deletions(-) create mode 100644 graphicsscene.cpp create mode 100644 graphicsscene.h diff --git a/graphicsscene.cpp b/graphicsscene.cpp new file mode 100644 index 0000000..e26684a --- /dev/null +++ b/graphicsscene.cpp @@ -0,0 +1,332 @@ +#include "graphicsscene.h" + +#include "model.h" + +#include "GL/gl.h" +#include "GL/glu.h" + +#include +#include + +class Controls : public QGroupBox +{ + Q_OBJECT + +public: + Controls(GraphicsScene *scene); + +private slots: + void loadModel(const QString &model); + void modelLoaded(); + void setModelColor(bool showDialog = true); + void setBackgroundColor(bool showDialog = true); + +private: + GraphicsScene *m_scene; + QFutureWatcher m_modelLoader; + QComboBox *m_models; + + QRgb m_modelColor; + QRgb m_backgroundColor; +}; + +Controls::Controls(GraphicsScene *scene) + : m_scene(scene) + , m_models(new QComboBox) + , m_modelColor(qRgb(180, 100, 255)) + , m_backgroundColor(qRgb(0, 0, 0)) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + + layout->addWidget(new QLabel("Model:")); + + QDir dir("models"); + dir.setNameFilters(QStringList() << "*.obj"); + m_models->addItems(dir.entryList()); + connect(m_models, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(loadModel(const QString &))); + connect(&m_modelLoader, SIGNAL(finished()), this, SLOT(modelLoaded())); + + if (m_models->count() > 0) + loadModel(m_models->currentText()); + layout->addWidget(m_models); + + QCheckBox *autoRotate = new QCheckBox("Auto-rotate"); + autoRotate->setChecked(true); + connect(autoRotate, SIGNAL(toggled(bool)), m_scene, SLOT(enableAutoRotate(bool))); + layout->addWidget(autoRotate); + + QCheckBox *wireframe = new QCheckBox("Render as wireframe"); + wireframe->setChecked(true); + connect(wireframe, SIGNAL(toggled(bool)), m_scene, SLOT(enableWireframe(bool))); + layout->addWidget(wireframe); + + QCheckBox *normals = new QCheckBox("Display normals vectors"); + wireframe->setChecked(false); + connect(normals, SIGNAL(toggled(bool)), m_scene, SLOT(enableNormals(bool))); + layout->addWidget(normals); + + layout->addWidget(new QLabel("Light position:")); + QSlider *lightPosition = new QSlider(Qt::Horizontal); + lightPosition->setRange(-100, 100); + connect(lightPosition, SIGNAL(valueChanged(int)), m_scene, SLOT(setLightPosition(int))); + layout->addWidget(lightPosition); + + m_scene->setLightPosition(lightPosition->value()); + + QPushButton *colorButton = new QPushButton("Choose model color"); + connect(colorButton, SIGNAL(pressed()), this, SLOT(setModelColor())); + layout->addWidget(colorButton); + setModelColor(false); + + QPushButton *backgroundButton = new QPushButton("Choose background color"); + connect(backgroundButton, SIGNAL(pressed()), this, SLOT(setBackgroundColor())); + layout->addWidget(backgroundButton); + setBackgroundColor(false); +} + +Model *loadModel(const QString &filename) +{ + return new Model(QString("models/") + filename); +} + +void Controls::loadModel(const QString &filename) +{ + m_modelLoader.setFuture(QtConcurrent::run(::loadModel, filename)); + m_models->setEnabled(false); + QApplication::setOverrideCursor(Qt::BusyCursor); +} + +void Controls::modelLoaded() +{ + m_scene->setModel(m_modelLoader.result()); + m_models->setEnabled(true); + QApplication::restoreOverrideCursor(); +} + +void Controls::setModelColor(bool showDialog) +{ + if (showDialog) + m_modelColor = QColorDialog::getRgba(m_modelColor); + + m_scene->setModelColor(m_modelColor); +} + +void Controls::setBackgroundColor(bool showDialog) +{ + if (showDialog) + m_backgroundColor = QColorDialog::getRgba(m_backgroundColor); + + m_scene->setBackgroundColor(m_backgroundColor); +} + +GraphicsScene::GraphicsScene() + : m_wireframeEnabled(true) + , m_normalsEnabled(false) + , m_autoRotate(true) + , m_rotating(false) + , m_axis(0.5, 1, 0.1) + , m_angle(0.2) + , m_distance(1.5) + , m_model(0) +{ + // set identity matrix + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 4; ++j) + m_matrix[i][j] = (i == j); + + Controls *controls = new Controls(this); + controls->setWindowOpacity(0.8); + + QGraphicsProxyWidget *item = addWidget(controls); + item->translate(10, 10); + item->setCacheMode(QGraphicsItem::DeviceCoordinateCache); + + setSceneRect(QRect(0, 0, 1024, 768)); +} + +void GraphicsScene::updateMatrix() +{ + if (!QGLContext::currentContext()) + return; + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glRotatef(m_angle, m_axis.x, m_axis.y, m_axis.z); + glMultMatrixf(&m_matrix[0][0]); + glGetFloatv(GL_MODELVIEW_MATRIX, &m_matrix[0][0]); + glPopMatrix(); +} + +void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) +{ + painter->save(); + + glClearColor(qRed(m_backgroundColor)/255.0f, qGreen(m_backgroundColor)/255.0f, qBlue(m_backgroundColor)/255.0f, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + bool useMultisample = static_cast(painter->device())->format().sampleBuffers(); + + if (m_model) { + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + gluPerspective(70, painter->device()->width() / float(painter->device()->height()), 0.01, 1000); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + float pos[] = { m_lightPos, 5, 2, 0 }; + glLightfv(GL_LIGHT0, GL_POSITION, pos); + glColor4f(qRed(m_modelColor)/255.0f, qGreen(m_modelColor)/255.0f, qBlue(m_modelColor)/255.0f, 1.0f); + + if (m_autoRotate && !m_rotating) + updateMatrix(); + + glLoadIdentity(); + glTranslatef(0, 0, -m_distance); + glMultMatrixf(&m_matrix[0][0]); + + if (useMultisample) + glEnable(GL_MULTISAMPLE); + + m_model->render(m_wireframeEnabled, m_normalsEnabled); + + if (useMultisample) + glDisable(GL_MULTISAMPLE); + + glPopMatrix(); + + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + } + + painter->restore(); + + QTimer::singleShot(20, this, SLOT(update())); +} + +void GraphicsScene::setModel(Model *model) +{ + delete m_model; + m_model = model; + update(); +} + +void GraphicsScene::enableAutoRotate(bool enabled) +{ + m_autoRotate = enabled; + update(); +} + +void GraphicsScene::enableWireframe(bool enabled) +{ + m_wireframeEnabled = enabled; +} + +void GraphicsScene::enableNormals(bool enabled) +{ + m_normalsEnabled = enabled; +} + +void GraphicsScene::setLightPosition(int pos) +{ + m_lightPos = pos * 0.05; + update(); +} + +void GraphicsScene::setModelColor(QRgb color) +{ + m_modelColor = color; + update(); +} + +void GraphicsScene::setBackgroundColor(QRgb color) +{ + m_backgroundColor = color; + update(); +} + +static Point3d spherical(const QPointF &point, qreal w, qreal h) +{ + qreal R = qMax(w, h); + + Point3d p; + p.x = -(point.x() - w / 2); + p.y = point.y() - h / 2; + p.z = sqrt(R * R - p.x * p.x - p.y * p.y); + + p.x /= R; + p.y /= R; + p.z /= R; + return p; +} + +void GraphicsScene::updateRotation(const QPointF &last, const QPointF ¤t) +{ + Point3d pos = spherical(current, width(), height()); + Point3d lastPos = spherical(last, width(), height()); + + m_axis.x = lastPos.y * pos.z - lastPos.z * pos.y; + m_axis.y = lastPos.z * pos.x - lastPos.x * pos.z; + m_axis.z = lastPos.x * pos.y - lastPos.y * pos.x; + + qreal length = sqrt(m_axis.x * m_axis.x + m_axis.y * m_axis.y + m_axis.z * m_axis.z); + + if (length == 0) { + m_angle = 0; + } else { + m_angle = -10 * asin(sqrt(length)); + + m_axis.x /= length; + m_axis.y /= length; + m_axis.z /= length; + + updateMatrix(); + update(); + } +} + +void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +{ + QGraphicsScene::mouseMoveEvent(event); + if (event->isAccepted() || !m_rotating) + return; + + updateRotation(event->lastScenePos(), event->scenePos()); + event->accept(); +} + +void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + QGraphicsScene::mousePressEvent(event); + if (event->isAccepted()) + return; + + event->accept(); + m_rotating = true; +} + +void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + QGraphicsScene::mouseReleaseEvent(event); + if (event->isAccepted()) + return; + + event->accept(); + m_rotating = false; +} + + +void GraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *event) +{ + QGraphicsScene::wheelEvent(event); + if (event->isAccepted()) + return; + + m_distance *= qPow(1.2, -event->delta() / 120); + event->accept(); + update(); +} + +#include "graphicsscene.moc" diff --git a/graphicsscene.h b/graphicsscene.h new file mode 100644 index 0000000..9618cf7 --- /dev/null +++ b/graphicsscene.h @@ -0,0 +1,57 @@ +#ifndef GRAPHICSSCENE_H +#define GRAPHICSSCENE_H + +#include "point3d.h" + +#include +#include + +class Model; + +class GraphicsScene : public QGraphicsScene +{ + Q_OBJECT + +public: + GraphicsScene(); + + void drawBackground(QPainter *painter, const QRectF &rect); + +public slots: + void setModel(Model *model); + void enableAutoRotate(bool enabled); + void enableWireframe(bool enabled); + void enableNormals(bool enabled); + void setLightPosition(int pos); + void setModelColor(QRgb color); + void setBackgroundColor(QRgb color); + +protected: + void mousePressEvent(QGraphicsSceneMouseEvent *event); + void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + void mouseMoveEvent(QGraphicsSceneMouseEvent *event); + void wheelEvent(QGraphicsSceneWheelEvent * wheelEvent); + +private: + void updateMatrix(); + void updateRotation(const QPointF &last, const QPointF ¤t); + + bool m_wireframeEnabled; + bool m_normalsEnabled; + bool m_autoRotate; + bool m_rotating; + + Point3d m_axis; + float m_angle; + float m_lightPos; + float m_distance; + + QRgb m_backgroundColor; + QRgb m_modelColor; + + Model *m_model; + + float m_matrix[4][4]; +}; + +#endif diff --git a/main.cpp b/main.cpp index 7d20fc1..e71e334 100644 --- a/main.cpp +++ b/main.cpp @@ -1,374 +1,7 @@ #include #include -#include -#include - -#include "model.h" - -class GraphicsScene : public QGraphicsScene -{ - Q_OBJECT - -public: - GraphicsScene(); - - void drawBackground(QPainter *painter, const QRectF &rect); - -public slots: - void setModel(Model *model); - void enableAutoRotate(bool enabled); - void enableWireframe(bool enabled); - void enableNormals(bool enabled); - void setLightPosition(int pos); - void setModelColor(QRgb color); - void setBackgroundColor(QRgb color); - -protected: - void mousePressEvent(QGraphicsSceneMouseEvent *event); - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); - void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - void wheelEvent(QGraphicsSceneWheelEvent * wheelEvent); - -private: - void updateMatrix(); - void updateRotation(const QPointF &last, const QPointF ¤t); - - bool m_wireframeEnabled; - bool m_normalsEnabled; - bool m_autoRotate; - bool m_rotating; - - Point3d m_axis; - float m_angle; - float m_lightPos; - float m_distance; - - QRgb m_backgroundColor; - QRgb m_modelColor; - - Model *m_model; - - float m_matrix[4][4]; -}; - -class Controls : public QGroupBox -{ - Q_OBJECT - -public: - Controls(GraphicsScene *scene); - -private slots: - void loadModel(const QString &model); - void modelLoaded(); - void setModelColor(bool showDialog = true); - void setBackgroundColor(bool showDialog = true); - -private: - GraphicsScene *m_scene; - QFutureWatcher m_modelLoader; - QComboBox *m_models; - - QRgb m_modelColor; - QRgb m_backgroundColor; -}; - -Controls::Controls(GraphicsScene *scene) - : m_scene(scene) - , m_models(new QComboBox) - , m_modelColor(qRgb(180, 100, 255)) - , m_backgroundColor(qRgb(0, 0, 0)) -{ - QVBoxLayout *layout = new QVBoxLayout(this); - - layout->addWidget(new QLabel("Model:")); - - QDir dir("models"); - dir.setNameFilters(QStringList() << "*.obj"); - m_models->addItems(dir.entryList()); - connect(m_models, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(loadModel(const QString &))); - connect(&m_modelLoader, SIGNAL(finished()), this, SLOT(modelLoaded())); - - if (m_models->count() > 0) - loadModel(m_models->currentText()); - layout->addWidget(m_models); - - QCheckBox *autoRotate = new QCheckBox("Auto-rotate"); - autoRotate->setChecked(true); - connect(autoRotate, SIGNAL(toggled(bool)), m_scene, SLOT(enableAutoRotate(bool))); - layout->addWidget(autoRotate); - - QCheckBox *wireframe = new QCheckBox("Render as wireframe"); - wireframe->setChecked(true); - connect(wireframe, SIGNAL(toggled(bool)), m_scene, SLOT(enableWireframe(bool))); - layout->addWidget(wireframe); - - QCheckBox *normals = new QCheckBox("Display normals vectors"); - wireframe->setChecked(false); - connect(normals, SIGNAL(toggled(bool)), m_scene, SLOT(enableNormals(bool))); - layout->addWidget(normals); - - layout->addWidget(new QLabel("Light position:")); - QSlider *lightPosition = new QSlider(Qt::Horizontal); - lightPosition->setRange(-100, 100); - connect(lightPosition, SIGNAL(valueChanged(int)), m_scene, SLOT(setLightPosition(int))); - layout->addWidget(lightPosition); - - m_scene->setLightPosition(lightPosition->value()); - - QPushButton *colorButton = new QPushButton("Choose model color"); - connect(colorButton, SIGNAL(pressed()), this, SLOT(setModelColor())); - layout->addWidget(colorButton); - setModelColor(false); - - QPushButton *backgroundButton = new QPushButton("Choose background color"); - connect(backgroundButton, SIGNAL(pressed()), this, SLOT(setBackgroundColor())); - layout->addWidget(backgroundButton); - setBackgroundColor(false); -} - -Model *loadModel(const QString &filename) -{ - return new Model(QString("models/") + filename); -} - -void Controls::loadModel(const QString &filename) -{ - m_modelLoader.setFuture(QtConcurrent::run(::loadModel, filename)); - m_models->setEnabled(false); - QApplication::setOverrideCursor(Qt::BusyCursor); -} - -void Controls::modelLoaded() -{ - m_scene->setModel(m_modelLoader.result()); - m_models->setEnabled(true); - QApplication::restoreOverrideCursor(); -} - -void Controls::setModelColor(bool showDialog) -{ - if (showDialog) - m_modelColor = QColorDialog::getRgba(m_modelColor); - - m_scene->setModelColor(m_modelColor); -} - -void Controls::setBackgroundColor(bool showDialog) -{ - if (showDialog) - m_backgroundColor = QColorDialog::getRgba(m_backgroundColor); - - m_scene->setBackgroundColor(m_backgroundColor); -} - -GraphicsScene::GraphicsScene() - : m_wireframeEnabled(true) - , m_normalsEnabled(false) - , m_autoRotate(true) - , m_rotating(false) - , m_axis(0.5, 1, 0.1) - , m_angle(0.2) - , m_distance(1.5) - , m_model(0) -{ - // set identity matrix - for (int i = 0; i < 4; ++i) - for (int j = 0; j < 4; ++j) - m_matrix[i][j] = (i == j); - - Controls *controls = new Controls(this); - controls->setWindowOpacity(0.8); - - QGraphicsProxyWidget *item = addWidget(controls); - item->translate(10, 10); - item->setCacheMode(QGraphicsItem::DeviceCoordinateCache); - - setSceneRect(QRect(0, 0, 1024, 768)); -} - -void GraphicsScene::updateMatrix() -{ - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - glRotatef(m_angle, m_axis.x, m_axis.y, m_axis.z); - glMultMatrixf(&m_matrix[0][0]); - glGetFloatv(GL_MODELVIEW_MATRIX, &m_matrix[0][0]); - glPopMatrix(); -} - -void GraphicsScene::drawBackground(QPainter *painter, const QRectF &) -{ - painter->save(); - - glClearColor(qRed(m_backgroundColor)/255.0f, qGreen(m_backgroundColor)/255.0f, qBlue(m_backgroundColor)/255.0f, 1); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - bool useMultisample = static_cast(painter->device())->format().sampleBuffers(); - - if (m_model) { - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - gluPerspective(70, painter->device()->width() / float(painter->device()->height()), 0.01, 1000); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - float pos[] = { m_lightPos, 5, 2, 0 }; - glLightfv(GL_LIGHT0, GL_POSITION, pos); - glColor4f(qRed(m_modelColor)/255.0f, qGreen(m_modelColor)/255.0f, qBlue(m_modelColor)/255.0f, 1.0f); - - if (m_autoRotate && !m_rotating) - updateMatrix(); - - glLoadIdentity(); - glTranslatef(0, 0, -m_distance); - glMultMatrixf(&m_matrix[0][0]); - - if (useMultisample) - glEnable(GL_MULTISAMPLE); - - m_model->render(m_wireframeEnabled, m_normalsEnabled); - - if (useMultisample) - glDisable(GL_MULTISAMPLE); - - glPopMatrix(); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - } - - painter->restore(); - - QTimer::singleShot(20, this, SLOT(update())); -} - -void GraphicsScene::setModel(Model *model) -{ - delete m_model; - m_model = model; - update(); -} - -void GraphicsScene::enableAutoRotate(bool enabled) -{ - m_autoRotate = enabled; - update(); -} - -void GraphicsScene::enableWireframe(bool enabled) -{ - m_wireframeEnabled = enabled; -} - -void GraphicsScene::enableNormals(bool enabled) -{ - m_normalsEnabled = enabled; -} - -void GraphicsScene::setLightPosition(int pos) -{ - m_lightPos = pos * 0.05; - update(); -} - -void GraphicsScene::setModelColor(QRgb color) -{ - m_modelColor = color; - update(); -} - -void GraphicsScene::setBackgroundColor(QRgb color) -{ - m_backgroundColor = color; - update(); -} - -static Point3d spherical(const QPointF &point, qreal w, qreal h) -{ - qreal R = qMax(w, h); - - Point3d p; - p.x = -(point.x() - w / 2); - p.y = point.y() - h / 2; - p.z = sqrt(R * R - p.x * p.x - p.y * p.y); - - p.x /= R; - p.y /= R; - p.z /= R; - return p; -} - -void GraphicsScene::updateRotation(const QPointF &last, const QPointF ¤t) -{ - Point3d pos = spherical(current, width(), height()); - Point3d lastPos = spherical(last, width(), height()); - - m_axis.x = lastPos.y * pos.z - lastPos.z * pos.y; - m_axis.y = lastPos.z * pos.x - lastPos.x * pos.z; - m_axis.z = lastPos.x * pos.y - lastPos.y * pos.x; - - qreal length = sqrt(m_axis.x * m_axis.x + m_axis.y * m_axis.y + m_axis.z * m_axis.z); - - if (length == 0) { - m_angle = 0; - } else { - m_angle = -10 * asin(sqrt(length)); - - m_axis.x /= length; - m_axis.y /= length; - m_axis.z /= length; - - updateMatrix(); - update(); - } -} - -void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - QGraphicsScene::mouseMoveEvent(event); - if (event->isAccepted() || !m_rotating) - return; - - updateRotation(event->lastScenePos(), event->scenePos()); - event->accept(); -} - -void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - QGraphicsScene::mousePressEvent(event); - if (event->isAccepted()) - return; - - event->accept(); - m_rotating = true; -} - -void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - QGraphicsScene::mouseReleaseEvent(event); - if (event->isAccepted()) - return; - - event->accept(); - m_rotating = false; -} - - -void GraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *event) -{ - QGraphicsScene::wheelEvent(event); - if (event->isAccepted()) - return; - - m_distance *= qPow(1.2, -event->delta() / 120); - event->accept(); - update(); -} +#include "graphicsscene.h" int main(int argc, char **argv) { @@ -388,5 +21,3 @@ int main(int argc, char **argv) return app.exec(); } - -#include "main.moc" diff --git a/openglexample.pro b/openglexample.pro index beff809..55f3025 100644 --- a/openglexample.pro +++ b/openglexample.pro @@ -8,6 +8,7 @@ DEPENDPATH += . INCLUDEPATH += . # Input -SOURCES += main.cpp model.cpp +HEADERS += graphicsscene.h point3d.h model.h +SOURCES += main.cpp model.cpp graphicsscene.cpp QT += opengl diff --git a/point3d.h b/point3d.h index aba6136..2e37e42 100644 --- a/point3d.h +++ b/point3d.h @@ -1,6 +1,8 @@ #ifndef POINT3D_H #define POINT3D_H +#include "math.h" + struct Point3d { float x, y, z; -- cgit v1.2.3