From 85c9e2eac126a5fe8dc8938999abac34f01257d2 Mon Sep 17 00:00:00 2001 From: Shaun Reed Date: Sun, 1 Jan 2023 22:26:58 -0500 Subject: [PATCH] Clean and comment code --- CMakeLists.txt | 5 +- src/CMakeLists.txt | 5 +- src/app/CMakeLists.txt | 5 +- src/app/debugconsole.cpp | 15 +-- src/app/debugconsole.h | 17 ++- src/app/examplescene.cpp | 8 +- src/app/examplescene.h | 10 +- src/app/main.cpp | 2 +- src/app/qtkmainwindow.cpp | 27 +++- src/app/qtkmainwindow.h | 27 ++-- src/app/qtkwidget.cpp | 197 ++++++++++++++--------------- src/app/qtkwidget.h | 106 ++++++++++------ src/app/toolbox.cpp | 2 +- src/app/toolbox.h | 12 +- src/app/treeview.cpp | 9 +- src/app/treeview.h | 14 +- src/app/widgetplugin.cpp | 42 +++--- src/app/widgetplugin.h | 20 ++- src/app/widgetplugincollection.cpp | 11 +- src/app/widgetplugincollection.h | 20 ++- src/qtk/CMakeLists.txt | 11 +- src/qtk/camera3d.cpp | 9 +- src/qtk/camera3d.h | 48 +++++-- src/qtk/input.cpp | 89 +++++++++---- src/qtk/input.h | 107 +++++++++++++--- src/qtk/meshrenderer.cpp | 115 ++++++++++------- src/qtk/meshrenderer.h | 153 +++++++++++++++++----- src/qtk/model.cpp | 152 +++------------------- src/qtk/model.h | 193 +++++++++++----------------- src/qtk/modelmesh.cpp | 129 +++++++++++++++++++ src/qtk/modelmesh.h | 138 ++++++++++++++++++++ src/qtk/object.cpp | 2 +- src/qtk/object.h | 16 ++- src/qtk/qtkapi.h | 8 +- src/qtk/scene.cpp | 26 ++-- src/qtk/scene.h | 62 +++++---- src/qtk/{mesh.cpp => shape.cpp} | 4 +- src/qtk/{mesh.h => shape.h} | 69 ++++++++-- src/qtk/skybox.cpp | 26 ++-- src/qtk/skybox.h | 34 ++++- src/qtk/texture.cpp | 8 +- src/qtk/texture.h | 92 +++++++++++--- src/qtk/transform3D.cpp | 30 +---- src/qtk/transform3D.h | 144 ++++++++++++++++++--- 44 files changed, 1463 insertions(+), 756 deletions(-) create mode 100644 src/qtk/modelmesh.cpp create mode 100644 src/qtk/modelmesh.h rename src/qtk/{mesh.cpp => shape.cpp} (99%) rename src/qtk/{mesh.h => shape.h} (84%) diff --git a/CMakeLists.txt b/CMakeLists.txt index c9f7a34..f80a734 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ ################################################################################ -## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## -## ## ## Project for working with OpenGL and Qt6 widgets ## +## ## +## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## +## All Content (c) 2023 Shaun Reed, all rights reserved ## ################################################################################ cmake_minimum_required(VERSION 3.23) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f7230f0..1b97d5f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,7 +1,8 @@ ################################################################################ -## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## -## ## ## Project for working with OpenGL and Qt6 widgets ## +## ## +## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## +## All Content (c) 2023 Shaun Reed, all rights reserved ## ################################################################################ # Qtk Library diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index f1b99e4..3c87bd1 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -1,7 +1,8 @@ ################################################################################ -## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## -## ## ## Project for working with OpenGL and Qt6 widgets ## +## ## +## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## +## All Content (c) 2023 Shaun Reed, all rights reserved ## ################################################################################ ################################################################################ diff --git a/src/app/debugconsole.cpp b/src/app/debugconsole.cpp index a459815..186c302 100644 --- a/src/app/debugconsole.cpp +++ b/src/app/debugconsole.cpp @@ -1,7 +1,7 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## -## About: MainWindow for creating an example Qt application ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: Debug console for qtk views ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ @@ -29,16 +29,5 @@ DebugConsole::DebugConsole( auto qtkWidget = dynamic_cast(owner); if(qtkWidget) { connect(qtkWidget, &QtkWidget::sendLog, this, &DebugConsole::sendLog); - sendLog( - "Debug console (" + name + ") attached to QtkWidget: '" - + qtkWidget->objectName() + "'"); - sendLog("Test\nLogging\t\n\tStuff", Status); - sendLog("Test\nLogging\t\n\tStuff", Debug); - sendLog("Test\nLogging\t\n\tStuff", Warn); - sendLog("Test\nLogging\t\n\tStuff", Error); - sendLog( - "Test\nLogging\t\n\tStuff that is really long and will wrap around but " - "it might not you don't know until you try", - Fatal); } } diff --git a/src/app/debugconsole.h b/src/app/debugconsole.h index 07a3679..a2fc69e 100644 --- a/src/app/debugconsole.h +++ b/src/app/debugconsole.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Debug console for qtk views ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -73,10 +73,14 @@ namespace Qtk { * @param name Base name for the DebugConsole window. */ inline void setTitle(QString name) { - setWindowTitle(name + "Debug Console"); + setWindowTitle(name + " Debug Console"); } private: + /** + * @param context Log context severity level. + * @return QColor corresponding with the message context. + */ [[nodiscard]] QColor logColor(const DebugContext & context) const { switch(context) { case Status: @@ -94,6 +98,13 @@ namespace Qtk { } } + /** + * Prefixes a log message to add context level. + * + * @param message The message to prefix. + * @param context The log context severity level. + * @return The log message prefixed with the DebugContext level. + */ [[nodiscard]] QString logPrefix( QString & message, const DebugContext & context) { QString prefix; @@ -121,8 +132,8 @@ namespace Qtk { return message; } - QTextEdit * mConsole; Ui::DebugConsole * ui_; + QTextEdit * mConsole; }; } // namespace Qtk diff --git a/src/app/examplescene.cpp b/src/app/examplescene.cpp index 9c687cc..627a3fc 100644 --- a/src/app/examplescene.cpp +++ b/src/app/examplescene.cpp @@ -1,15 +1,11 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## -## About: Classes for managing objects and data within a scene ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: Example Qtk scene ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ -#include -#include -#include - #include "examplescene.h" #include "resources.h" diff --git a/src/app/examplescene.h b/src/app/examplescene.h index 9c182a4..6f0c187 100644 --- a/src/app/examplescene.h +++ b/src/app/examplescene.h @@ -1,7 +1,7 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## -## About: Classes for managing objects and data within a scene ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: Example Qtk scene ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ @@ -9,11 +9,7 @@ #ifndef QTK_EXAMPLE_SCENE_H #define QTK_EXAMPLE_SCENE_H -#include - -#include #include -#include /** * Example scene using QtkWidget to render 3D models and simple geometry within @@ -40,6 +36,7 @@ class ExampleScene : public Qtk::Scene { **************************************************************************/ ExampleScene(); + ~ExampleScene(); /*************************************************************************** @@ -50,6 +47,7 @@ class ExampleScene : public Qtk::Scene { * Initialize objects within the scene */ void init() override; + /** * Called when OpenGL repaints the widget. */ diff --git a/src/app/main.cpp b/src/app/main.cpp index 90136d5..116d1f8 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Main program for practice using Qt6 widgets and OpenGL ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## diff --git a/src/app/qtkmainwindow.cpp b/src/app/qtkmainwindow.cpp index 67596ba..cea68eb 100644 --- a/src/app/qtkmainwindow.cpp +++ b/src/app/qtkmainwindow.cpp @@ -1,19 +1,21 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: MainWindow for Qtk application ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ -#include - #include "examplescene.h" #include "qtkmainwindow.h" #include "ui_qtkmainwindow.h" MainWindow * MainWindow::mainWindow_ = Q_NULLPTR; +/******************************************************************************* + * Constructors / Destructors + ******************************************************************************/ + MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) { ui_ = new Ui::MainWindow; setObjectName("MainWindow"); @@ -47,6 +49,25 @@ MainWindow::~MainWindow() { delete ui_; } +/******************************************************************************* + * Public Methods + ******************************************************************************/ + +MainWindow * MainWindow::getMainWindow() { + if(mainWindow_ == Q_NULLPTR) { + mainWindow_ = new MainWindow; + } + return mainWindow_; +} + +Qtk::QtkWidget * MainWindow::getQtkWidget(const QString & name) { + if(!views_.count(name)) { + return Q_NULLPTR; + } + return views_[name]; +} + void MainWindow::refreshScene(QString sceneName) { + // TODO: Select TreeView using sceneName> ui_->qtk__TreeView->updateView(getQtkWidget(sceneName)->getScene()); } diff --git a/src/app/qtkmainwindow.h b/src/app/qtkmainwindow.h index f62e310..5f797a8 100644 --- a/src/app/qtkmainwindow.h +++ b/src/app/qtkmainwindow.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: MainWindow for Qtk application ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -40,22 +40,18 @@ class MainWindow : public QMainWindow { * @param parent The parent for this QMainWindow */ explicit MainWindow(QWidget * parent = nullptr); + ~MainWindow() override; /*************************************************************************** - * Public Static Methods + * Public Methods **************************************************************************/ /** * Allows widgets to retrieve an instance of this root QMainWindow. * @return this */ - inline static MainWindow * getMainWindow() { - if(mainWindow_ == Q_NULLPTR) { - mainWindow_ = new MainWindow; - } - return mainWindow_; - } + static MainWindow * getMainWindow(); /** * Accessor for retrieving a QtkWidget by it's objectName. @@ -64,22 +60,23 @@ class MainWindow : public QMainWindow { * @param name The objectName associated with the QtkWidget. * @return Pointer to an active QtkWidget or Q_NULLPTR is not found. */ - inline Qtk::QtkWidget * getQtkWidget(const QString & name) { - if(!views_.count(name)) { - return Q_NULLPTR; - } - return views_[name]; - } + Qtk::QtkWidget * getQtkWidget(const QString & name); public slots: + /** + * Trigger a refresh for widgets related to a scene that has been updated. + * @param sceneName The name of the scene that has been modified. + */ void refreshScene(QString sceneName); private: - MainWindow(const MainWindow &) {}; /*************************************************************************** * Private Members **************************************************************************/ + /** Do not allow copying */ + MainWindow(const MainWindow &) {}; + Ui::MainWindow * ui_ {}; static MainWindow * mainWindow_; diff --git a/src/app/qtkwidget.cpp b/src/app/qtkwidget.cpp index 01bf9e8..5735db4 100644 --- a/src/app/qtkwidget.cpp +++ b/src/app/qtkwidget.cpp @@ -1,7 +1,7 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## -## About: Main window for Qt6 OpenGL widget application ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: QtkWidget for Qt desktop application ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ @@ -9,9 +9,9 @@ #include #include -#include "qtk/input.h" -#include "qtk/mesh.h" -#include "qtk/scene.h" +#include +#include +#include #include "debugconsole.h" #include "qtkmainwindow.h" @@ -23,12 +23,15 @@ using namespace Qtk; * Constructors, Destructors ******************************************************************************/ +QtkWidget::QtkWidget(QWidget * parent) : + QtkWidget(parent, "QtkWidget") {} + QtkWidget::QtkWidget(QWidget * parent, const QString & name) : QtkWidget(parent, name, Q_NULLPTR) {} QtkWidget::QtkWidget(QWidget * parent, const QString & name, Scene * scene) : QOpenGLWidget(parent), mDebugLogger(Q_NULLPTR), - mConsole(new DebugConsole(this, name)) { + mConsole(new DebugConsole(this, name)), mScene(Q_NULLPTR) { setScene(scene); setObjectName(name); QSurfaceFormat format; @@ -65,10 +68,6 @@ QAction * QtkWidget::getActionToggleConsole() { return action; } -/******************************************************************************* - * Public Inherited Virtual Methods - ******************************************************************************/ - void QtkWidget::initializeGL() { initializeOpenGLFunctions(); // Connect the frameSwapped signal to call the update() function @@ -113,10 +112,58 @@ void QtkWidget::paintGL() { } } +void QtkWidget::setScene(Qtk::Scene * scene) { + delete mScene; + mScene = scene; + if(mScene != Q_NULLPTR) { + mConsole->setTitle(mScene->getSceneName()); + } else { + mConsole->setTitle("Null Scene"); + } +} + +void QtkWidget::toggleConsole() { + if(mConsoleActive) { + mConsole->setHidden(true); + mConsoleActive = false; + } else { + MainWindow::getMainWindow()->addDockWidget( + Qt::DockWidgetArea::BottomDockWidgetArea, + dynamic_cast(mConsole)); + mConsole->setHidden(false); + mConsoleActive = true; + } +} + /******************************************************************************* - * Protected Slots + * Protected Methods ******************************************************************************/ +void QtkWidget::keyPressEvent(QKeyEvent * event) { + if(event->isAutoRepeat()) { + // Do not repeat input while a key is held down + event->ignore(); + } else { + Input::registerKeyPress(event->key()); + } +} + +void QtkWidget::keyReleaseEvent(QKeyEvent * event) { + if(event->isAutoRepeat()) { + event->ignore(); + } else { + Input::registerKeyRelease(event->key()); + } +} + +void QtkWidget::mousePressEvent(QMouseEvent * event) { + Input::registerMousePress(event->button()); +} + +void QtkWidget::mouseReleaseEvent(QMouseEvent * event) { + Input::registerMouseRelease(event->button()); +} + void QtkWidget::update() { updateCameraInput(); @@ -195,39 +242,49 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) { sendLog("(OpenGL) " + error.replace("\n", "\n(OpenGL) "), context); } -/******************************************************************************* - * Protected Methods - ******************************************************************************/ - -void QtkWidget::keyPressEvent(QKeyEvent * event) { - if(event->isAutoRepeat()) { - // Do not repeat input while a key is held down - event->ignore(); - } else { - Input::registerKeyPress(event->key()); - } -} - -void QtkWidget::keyReleaseEvent(QKeyEvent * event) { - if(event->isAutoRepeat()) { - event->ignore(); - } else { - Input::registerKeyRelease(event->key()); - } -} - -void QtkWidget::mousePressEvent(QMouseEvent * event) { - Input::registerMousePress(event->button()); -} - -void QtkWidget::mouseReleaseEvent(QMouseEvent * event) { - Input::registerMouseRelease(event->button()); -} - /******************************************************************************* * Private Methods ******************************************************************************/ +void QtkWidget::teardownGL() { /* Nothing to teardown yet... */ } + +void QtkWidget::updateCameraInput() { + Input::update(); + // Camera Transformation + if(Input::buttonPressed(Qt::RightButton)) { + static const float transSpeed = 0.1f; + static const float rotSpeed = 0.5f; + + // Handle rotations + Scene::getCamera().getTransform().rotate( + -rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp); + Scene::getCamera().getTransform().rotate( + -rotSpeed * Input::mouseDelta().y(), Scene::getCamera().getRight()); + + // Handle translations + QVector3D translation; + if(Input::keyPressed(Qt::Key_W)) { + translation += Scene::getCamera().getForward(); + } + if(Input::keyPressed(Qt::Key_S)) { + translation -= Scene::getCamera().getForward(); + } + if(Input::keyPressed(Qt::Key_A)) { + translation -= Scene::getCamera().getRight(); + } + if(Input::keyPressed(Qt::Key_D)) { + translation += Scene::getCamera().getRight(); + } + if(Input::keyPressed(Qt::Key_Q)) { + translation -= Scene::getCamera().getUp() / 2.0f; + } + if(Input::keyPressed(Qt::Key_E)) { + translation += Scene::getCamera().getUp() / 2.0f; + } + Scene::getCamera().getTransform().translate(transSpeed * translation); + } +} + void QtkWidget::printContextInformation() { QString glType; QString glVersion; @@ -260,63 +317,3 @@ void QtkWidget::printContextInformation() { qDebug() << qPrintable(message); sendLog("(OpenGL) " + message.replace("\n", "\n(OpenGL) "), Status); } - -void QtkWidget::updateCameraInput() { - Input::update(); - // Camera Transformation - if(Input::buttonPressed(Qt::RightButton)) { - static const float transSpeed = 0.1f; - static const float rotSpeed = 0.5f; - - // Handle rotations - Scene::getCamera().getTransform().rotate( - -rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp); - Scene::getCamera().getTransform().rotate( - -rotSpeed * Input::mouseDelta().y(), Scene::getCamera().right()); - - // Handle translations - QVector3D translation; - if(Input::keyPressed(Qt::Key_W)) { - translation += Scene::getCamera().forward(); - } - if(Input::keyPressed(Qt::Key_S)) { - translation -= Scene::getCamera().forward(); - } - if(Input::keyPressed(Qt::Key_A)) { - translation -= Scene::getCamera().right(); - } - if(Input::keyPressed(Qt::Key_D)) { - translation += Scene::getCamera().right(); - } - if(Input::keyPressed(Qt::Key_Q)) { - translation -= Scene::getCamera().up() / 2.0f; - } - if(Input::keyPressed(Qt::Key_E)) { - translation += Scene::getCamera().up() / 2.0f; - } - Scene::getCamera().getTransform().translate(transSpeed * translation); - } -} - -void QtkWidget::toggleConsole() { - if(mConsoleActive) { - mConsole->setHidden(true); - mConsoleActive = false; - } else { - MainWindow::getMainWindow()->addDockWidget( - Qt::DockWidgetArea::BottomDockWidgetArea, - dynamic_cast(mConsole)); - mConsole->setHidden(false); - mConsoleActive = true; - } -} - -void QtkWidget::setScene(Qtk::Scene * scene) { - delete mScene; - mScene = scene; - if(mScene != Q_NULLPTR) { - mConsole->setTitle(mScene->getSceneName()); - } else { - mConsole->setTitle("Null Scene"); - } -} diff --git a/src/app/qtkwidget.h b/src/app/qtkwidget.h index 83a2c12..56ac290 100644 --- a/src/app/qtkwidget.h +++ b/src/app/qtkwidget.h @@ -1,7 +1,7 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## -## About: Main window for Qt6 OpenGL widget application ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: QtkWidget for Qt desktop application ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ @@ -17,8 +17,8 @@ #include #include -#include "qtk/qtkapi.h" -#include "qtk/scene.h" +#include +#include namespace Qtk { class DebugConsole; @@ -42,8 +42,7 @@ namespace Qtk { * * @param parent Pointer to a parent widget for this QtkWidget or nullptr. */ - explicit QtkWidget(QWidget * parent = nullptr) : - QtkWidget(parent, "QtkWidget") {} + explicit QtkWidget(QWidget * parent = nullptr); /** * Default construct a QtkWidget. @@ -62,26 +61,18 @@ namespace Qtk { */ QtkWidget(QWidget * parent, const QString & name, Qtk::Scene * scene); - ~QtkWidget() override; + ~QtkWidget(); + /************************************************************************* * Public Methods ************************************************************************/ + + /** + * Constructs a QAction to hide / show this DebugConsole. + * @return QAction to toggle visibility of this DebugConsole. + */ QAction * getActionToggleConsole(); - private: - /************************************************************************* - * Private Methods - ************************************************************************/ - - // clang-format off - void teardownGL() { /* Nothing to teardown yet... */ } - // clang-format on - - public: - /************************************************************************* - * Public Inherited Virtual Methods - ************************************************************************/ - /** * Called when the widget is first constructed. */ @@ -104,24 +95,61 @@ namespace Qtk { * Accessors ************************************************************************/ + /** + * @return The active scene being viewed in this widget. + */ inline Qtk::Scene * getScene() { return mScene; } /************************************************************************* * Setters ************************************************************************/ + /** + * @param scene The new scene to view. + */ void setScene(Qtk::Scene * scene); + public slots: + /** * Toggle visibility of the DebugConsole associated with this QtkWidget. */ void toggleConsole(); - protected slots: + signals: + /** + * Log a message to the DebugConsole associated with this widget. + * @param message The message to log. + * @param context The context of the log message. + */ + void sendLog(const QString & message, DebugContext context = Status); + + protected: /************************************************************************* - * Qt Slots + * Protected Methods ************************************************************************/ + /** + * @param event Key press event to update camera input manager. + */ + void keyPressEvent(QKeyEvent * event) override; + + /** + * @param event Key release event to update camera input manager. + */ + void keyReleaseEvent(QKeyEvent * event) override; + + /** + * @param event Mouse button press event to update camera input manager. + */ + void mousePressEvent(QMouseEvent * event) override; + + /** + * @param event Mouse button release event to update camera input manager. + */ + void mouseReleaseEvent(QMouseEvent * event) override; + + protected slots: /** * Called when the `frameSwapped` signal is caught. * See definition of initializeGL() @@ -137,39 +165,39 @@ namespace Qtk { */ void messageLogged(const QOpenGLDebugMessage & msg); #endif - public: - signals: - void sendLog( - const QString & message, Qtk::DebugContext context = Qtk::Status); - - protected: - /************************************************************************* - * Protected Methods - ************************************************************************/ - - void keyPressEvent(QKeyEvent * event) override; - void keyReleaseEvent(QKeyEvent * event) override; - void mousePressEvent(QMouseEvent * event) override; - void mouseReleaseEvent(QMouseEvent * event) override; private: /************************************************************************* * Private Methods ************************************************************************/ + /** + * Deconstruct any resources we have allocated for this widget. + */ + void teardownGL(); + + /** + * Callback function to update input for camera controls + */ static void updateCameraInput(); #ifdef QTK_DEBUG + /** + * Prints OpenGL context information at start of debug session. + */ void printContextInformation(); - QOpenGLDebugLogger * mDebugLogger; #endif + /************************************************************************* * Private Members ************************************************************************/ - bool mConsoleActive = false; +#ifdef QTK_DEBUG + QOpenGLDebugLogger * mDebugLogger; +#endif Qtk::Scene * mScene; Qtk::DebugConsole * mConsole; + bool mConsoleActive = false; }; } // namespace Qtk diff --git a/src/app/toolbox.cpp b/src/app/toolbox.cpp index ef986fc..72f9275 100644 --- a/src/app/toolbox.cpp +++ b/src/app/toolbox.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Toolbox plugin for object details and options ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## diff --git a/src/app/toolbox.h b/src/app/toolbox.h index 12a76a2..7181cf0 100644 --- a/src/app/toolbox.h +++ b/src/app/toolbox.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Toolbox plugin for object details and options ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -22,10 +22,20 @@ namespace Qtk { Q_OBJECT public: + /************************************************************************* + * Contructors / Destructors + *************************************************************************/ + explicit ToolBox(QWidget * parent = nullptr); + ~ToolBox(); private: + + /************************************************************************* + * Private Members + ************************************************************************/ + Ui::ToolBox * ui; }; } // namespace Qtk diff --git a/src/app/treeview.cpp b/src/app/treeview.cpp index b9c37dc..1fc95c5 100644 --- a/src/app/treeview.cpp +++ b/src/app/treeview.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: TreeView plugin for scene hierarchy ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -28,8 +28,9 @@ Qtk::TreeView::~TreeView() { } /******************************************************************************* - * Public Members + * Public Methods ******************************************************************************/ + void Qtk::TreeView::updateView(const Qtk::Scene * scene) { ui->treeWidget->clear(); ui->treeWidget->setColumnCount(1); @@ -48,9 +49,9 @@ void Qtk::TreeView::itemFocus(QTreeWidgetItem * item, int column) { auto & transform = scene->getCamera().getTransform(); auto object = scene->getObject(name); Transform3D * objectTransform; - if(object->getType() == Object::MESH) { + if(object->getType() == Object::QTK_MESH) { objectTransform = &dynamic_cast(object)->getTransform(); - } else if(object->getType() == Object::MODEL) { + } else if(object->getType() == Object::QTK_MODEL) { objectTransform = &dynamic_cast(object)->getTransform(); } transform.setTranslation(objectTransform->getTranslation()); diff --git a/src/app/treeview.h b/src/app/treeview.h index 2afcffd..d1bdba9 100644 --- a/src/app/treeview.h +++ b/src/app/treeview.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: TreeView plugin for scene hierarchy ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -26,10 +26,18 @@ namespace Qtk { Q_OBJECT public: + /************************************************************************* + * Constructors / Destructors + ************************************************************************/ + explicit TreeView(QWidget * parent = nullptr); ~TreeView(); + /************************************************************************* + * Public Methods + ************************************************************************/ + /** * Updates the QTreeWidget with all objects within the scene. * @param scene The scene to load objects from. @@ -48,6 +56,10 @@ namespace Qtk { void itemFocus(QTreeWidgetItem * item, int column); private: + /************************************************************************* + * Private Members + ************************************************************************/ + Ui::TreeView * ui; /** diff --git a/src/app/widgetplugin.cpp b/src/app/widgetplugin.cpp index 1fc6f49..c79bc4b 100644 --- a/src/app/widgetplugin.cpp +++ b/src/app/widgetplugin.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Generic Qt Designer widget plugin ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -11,10 +11,14 @@ #include #include -#include "qtk/qtkapi.h" +#include #include "widgetplugin.h" +/******************************************************************************* + * Constructors, Destructors + ******************************************************************************/ + WidgetPlugin::WidgetPlugin( QString group, QString class_name, QString include, WidgetPlugin::Factory factory) : @@ -22,21 +26,11 @@ WidgetPlugin::WidgetPlugin( m_className(std::move(class_name)), m_includeFile(std::move(include)), m_factory(std::move(factory)), m_objectName(class_name) {} -QString WidgetPlugin::toolTip() const { - return QStringLiteral("A custom widget tool tip."); -} +WidgetPlugin::WidgetPlugin(QObject * parent) : QObject(parent) {} -QString WidgetPlugin::whatsThis() const { - return QStringLiteral("Custom widget what's this?"); -} - -QIcon WidgetPlugin::icon() const { - return Qtk::getIcon(); -} - -bool WidgetPlugin::isContainer() const { - return true; -} +/******************************************************************************* + * Public Methods + ******************************************************************************/ QString WidgetPlugin::group() const { return m_group; @@ -54,6 +48,22 @@ QWidget * WidgetPlugin::createWidget(QWidget * parent) { return m_factory(parent); } +QString WidgetPlugin::toolTip() const { + return QStringLiteral("A custom widget tool tip."); +} + +QString WidgetPlugin::whatsThis() const { + return QStringLiteral("Custom widget what's this?"); +} + +QIcon WidgetPlugin::icon() const { + return Qtk::getIcon(); +} + +bool WidgetPlugin::isContainer() const { + return true; +} + bool WidgetPlugin::isInitialized() const { return m_initialized; } diff --git a/src/app/widgetplugin.h b/src/app/widgetplugin.h index 351d079..74f2330 100644 --- a/src/app/widgetplugin.h +++ b/src/app/widgetplugin.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Generic Qt Designer widget plugin ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -22,14 +22,21 @@ class QDESIGNER_WIDGET_EXPORT WidgetPlugin : using Factory = std::function; public: + /*************************************************************************** + * Contructors / Destructors + **************************************************************************/ + WidgetPlugin( QString group, QString class_name, QString include, Factory factory); - explicit WidgetPlugin(QObject * parent = nullptr) : QObject(parent) {} + explicit WidgetPlugin(QObject * parent = nullptr); ~WidgetPlugin() = default; - public: + /*************************************************************************** + * Public Methods + **************************************************************************/ + /** * @return The name of the group to which this widget belongs. */ @@ -56,7 +63,7 @@ class QDESIGNER_WIDGET_EXPORT WidgetPlugin : * @param parent Parent widget to the new instance of this widget. * @return A new instance of this custom widget. */ - QWidget * createWidget(QWidget * parent) override; + [[nodiscard]] QWidget * createWidget(QWidget * parent) override; /** * @return Short description used in Qt Designer tool tips. @@ -102,8 +109,11 @@ class QDESIGNER_WIDGET_EXPORT WidgetPlugin : [[nodiscard]] QString domXml() const override; private: - bool m_initialized = false; + /*************************************************************************** + * Private Members + **************************************************************************/ + bool m_initialized = false; QString m_group; QString m_className; QString m_objectName; diff --git a/src/app/widgetplugincollection.cpp b/src/app/widgetplugincollection.cpp index c1b0906..c728b54 100644 --- a/src/app/widgetplugincollection.cpp +++ b/src/app/widgetplugincollection.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Collection of widget plugins for Qt Designer ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -14,6 +14,10 @@ #include "treeview.h" #include "widgetplugin.h" +/******************************************************************************* + * Constructors, Destructors + ******************************************************************************/ + WidgetPluginCollection::WidgetPluginCollection(QObject * parent) : QObject(parent), m_collectionName("Qtk Widget Collection") { m_collection = { @@ -28,6 +32,11 @@ WidgetPluginCollection::WidgetPluginCollection(QObject * parent) : [](QWidget * parent) { return new Qtk::ToolBox(parent); }), }; } + +/******************************************************************************* + * Public Methods + ******************************************************************************/ + QList WidgetPluginCollection::customWidgets() const { return m_collection; diff --git a/src/app/widgetplugincollection.h b/src/app/widgetplugincollection.h index 20e4faa..f420084 100644 --- a/src/app/widgetplugincollection.h +++ b/src/app/widgetplugincollection.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Collection of widget plugins for Qt Designer ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -17,16 +17,32 @@ class WidgetPluginCollection : public QDesignerCustomWidgetCollectionInterface { Q_OBJECT // Since we're exporting a collection, this is the only plugin metadata - // needed. + // needed. We don't need this for-each widget in the collection. Q_PLUGIN_METADATA(IID "com.Klips.WidgetPluginCollection") // Tell Qt Object system that we're implementing an interface. Q_INTERFACES(QDesignerCustomWidgetCollectionInterface) public: + /*************************************************************************** + * Contructors / Destructors + **************************************************************************/ + explicit WidgetPluginCollection(QObject * parent = nullptr); + + /*************************************************************************** + * Public Methods + **************************************************************************/ + + /** + * @return QList of all custom widgets pointers. + */ [[nodiscard]] QList customWidgets() const; private: + /*************************************************************************** + * Private Members + **************************************************************************/ + QList m_collection; QString m_collectionName; }; diff --git a/src/qtk/CMakeLists.txt b/src/qtk/CMakeLists.txt index e4cfda2..b28b111 100644 --- a/src/qtk/CMakeLists.txt +++ b/src/qtk/CMakeLists.txt @@ -1,7 +1,8 @@ ################################################################################ -## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## -## ## ## Project for working with OpenGL and Qt6 widgets ## +## ## +## Author: Shaun Reed | Contact: shaunrd0@gmail.com | URL: www.shaunreed.com ## +## All Content (c) 2023 Shaun Reed, all rights reserved ## ################################################################################ # TODO: Provide option for linking MainWindow with plugin statically @@ -16,9 +17,10 @@ set(PUBLIC_HEADERS camera3d.h input.h - mesh.h + shape.h meshrenderer.h model.h + modelmesh.h object.h qtkapi.h scene.h @@ -30,9 +32,10 @@ set(PUBLIC_HEADERS set(SOURCE_FILES camera3d.cpp input.cpp - mesh.cpp + shape.cpp meshrenderer.cpp model.cpp + modelmesh.cpp object.cpp scene.cpp skybox.cpp diff --git a/src/qtk/camera3d.cpp b/src/qtk/camera3d.cpp index ec0da3b..1a2689d 100644 --- a/src/qtk/camera3d.cpp +++ b/src/qtk/camera3d.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Fly camera class from tutorials followed at trentreed.net ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -10,15 +10,18 @@ using namespace Qtk; +/******************************************************************************* + * Static Public Constants + ******************************************************************************/ + const QVector3D Camera3D::LocalForward(0.0f, 0.0f, -1.0f); const QVector3D Camera3D::LocalUp(0.0f, 1.0f, 0.0f); const QVector3D Camera3D::LocalRight(1.0f, 0.0f, 0.0f); /******************************************************************************* - * Accessors + * Public Methods ******************************************************************************/ -// Produces worldToView matrix const QMatrix4x4 & Camera3D::toMatrix() { mWorld.setToIdentity(); // Qt6 renamed QMatrix4x4::conjugate() to conjugated() diff --git a/src/qtk/camera3d.h b/src/qtk/camera3d.h index 809ce38..5d76221 100644 --- a/src/qtk/camera3d.h +++ b/src/qtk/camera3d.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Fly camera class from tutorials followed at trentreed.net ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -18,7 +18,7 @@ namespace Qtk { class QTKAPI Camera3D { public: /************************************************************************* - * Constants + * Static Public Constants ************************************************************************/ static const QVector3D LocalForward; @@ -29,39 +29,56 @@ namespace Qtk { * Accessors ************************************************************************/ + /** + * @return Transform3D associated with this camera. + */ inline Transform3D & getTransform() { return mTransform; } + /** + * @return Current translation of the camera as a QVector3D. + */ [[nodiscard]] inline const QVector3D & getTranslation() const { return mTransform.getTranslation(); } + /** + * @return Current rotation of this camera as a QQuaternion. + */ [[nodiscard]] inline const QQuaternion & getRotation() const { return mTransform.getRotation(); } - const QMatrix4x4 & toMatrix(); - - // Queries - [[nodiscard]] inline QVector3D forward() const { + /** + * @return QVector3D for the forward vector of the camera. + */ + [[nodiscard]] inline QVector3D getForward() const { return mTransform.getRotation().rotatedVector(LocalForward); } - [[nodiscard]] inline QVector3D right() const { + /** + * @return QVector3D for the right vector of the camera. + */ + [[nodiscard]] inline QVector3D getRight() const { return mTransform.getRotation().rotatedVector(LocalRight); } - [[nodiscard]] inline QVector3D up() const { + /** + * @return QVector3D for the up vector of the camera. + */ + [[nodiscard]] inline QVector3D getUp() const { return mTransform.getRotation().rotatedVector(LocalUp); } - private: /************************************************************************* - * Private Members + * Public Methods ************************************************************************/ - Transform3D mTransform; - QMatrix4x4 mWorld; + /** + * @return World To View matrix for this camera. + */ + const QMatrix4x4 & toMatrix(); + private: /************************************************************************* * Private Methods ************************************************************************/ @@ -70,6 +87,13 @@ namespace Qtk { friend QDataStream & operator<<(QDataStream & out, Camera3D & transform); friend QDataStream & operator>>(QDataStream & in, Camera3D & transform); #endif + + /************************************************************************* + * Private Members + ************************************************************************/ + + Transform3D mTransform; + QMatrix4x4 mWorld; }; // Qt Streams diff --git a/src/qtk/input.cpp b/src/qtk/input.cpp index 2be197a..91f7a71 100644 --- a/src/qtk/input.cpp +++ b/src/qtk/input.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Input class from tutorials followed at trentreed.net ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -18,6 +18,13 @@ using namespace Qtk; /******************************************************************************* * Static Helper Structs ******************************************************************************/ + + /** + * Struct to hold key input state. When a key is pressed we construct this and + * store it within a KeyContainer (or ButtonContainer for mouse buttons). + * + * @tparam T Qt::Key or Qt::MouseButton input type for this instance. + */ template struct InputInstance : std::pair { typedef std::pair base_class; @@ -28,6 +35,7 @@ template struct InputInstance : std::pair { inline InputInstance(T value, Input::InputState state) : base_class(value, state) {} + // Allows use of std::find to search for a key's InputInstance inline bool operator==(const InputInstance & rhs) const { return this->first == rhs.first; } @@ -53,14 +61,44 @@ static QPoint sg_mouseDelta; * Static Inline Helper Functions ******************************************************************************/ +/** + * Search for the InputInstance of a key. + * + * @param value The key to search for. + * @return Iterator to the found element or the end iterator if not found. + */ static inline KeyContainer::iterator FindKey(Qt::Key value) { return std::find(sg_keyInstances.begin(), sg_keyInstances.end(), value); } +/** + * Search for the InputInstance of a mouse button. + * + * @param value The mouse button to search for. + * @return Iterator to the found element or the end iterator if not found. + */ static inline ButtonContainer::iterator FindButton(Qt::MouseButton value) { return std::find(sg_buttonInstances.begin(), sg_buttonInstances.end(), value); } +/** + * Check an InputInstance for the InputReleased state. + * + * @tparam TPair KeyInstance or ButtonInstance + * @param instance Instance to check for InputReleased state. + * @return True if the InputInstance is in the released state. + */ +template +static inline bool CheckReleased(const TPair & instance) { + return instance.second == Input::InputReleased; +} + +/** + * Updates an InputInstance and applies transitions if needed. + * + * @tparam TPair KeyInstance or ButtonInstance. + * @param instance The InputInstance to update. + */ template static inline void UpdateStates(TPair & instance) { switch(instance.second) { case Input::InputRegistered: @@ -77,11 +115,12 @@ template static inline void UpdateStates(TPair & instance) { } } -template -static inline bool CheckReleased(const TPair & instance) { - return instance.second == Input::InputReleased; -} - +/** + * Updates InputInstance containers to track input state. + * + * @tparam Container The type of container, KeyContainer or ButtonContainer. + * @param container The InputInstance container to update. + */ template static inline void Update(Container & container) { typedef typename Container::iterator Iter; typedef typename Container::value_type TPair; @@ -96,27 +135,9 @@ template static inline void Update(Container & container) { } /******************************************************************************* - * Input Implementation + * Static Public Methods ******************************************************************************/ -Input::InputState Input::keyState(Qt::Key k) { - auto it = FindKey(k); - return (it != sg_keyInstances.end()) ? it->second : InputInvalid; -} - -Input::InputState Input::buttonState(Qt::MouseButton k) { - auto it = FindButton(k); - return (it != sg_buttonInstances.end()) ? it->second : InputInvalid; -} - -QPoint Input::mousePosition() { - return QCursor::pos(); -} - -QPoint Input::mouseDelta() { - return sg_mouseDelta; -} - void Input::update() { // Update Mouse Delta sg_mousePrevPosition = sg_mouseCurrPosition; @@ -160,3 +181,21 @@ void Input::reset() { sg_keyInstances.clear(); sg_buttonInstances.clear(); } + +Input::InputState Input::keyState(Qt::Key k) { + auto it = FindKey(k); + return (it != sg_keyInstances.end()) ? it->second : InputInvalid; +} + +Input::InputState Input::buttonState(Qt::MouseButton k) { + auto it = FindButton(k); + return (it != sg_buttonInstances.end()) ? it->second : InputInvalid; +} + +QPoint Input::mousePosition() { + return QCursor::pos(); +} + +QPoint Input::mouseDelta() { + return sg_mouseDelta; +} diff --git a/src/qtk/input.h b/src/qtk/input.h index 5873e0d..c11b392 100644 --- a/src/qtk/input.h +++ b/src/qtk/input.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Input class from tutorials followed at trentreed.net ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -22,60 +22,133 @@ namespace Qtk { ************************************************************************/ /** - * Possible key states + * Possible key states. See UpdateStates for state transitions. + * + * When a key is pressed we enter states Registered->Triggered->Pressed. + * InputTriggered state will be met only once if a key is pressed or held. + * While a key is held down the state is InputPressed. + * + * When a key is released we enter InputUnregistered->InputReleased + * When an active InputInstance for a key has this state it is removed. */ enum InputState { InputInvalid, - InputRegistered, - InputUnregistered, - InputTriggered, - InputPressed, - InputReleased + InputRegistered, // Initial state. Transitions to InputTriggered + InputUnregistered, // Transition to InputReleased + InputTriggered, // Transition to InputPressed + InputPressed, // State of a key while it is held down. + InputReleased // Released keys are removed from state containers. }; /************************************************************************* * Public Methods ************************************************************************/ - // State checking + // + // State updating. + + /** + * Update state for all mouse button and key instances. + */ + static void update(); + + /** + * @param key Key to set InputRegistered state. + */ + static void registerKeyPress(int key); + + /** + * @param key Key to set InputReleased state. + */ + static void registerKeyRelease(int key); + + /** + * @param button Mouse button to set InputRegistered state. + */ + static void registerMousePress(Qt::MouseButton button); + + /** + * @param button Mouse button to set InputReleased state. + */ + static void registerMouseRelease(Qt::MouseButton button); + + /** + * Reset input state for all key and mouse buttons. + */ + static void reset(); + + // + // State Checking. + + /** + * @param key Key to check state. + * @return True if the key is in InputTriggered state. + */ inline static bool keyTriggered(Qt::Key key) { return keyState(key) == InputTriggered; } + /** + * @param key Key to check state. + * @return True if the key is in InputPressed state. + */ inline static bool keyPressed(Qt::Key key) { return keyState(key) == InputPressed; } + /** + * @param key Key to check state. + * @return True if the key is in InputReleased state. + */ inline static bool keyReleased(Qt::Key key) { return keyState(key) == InputReleased; } + /** + * @param button Mouse button to check state. + * @return True if the key is in InputTriggered state. + */ inline static bool buttonTriggered(Qt::MouseButton button) { return buttonState(button) == InputTriggered; } + /** + * @param button Mouse button to check state. + * @return True if the key is in InputPressed state. + */ inline static bool buttonPressed(Qt::MouseButton button) { return buttonState(button) == InputPressed; } + /** + * @param button Mouse button to check state. + * @return True if the key is in InputReleased state. + */ inline static bool buttonReleased(Qt::MouseButton button) { return buttonState(button) == InputReleased; } - // Implementation + /** + * @param key The key to check InputState. + * @return The current InputState for the given key. + */ static InputState keyState(Qt::Key key); + + /** + * @param button The mouse button to check InputState. + * @return The current InputState for the mouse button. + */ static InputState buttonState(Qt::MouseButton button); + /** + * @return QPoint representing the mouse position within the widget. + */ static QPoint mousePosition(); - static QPoint mouseDelta(); - // State updating - static void update(); - static void registerKeyPress(int key); - static void registerKeyRelease(int key); - static void registerMousePress(Qt::MouseButton button); - static void registerMouseRelease(Qt::MouseButton button); - static void reset(); + /** + * @return Delta movement of mouse from previous to current position. + */ + static QPoint mouseDelta(); }; } // namespace Qtk diff --git a/src/qtk/meshrenderer.cpp b/src/qtk/meshrenderer.cpp index 66992ee..d88bc01 100644 --- a/src/qtk/meshrenderer.cpp +++ b/src/qtk/meshrenderer.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: MeshRenderer class for quick object creation and drawing ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -17,8 +17,20 @@ using namespace Qtk; // Static QHash that holds all MeshRenderer instances using their mName as keys Qtk::MeshRenderer::MeshManager Qtk::MeshRenderer::sInstances; +/******************************************************************************* + * Constructors / Destructors + ******************************************************************************/ + +MeshRenderer::MeshRenderer( + const char * name, Vertices vertices, Indices indices, DrawMode mode) : + MeshRenderer( + name, ShapeBase(mode, std::move(vertices), std::move(indices))) {} + +MeshRenderer::MeshRenderer(const char * name) : + MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS)) {} + MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) : - Object(name, shape, MESH), mVertexShader(":/multi-color.vert"), + Object(name, shape, QTK_MESH), mVertexShader(":/multi-color.vert"), mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES) { mShape = Shape(shape); init(); @@ -29,20 +41,8 @@ MeshRenderer::~MeshRenderer() { sInstances.remove(mName); } -// Static member function to retrieve instances of MeshRenderers -MeshRenderer * MeshRenderer::getInstance(const QString & name) { - if(!sInstances.contains(name)) { -#if QTK_DEBUG - qDebug() << "Attempt to access MeshRenderer instance that does not exist! (" - << qPrintable(name) << ")\n"; -#endif - return nullptr; - } - return sInstances[name]; -} - /******************************************************************************* - * Public Member Functions + * Public Methods ******************************************************************************/ void MeshRenderer::init() { @@ -123,33 +123,11 @@ void MeshRenderer::draw() { releaseShaders(); } -void MeshRenderer::setShaders( - const std::string & vert, const std::string & frag) { - mVertexShader = vert; - mFragmentShader = frag; - init(); -} - -void MeshRenderer::setUniformMVP( - const char * model, const char * view, const char * projection) { +void MeshRenderer::enableAttributeArray(int location) { ShaderBindScope lock(&mProgram, mBound); - mProgram.setUniformValue(projection, Scene::getProjectionMatrix()); - mProgram.setUniformValue(view, Scene::getViewMatrix()); - mProgram.setUniformValue(model, mTransform.toMatrix()); -} - -void MeshRenderer::setColor(const QVector3D & color) { - if(mShape.mColors.empty()) { - for(const auto & vertex : mShape.getVertices()) { - mShape.mColors.push_back(color); - } - } else { - for(int i = 0; i < mShape.getColors().size(); i++) { - mShape.mColors[i] = color; - } - } - // TODO: Factor this out so we don't need to reinitialize - init(); + mVAO.bind(); + mProgram.enableAttributeArray(location); + mVAO.release(); } void MeshRenderer::reallocateTexCoords(const TexCoords & t, unsigned dims) { @@ -185,11 +163,60 @@ void MeshRenderer::reallocateNormals(const Normals & n, unsigned dims) { mVAO.release(); } -/******************************************************************************* - * Inherited Virtual Member Functions - ******************************************************************************/ +void MeshRenderer::setShaders( + const std::string & vert, const std::string & frag) { + mVertexShader = vert; + mFragmentShader = frag; + init(); +} + +void MeshRenderer::setUniformMVP( + const char * model, const char * view, const char * projection) { + ShaderBindScope lock(&mProgram, mBound); + mProgram.setUniformValue(projection, Scene::getProjectionMatrix()); + mProgram.setUniformValue(view, Scene::getViewMatrix()); + mProgram.setUniformValue(model, mTransform.toMatrix()); +} void MeshRenderer::setShape(const Shape & value) { Object::setShape(value); init(); } + +void MeshRenderer::setColor(const QVector3D & color) { + if(mShape.mColors.empty()) { + for(const auto & vertex : mShape.getVertices()) { + mShape.mColors.push_back(color); + } + } else { + for(int i = 0; i < mShape.getColors().size(); i++) { + mShape.mColors[i] = color; + } + } + // TODO: Factor this out so we don't need to reinitialize + init(); +} + +void MeshRenderer::setAttributeBuffer( + int location, GLenum type, int offset, int tupleSize, int stride) { + ShaderBindScope lock(&mProgram, mBound); + mVAO.bind(); + mProgram.setAttributeBuffer(location, type, offset, tupleSize, stride); + mVAO.release(); +} + +/******************************************************************************* + * Static Public Methods + ******************************************************************************/ + +// Static member function to retrieve instances of MeshRenderers +MeshRenderer * MeshRenderer::getInstance(const QString & name) { + if(!sInstances.contains(name)) { +#if QTK_DEBUG + qDebug() << "Attempt to access MeshRenderer instance that does not exist! (" + << qPrintable(name) << ")\n"; +#endif + return nullptr; + } + return sInstances[name]; +} diff --git a/src/qtk/meshrenderer.h b/src/qtk/meshrenderer.h index a2e55b1..28a8fbb 100644 --- a/src/qtk/meshrenderer.h +++ b/src/qtk/meshrenderer.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: MeshRenderer class for quick object creation and drawing ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -10,9 +10,9 @@ #include -#include "mesh.h" #include "object.h" #include "qtkapi.h" +#include "shape.h" namespace Qtk { class QTKAPI MeshRenderer : public Object { @@ -21,93 +21,179 @@ namespace Qtk { * Typedefs ************************************************************************/ - /* Static QHash of all mesh objects within the scene. */ + /** Static QHash of all mesh objects within the scene. */ typedef QHash MeshManager; /************************************************************************* * Constructors / Destructors ************************************************************************/ - // Delegate constructors + /** + * Delegate constructor. + * Constructs a MeshRenderer with custom vertices and indices for more + * complex geometry. + * + * @param name Name to use for the new QObject. + * @param vertices Vertices to use for initializing geometry shape. + * @param indices Indicess to use for initializes geometry shape. + * @param mode OpenGL draw mode. Supported modes are prefixed with QTK_* + */ MeshRenderer( const char * name, Vertices vertices, Indices indices, - DrawMode mode = QTK_DRAW_ARRAYS) : - MeshRenderer( - name, ShapeBase(mode, std::move(vertices), std::move(indices))) {} + DrawMode mode = QTK_DRAW_ARRAYS); - explicit MeshRenderer(const char * name) : - MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS)) {} + /** + * Delegate constructor. + * Constructs a MeshRenderer with a default shape of a cube. + * + * @param name Name to use for the new QObject. + */ + explicit MeshRenderer(const char * name); - // Constructor + /** + * Construct a MeshRenderer. + * Default shaders will be used unless subsequently set by the caller. + * + * @param name Name to use for the new QObject. + * @param shape The shape of the MeshRenderer. + * For models this can be set using ShapeBase ctors. + */ MeshRenderer(const char * name, const ShapeBase & shape); - ~MeshRenderer() override; + + ~MeshRenderer(); /************************************************************************* * Public Methods ************************************************************************/ + /** + * Initializes OpenGL buffers and settings for this MeshRenderer. + */ void init(); + + /** + * Draws this MeshRenderer. + */ void draw(); - inline void enableAttributeArray(int location) { - ShaderBindScope lock(&mProgram, mBound); - mVAO.bind(); - mProgram.enableAttributeArray(location); - mVAO.release(); - } + /** + * Enables shader attribute array from the MeshRenderer's VAO. + * @param location Index location of the attribute array to enable. + */ + void enableAttributeArray(int location); + /** + * Reallocates texture coordinates to the mNBO member object. + * + * @param t Texture coordinates to reallocate. + * @param dims Number of dimensions to use for the coordinates. + */ void reallocateTexCoords(const TexCoords & t, unsigned dims = 2); + /** + * Reallocates normals to the mNBO member object. + * + * @param n Normal coordinate to reallocate. + * @param dims Number of dimensions to use for the coordinates. + */ void reallocateNormals(const Normals & n, unsigned dims = 3); /************************************************************************* * Setters ************************************************************************/ - // Draw types like GL_TRIANGLES, GL_POINTS, GL_LINES, etc - void setDrawType(int drawType) { mDrawType = drawType; } + /** + * Set OpenGL draw type. GL_TRIANGLES, GL_POINTS, GL_LINES, etc. + * + * @param drawType The draw type to use for this MeshRenderer. + */ + inline void setDrawType(int drawType) { mDrawType = drawType; } - // Shader settings + /** + * @param vert Path to vertex shader to use for this MeshRenderer. + */ inline void setShaderVertex(const std::string & vert) { mVertexShader = vert; } + /** + * @param frag Path to fragment shader to use for this MeshRenderer. + */ inline void setShaderFragment(const std::string & frag) { mFragmentShader = frag; } + /** + * @param vert Path to vertex shader to use for this MeshRenderer. + * @param frag Path to fragment shader to use for this MeshRenderer. + */ void setShaders(const std::string & vert, const std::string & frag); + /** + * @tparam T Type of the uniform value to set. + * @param location Index location of the uniform value we are setting. + * @param value The value to use for the uniform. + */ template inline void setUniform(int location, T value) { ShaderBindScope lock(&mProgram, mBound); mProgram.setUniformValue(location, value); } + /** + * @tparam T Type of the uniform value to set. + * @param location Name of the uniform value we are setting. + * @param value The value to use for the uniform. + */ template inline void setUniform(const char * location, T value) { ShaderBindScope lock(&mProgram, mBound); mProgram.setUniformValue(location, value); } - // Set MVP matrix using this Object's transform - // + View and projection provided by MainWidget static members + /** + * Sets the MVP matrices for this object within the scene. + * Model matrix is provided by this model's transform. + * View and Projection matrices are provided by the scene. + * + * @param model Name of the uniform to store the Model matrix. + * @param view Name of the uniform to store the View matrix. + * @param projection Name of the uniform to store the Projection matrix. + */ void setUniformMVP( const char * model = "uModel", const char * view = "uView", const char * projection = "uProjection"); - // These functions modify data stored in a VBO - // + After calling them, the VBO will need to be reallocated + /** + * Sets the shape of the MeshRenderer using the Object base class method. + * The MeshRenderer will be reinitialized after this call using `init()`. + * + * @param value Shape to use for this MeshRenderer. + */ void setShape(const Shape & value) override; + + /** + * Sets all vertices in the mesh to a color. + * The MeshRenderer will be reinitialized after this call using `init()`. + * + * @param color The color to use for the entire mesh. + */ void setColor(const QVector3D & color); + /** + * Updates an attribute buffer. This should be called whenever related + * buffers are reallocated. If the new buffer uses an identical format + * this may not be required. + * + * @param location Index location of the attribute buffer to set. + * @param type The type of the values within the attribute buffer. + * @param offset Offset to the beginning of the buffer. + * @param tupleSize Size of each group of elements in the buffer. + * For (x, y) positions this would be 2, (x, y, z) would be 3, etc. + * @param stride Stride between groups of elements in the buffer. + * For example (x, y) data stride is `2 * sizeof(type)` + */ void setAttributeBuffer( - int location, GLenum type, int offset, int tupleSize, - int stride = 0) { - ShaderBindScope lock(&mProgram, mBound); - mVAO.bind(); - mProgram.setAttributeBuffer(location, type, offset, tupleSize, stride); - mVAO.release(); - } + int location, GLenum type, int offset, int tupleSize, int stride = 0); /************************************************************************* * Accessors @@ -120,7 +206,10 @@ namespace Qtk { */ static MeshRenderer * getInstance(const QString & name); - Transform3D & getTransform() { return mTransform; } + /** + * @return Transform3D attached to this MeshRenderer. + */ + inline Transform3D & getTransform() { return mTransform; } private: /************************************************************************* diff --git a/src/qtk/model.cpp b/src/qtk/model.cpp index 5930319..0e071e4 100644 --- a/src/qtk/model.cpp +++ b/src/qtk/model.cpp @@ -1,7 +1,7 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## -## About: Model classes for importing with Assimp ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: Model class for importing with Assimp ## ## From following tutorials on learnopengl.com ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -15,145 +15,24 @@ using namespace Qtk; +/** Static QHash used to store and access models globally. */ Model::ModelManager Model::mManager; -// Static function to access ModelManager for getting Models by name -Model * Model::getInstance(const char * name) { - return mManager[name]; -} - /******************************************************************************* - * ModelMesh Private Member Functions - ******************************************************************************/ - -void ModelMesh::initMesh(const char * vert, const char * frag) { - initializeOpenGLFunctions(); - - // Create VAO, VBO, EBO - mVAO->create(); - mVBO->create(); - mEBO->create(); - - mVAO->bind(); - - // Allocate VBO - mVBO->setUsagePattern(QOpenGLBuffer::StaticDraw); - mVBO->bind(); - - mVBO->allocate(mVertices.data(), mVertices.size() * sizeof(mVertices[0])); - - // Allocate EBO - mEBO->setUsagePattern(QOpenGLBuffer::StaticDraw); - mEBO->bind(); - mEBO->allocate(mIndices.data(), mIndices.size() * sizeof(mIndices[0])); - mEBO->release(); - - // Load and link shaders - mProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, vert); - mProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, frag); - mProgram->link(); - mProgram->bind(); - - // Positions - mProgram->enableAttributeArray(0); - mProgram->setAttributeBuffer( - 0, GL_FLOAT, offsetof(ModelVertex, mPosition), 3, sizeof(ModelVertex)); - - // Normals - mProgram->enableAttributeArray(1); - mProgram->setAttributeBuffer( - 1, GL_FLOAT, offsetof(ModelVertex, mNormal), 3, sizeof(ModelVertex)); - - // Texture Coordinates - mProgram->enableAttributeArray(2); - mProgram->setAttributeBuffer( - 2, GL_FLOAT, offsetof(ModelVertex, mTextureCoord), 2, - sizeof(ModelVertex)); - - // Vertex tangents - mProgram->enableAttributeArray(3); - mProgram->setAttributeBuffer( - 3, GL_FLOAT, offsetof(ModelVertex, mTangent), 3, sizeof(ModelVertex)); - - // Vertex bitangents - mProgram->enableAttributeArray(4); - mProgram->setAttributeBuffer( - 4, GL_FLOAT, offsetof(ModelVertex, mBitangent), 3, sizeof(ModelVertex)); - - mProgram->release(); - mVBO->release(); - mVAO->release(); -} - -/******************************************************************************* - * ModelMesh Public Member Functions - ******************************************************************************/ - -void ModelMesh::draw(QOpenGLShaderProgram & shader) { - mVAO->bind(); - // Bind shader - shader.bind(); - - // Set Model View Projection values - shader.setUniformValue("uModel", mTransform.toMatrix()); - shader.setUniformValue("uView", Scene::getViewMatrix()); - shader.setUniformValue("uProjection", Scene::getProjectionMatrix()); - - GLuint diffuseCount = 1; - GLuint specularCount = 1; - GLuint normalCount = 1; - for(GLuint i = 0; i < mTextures.size(); i++) { - // Activate the current texture index by adding offset to GL_TEXTURE0 - glActiveTexture(GL_TEXTURE0 + i); - mTextures[i].mTexture->bind(); - - // Get a name for the texture using a known convention - - // Diffuse: material.texture_diffuse1, material.texture_diffuse2, ... - // Specular: material.texture_specular1, material.texture_specular2, ... - std::string number; - std::string name = mTextures[i].mType; - if(name == "texture_diffuse") { - number = std::to_string(diffuseCount++); - } - if(name == "texture_specular") { - number = std::to_string(specularCount++); - } - if(name == "texture_normal") { - number = std::to_string(normalCount++); - } - - // Set the uniform to track this texture ID using our naming convention - shader.setUniformValue((name + number).c_str(), i); - } - - // Draw the mesh - glDrawElements( - GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data()); - - // Release shader, textures - for(const auto & texture : mTextures) { - texture.mTexture->release(); - } - shader.release(); - mVAO->release(); - glActiveTexture(GL_TEXTURE0); -} - -/******************************************************************************* - * Model Public Member Functions + * Public Member Functions ******************************************************************************/ void Model::draw() { - for(auto & mMeshe : mMeshes) { - mMeshe.mTransform = mTransform; - mMeshe.draw(); + for(auto & mesh : mMeshes) { + mesh.mTransform = mTransform; + mesh.draw(); } } void Model::draw(QOpenGLShaderProgram & shader) { - for(auto & mMeshe : mMeshes) { - mMeshe.mTransform = mTransform; - mMeshe.draw(shader); + for(auto & mesh : mMeshes) { + mesh.mTransform = mTransform; + mesh.draw(shader); } } @@ -175,8 +54,13 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) { } } +// Static function to access ModelManager for getting Models by name +Model * Qtk::Model::getInstance(const char * name) { + return mManager[name]; +} + /******************************************************************************* - * Model Private Member Functions + * Private Member Functions ******************************************************************************/ void Model::loadModel(const std::string & path) { @@ -210,7 +94,7 @@ void Model::loadModel(const std::string & path) { // Sort models by their distance from the camera // Optimizes drawing so that overlapping objects are not overwritten // + Since the topmost object will be drawn first - sortModels(); + sortModelMeshes(); // Object finished loading, insert it into ModelManager mManager.insert(getName(), this); @@ -362,7 +246,7 @@ ModelMesh::Textures Model::loadMaterialTextures( return textures; } -void Model::sortModels() { +void Model::sortModelMeshes() { auto cameraPos = Scene::getCamera().getTransform(); auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) { // Sort by the first vertex position in the model diff --git a/src/qtk/model.h b/src/qtk/model.h index e2c5dbd..d3e74eb 100644 --- a/src/qtk/model.h +++ b/src/qtk/model.h @@ -1,7 +1,7 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## -## About: Model classes for importing with Assimp ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: Model class for importing with Assimp ## ## From following tutorials on learnopengl.com ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -9,115 +9,19 @@ #ifndef QTK_MODEL_H #define QTK_MODEL_H -// QT -#include -#include +// Qt #include -#include -#include -#include // Assimp #include #include #include -// QTK -#include "object.h" +// Qtk +#include "modelmesh.h" #include "qtkapi.h" -#include "transform3D.h" namespace Qtk { - /** - * 3D models will store this data for each vertex in geometry. - */ - struct QTKAPI ModelVertex { - QVector3D mPosition; - QVector3D mNormal; - QVector2D mTextureCoord; - QVector3D mTangent; - QVector3D mBitangent; - }; - - /** - * Struct to store model textures. 3D Models may have multiple. - */ - struct QTKAPI ModelTexture { - GLuint mID {}; - QOpenGLTexture * mTexture {}; - std::string mType {}; - std::string mPath {}; - }; - - class Model; - - /** - * Mesh class specialized for storing 3D model data. - * Eventually this can be consolidated into a more generic class. - */ - class QTKAPI ModelMesh : protected QOpenGLFunctions { - public: - /************************************************************************* - * Typedefs - ************************************************************************/ - - friend Model; - typedef std::vector Vertices; - typedef std::vector Indices; - typedef std::vector Textures; - - /************************************************************************* - * Constructors, Destructors - ************************************************************************/ - - ModelMesh( - Vertices vertices, Indices indices, Textures textures, - const char * vertexShader = ":/model-basic.vert", - const char * fragmentShader = ":/model-basic.frag") : - mProgram(new QOpenGLShaderProgram), - mVAO(new QOpenGLVertexArrayObject), - mVBO(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)), - mEBO(new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer)), - mVertices(std::move(vertices)), mIndices(std::move(indices)), - mTextures(std::move(textures)) { - initMesh(vertexShader, fragmentShader); - } - - ~ModelMesh() = default; - - /************************************************************************* - * Public Methods - ************************************************************************/ - - inline void draw() { draw(*mProgram); } - - void draw(QOpenGLShaderProgram & shader); - - /************************************************************************* - * Public Members - ************************************************************************/ - - Vertices mVertices {}; - Indices mIndices {}; - Textures mTextures {}; - Transform3D mTransform; - - private: - /************************************************************************* - * Private Methods - ************************************************************************/ - - void initMesh(const char * vert, const char * frag); - - /************************************************************************* - * Private Members - ************************************************************************/ - - QOpenGLBuffer *mVBO, *mEBO; - QOpenGLVertexArrayObject * mVAO; - QOpenGLShaderProgram * mProgram; - }; - /** * Model object that has a ModelMesh. * Top-level object that represents 3D models stored within a scene. @@ -128,19 +32,27 @@ namespace Qtk { * Typedefs ************************************************************************/ - /* ModelManager typedef that will manage global model access. */ + /** ModelManager typedef that will manage global model access. */ typedef QHash ModelManager; /************************************************************************* * Constructors, Destructors ************************************************************************/ - // Default model shaders are provided but we can override them in the ctor + /** + * Constructs a Model + * If no shaders are provided we will use default shaders. + * + * @param name Name to use for the Model's objectName. + * @param path Path to the model to load for construction. + * @param vertexShader Optional path to custom vertex shader. + * @param fragmentShader Optional path to custom fragment shader. + */ inline Model( const char * name, const char * path, const char * vertexShader = ":/model-basic.vert", const char * fragmentShader = ":/model-basic.frag") : - Object(name, MODEL), + Object(name, QTK_MODEL), mModelPath(path), mVertexShader(vertexShader), mFragmentShader(fragmentShader) { loadModel(mModelPath); @@ -152,7 +64,16 @@ namespace Qtk { * Public Methods ************************************************************************/ + /** + * Draws the model using attached shader program. + */ void draw(); + + /** + * Draws the model using a custom shader program. + * + * @param shader Shader program to use to draw the model. + */ void draw(QOpenGLShaderProgram & shader); /** @@ -170,13 +91,13 @@ namespace Qtk { ************************************************************************/ /** - * Sets a uniform value + * Sets a uniform value for each ModelMesh within this Model. * * @tparam T The type of the value we are settings * @param location The uniform location * @param value The value to assign to the uniform */ - template void setUniform(const char * location, T value) { + template inline void setUniform(const char * location, T value) { for(auto & mesh : mMeshes) { mesh.mProgram->bind(); mesh.mProgram->setUniformValue(location, value); @@ -195,9 +116,12 @@ namespace Qtk { * @param name The name of the model to load as it was constructed. * @return Pointer to the model stored within the scene. */ - static Model * getInstance(const char * name); + [[nodiscard]] static Model * getInstance(const char * name); - Transform3D & getTransform() { return mTransform; } + /** + * @return Transform3D attached to this Model. + */ + inline Transform3D & getTransform() { return mTransform; } private: /************************************************************************* @@ -209,44 +133,69 @@ namespace Qtk { * For a full list of formats see assimp documentation: * https://github.com/assimp/assimp/blob/master/doc/Fileformats.md * - * Models should not be loaded into Qt resource system. + * Large models should not be loaded into Qt resource system. * Instead pass an *absolute* path to this function. * Relative paths will break if Qtk is executed from different locations. * - * Models can also be loaded from the `qtk/resource` directory using qrc - * format loadModel(":/models/backpack/backpack.obj"). - * This does not use Qt resource system, it just provides similar syntax - * for accessing files within the same `resources/` directory. - * - * See resourcemanager.h for more information on how this works. - * * @param path Absolute path to a model in .obj or another format accepted * by assimp. */ void loadModel(const std::string & path); + /** + * Process a node in the model's geometry using Assimp. + * + * @param node The Assimp node to process. + * @param scene The Assimp scene for the loaded model. + */ void processNode(aiNode * node, const aiScene * scene); + /** + * Process a mesh within a node using Assimp. + * + * @param mesh The Assimp mesh to process. + * @param scene The Assimp scene for the loaded model. + * @return + */ ModelMesh processMesh(aiMesh * mesh, const aiScene * scene); + /** + * Load a collection of material texture using Assimp. + * This function loads diffuse, specular, and narmal material textures. + * A Mesh may have many of any or all of the texture types above. + * Models can have many Meshes attached. + * This function returns all textures for a single Mesh within a Model. + * + * @param mat Loaded Assimp material. + * @param type Type of the material. + * @param typeName Texture type name in string format. + * @return Collection of all textures for a single ModelMesh. + */ ModelMesh::Textures loadMaterialTextures( aiMaterial * mat, aiTextureType type, const std::string & typeName); - void sortModels(); + /** + * Sorts each mesh in the Model based on distance from the camera. + * This is for efficient drawing in OpenGL by preventing the drawing of + * objects not visible due to being partially or entirely behind another + * object. + */ + void sortModelMeshes(); /************************************************************************* * Private Members ************************************************************************/ - /* Static QHash used to store and access models globally. */ + + /** Static QHash used to store and access models globally. */ static ModelManager mManager; - /* Container to store N loaded textures for this model. */ + /** Container to store N loaded textures for this model. */ ModelMesh::Textures mTexturesLoaded {}; - /* Container to store N loaded meshes for this model. */ + /** Container to store N loaded meshes for this model. */ std::vector mMeshes {}; - /* The directory this model and it's textures are stored. */ + /** The directory this model and it's textures are stored. */ std::string mDirectory {}; - /* File names for shaders and 3D model on disk. */ + /** File names for shaders and 3D model on disk. */ const char *mVertexShader, *mFragmentShader, *mModelPath; }; } // namespace Qtk diff --git a/src/qtk/modelmesh.cpp b/src/qtk/modelmesh.cpp new file mode 100644 index 0000000..341f282 --- /dev/null +++ b/src/qtk/modelmesh.cpp @@ -0,0 +1,129 @@ +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: ModelMesh class for importing 3D models with Assimp ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +##############################################################################*/ + +#include "scene.h" +#include "modelmesh.h" + +using namespace Qtk; + +/******************************************************************************* + * Public Member Functions + ******************************************************************************/ + +void ModelMesh::draw(QOpenGLShaderProgram & shader) { + mVAO->bind(); + // Bind shader + shader.bind(); + + // Set Model View Projection values + shader.setUniformValue("uModel", mTransform.toMatrix()); + shader.setUniformValue("uView", Scene::getViewMatrix()); + shader.setUniformValue("uProjection", Scene::getProjectionMatrix()); + + GLuint diffuseCount = 1; + GLuint specularCount = 1; + GLuint normalCount = 1; + for(GLuint i = 0; i < mTextures.size(); i++) { + // Activate the current texture index by adding offset to GL_TEXTURE0 + glActiveTexture(GL_TEXTURE0 + i); + mTextures[i].mTexture->bind(); + + // Get a name for the texture using a known convention - + // Diffuse: material.texture_diffuse1, material.texture_diffuse2, ... + // Specular: material.texture_specular1, material.texture_specular2, ... + std::string number; + std::string name = mTextures[i].mType; + if(name == "texture_diffuse") { + number = std::to_string(diffuseCount++); + } + if(name == "texture_specular") { + number = std::to_string(specularCount++); + } + if(name == "texture_normal") { + number = std::to_string(normalCount++); + } + + // Set the uniform to track this texture ID using our naming convention + shader.setUniformValue((name + number).c_str(), i); + } + + // Draw the mesh + glDrawElements( + GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data()); + + // Release shader, textures + for(const auto & texture : mTextures) { + texture.mTexture->release(); + } + shader.release(); + mVAO->release(); + glActiveTexture(GL_TEXTURE0); +} + +/******************************************************************************* + * Private Member Functions + ******************************************************************************/ + +void ModelMesh::initMesh(const char * vert, const char * frag) { + initializeOpenGLFunctions(); + + // Create VAO, VBO, EBO + mVAO->create(); + mVBO->create(); + mEBO->create(); + + mVAO->bind(); + + // Allocate VBO + mVBO->setUsagePattern(QOpenGLBuffer::StaticDraw); + mVBO->bind(); + + mVBO->allocate(mVertices.data(), mVertices.size() * sizeof(mVertices[0])); + + // Allocate EBO + mEBO->setUsagePattern(QOpenGLBuffer::StaticDraw); + mEBO->bind(); + mEBO->allocate(mIndices.data(), mIndices.size() * sizeof(mIndices[0])); + mEBO->release(); + + // Load and link shaders + mProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, vert); + mProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, frag); + mProgram->link(); + mProgram->bind(); + + // Positions + mProgram->enableAttributeArray(0); + mProgram->setAttributeBuffer( + 0, GL_FLOAT, offsetof(ModelVertex, mPosition), 3, sizeof(ModelVertex)); + + // Normals + mProgram->enableAttributeArray(1); + mProgram->setAttributeBuffer( + 1, GL_FLOAT, offsetof(ModelVertex, mNormal), 3, sizeof(ModelVertex)); + + // Texture Coordinates + mProgram->enableAttributeArray(2); + mProgram->setAttributeBuffer( + 2, GL_FLOAT, offsetof(ModelVertex, mTextureCoord), 2, + sizeof(ModelVertex)); + + // Vertex tangents + mProgram->enableAttributeArray(3); + mProgram->setAttributeBuffer( + 3, GL_FLOAT, offsetof(ModelVertex, mTangent), 3, sizeof(ModelVertex)); + + // Vertex bitangents + mProgram->enableAttributeArray(4); + mProgram->setAttributeBuffer( + 4, GL_FLOAT, offsetof(ModelVertex, mBitangent), 3, sizeof(ModelVertex)); + + mProgram->release(); + mVBO->release(); + mVAO->release(); +} diff --git a/src/qtk/modelmesh.h b/src/qtk/modelmesh.h new file mode 100644 index 0000000..1a30a07 --- /dev/null +++ b/src/qtk/modelmesh.h @@ -0,0 +1,138 @@ +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## +## About: ModelMesh class for importing 3D models with Assimp ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +##############################################################################*/ + +#ifndef QTK_MODELMESH_H +#define QTK_MODELMESH_H + +// QTK +#include "object.h" +#include "transform3D.h" + +namespace Qtk { + /** + * 3D models will store this data for each vertex in geometry. + */ + struct QTKAPI ModelVertex { + QVector3D mPosition; + QVector3D mNormal; + QVector2D mTextureCoord; + QVector3D mTangent; + QVector3D mBitangent; + }; + + /** + * Struct to store model textures. 3D Models may have multiple. + */ + struct QTKAPI ModelTexture { + /** Texture ID for for this texture. */ + GLuint mID {}; + QOpenGLTexture * mTexture {}; + + /** + * Type of this texture in string format. + * See calls to Model::loadMaterialTexture in Model::processMesh + */ + std::string mType {}; + /** Path to the model on disk. */ + std::string mPath {}; + }; + + class Model; + + /** + * Mesh class specialized for storing 3D model data. + * Eventually this can be consolidated into a more generic class. + */ + class QTKAPI ModelMesh : protected QOpenGLFunctions { + public: + /************************************************************************* + * Typedefs + ************************************************************************/ + + friend Model; + typedef std::vector Vertices; + typedef std::vector Indices; + typedef std::vector Textures; + + /************************************************************************* + * Constructors, Destructors + ************************************************************************/ + + /** + * Construct a ModelMesh. + * If no shaders are provided defaults will be used. + * + * @param vertices Vertex data to use for this ModelMesh. + * @param indices Index data to use for this ModelMesh. + * @param textures Collection of ModelTextures for this ModelMesh. + * @param vertexShader Path to vertex shader for this ModelMesh. + * @param fragmentShader Path to fragment shader for this ModelMesh. + */ + ModelMesh( + Vertices vertices, Indices indices, Textures textures, + const char * vertexShader = ":/model-basic.vert", + const char * fragmentShader = ":/model-basic.frag") : + mProgram(new QOpenGLShaderProgram), + mVAO(new QOpenGLVertexArrayObject), + mVBO(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)), + mEBO(new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer)), + mVertices(std::move(vertices)), mIndices(std::move(indices)), + mTextures(std::move(textures)) { + initMesh(vertexShader, fragmentShader); + } + + ~ModelMesh() = default; + + /************************************************************************* + * Public Methods + ************************************************************************/ + + /** + * Draw the model with the attached shader program. + */ + inline void draw() { draw(*mProgram); } + + /** + * Draw the model with a custom shader program. + * @param shader The shader program to use for drawing the object. + */ + void draw(QOpenGLShaderProgram & shader); + + /************************************************************************* + * Public Members + ************************************************************************/ + + Vertices mVertices {}; + Indices mIndices {}; + Textures mTextures {}; + Transform3D mTransform; + + private: + /************************************************************************* + * Private Methods + ************************************************************************/ + + /** + * Initializes the buffers and shaders for this model mesh. + * + * @param vert Path to vertex shader to use for this model. + * @param frag Path to fragment shader to use for this model. + */ + void initMesh(const char * vert, const char * frag); + + /************************************************************************* + * Private Members + ************************************************************************/ + + QOpenGLBuffer *mVBO, *mEBO; + QOpenGLVertexArrayObject * mVAO; + QOpenGLShaderProgram * mProgram; + }; +} // namespace Qtk + +#endif // QTK_MODELMESH_H diff --git a/src/qtk/object.cpp b/src/qtk/object.cpp index ea44ab2..7c9993e 100644 --- a/src/qtk/object.cpp +++ b/src/qtk/object.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Object class for storing object data ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## diff --git a/src/qtk/object.h b/src/qtk/object.h index 0e99bc2..c0955ab 100644 --- a/src/qtk/object.h +++ b/src/qtk/object.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Object class for storing object data ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -13,8 +13,8 @@ #include #include -#include "mesh.h" #include "qtkapi.h" +#include "shape.h" #include "texture.h" namespace Qtk { @@ -38,7 +38,7 @@ namespace Qtk { /** * Enum flag to identify Object type without casting. */ - enum Type { OBJECT, MESH, MODEL }; + enum Type { QTK_OBJECT, QTK_MESH, QTK_MODEL }; /************************************************************************* * Constructors / Destructors @@ -47,12 +47,16 @@ namespace Qtk { // Initialize an object with no shape data assigned explicit Object(const char * name, Type type) : mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false), - mType(type) {} + mType(type) { + setObjectName(name); + } // Initialize an object with shape data assigned Object(const char * name, const ShapeBase & shape, Type type) : mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape), - mBound(false), mType(type) {} + mBound(false), mType(type) { + setObjectName(name); + } ~Object() override = default; @@ -156,7 +160,7 @@ namespace Qtk { Texture mTexture; const char * mName; bool mBound; - Type mType = OBJECT; + Type mType = QTK_OBJECT; }; } // namespace Qtk diff --git a/src/qtk/qtkapi.h b/src/qtk/qtkapi.h index d5f5968..5f52438 100644 --- a/src/qtk/qtkapi.h +++ b/src/qtk/qtkapi.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Main window for Qt6 OpenGL widget application ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -8,6 +8,7 @@ #ifndef QTK_QTKAPI_H #define QTK_QTKAPI_H +#include #include #include @@ -41,8 +42,11 @@ namespace Qtk { return widget; } + /** + * @return Default icon to use for Qtk desktop application. + */ static QIcon getIcon() { - return QIcon(":/icon.png"); + return QIcon(":/icons/resources/icon.png"); } } // namespace Qtk diff --git a/src/qtk/scene.cpp b/src/qtk/scene.cpp index 8495c4e..08cc2b3 100644 --- a/src/qtk/scene.cpp +++ b/src/qtk/scene.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Classes for managing objects and data within a scene ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -15,7 +15,7 @@ Camera3D Scene::mCamera; QMatrix4x4 Scene::mProjection; /******************************************************************************* - * Constructors, Destructors + * Constructors / Destructors ******************************************************************************/ Scene::Scene() : mSceneName("Default Scene") { @@ -34,7 +34,7 @@ Scene::~Scene() { } /******************************************************************************* - * Accessors + * Public Methods ******************************************************************************/ std::vector Scene::getObjects() const { @@ -49,9 +49,14 @@ std::vector Scene::getObjects() const { return objects; } -/******************************************************************************* - * Setters - ******************************************************************************/ +Object * Scene::getObject(const QString & name) { + for(auto object : getObjects()) { + if(object->getName() == name) { + return object; + } + } + return Q_NULLPTR; +} void Scene::setSkybox(Skybox * skybox) { delete mSkybox; @@ -90,12 +95,3 @@ void Scene::privateDraw() { mesh->draw(); } } - -Object * Scene::getObject(const QString & name) { - for(auto object : getObjects()) { - if(object->getName() == name) { - return object; - } - } - return Q_NULLPTR; -} diff --git a/src/qtk/scene.h b/src/qtk/scene.h index 2cbc994..4971251 100644 --- a/src/qtk/scene.h +++ b/src/qtk/scene.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Classes for managing objects and data within a scene ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -78,25 +78,43 @@ namespace Qtk { * Accessors ************************************************************************/ + /** + * @return All Qtk::Objects within the scene. + * If any object is invalid, we return an empty vector. + */ + [[nodiscard]] std::vector getObjects() const; + + /** + * Retrieve and object from the scene by it's objectName. + * + * @param name The objectName to look for within this scene. + * @return The found object or Q_NULLPTR if none found. + */ + [[nodiscard]] Object * getObject(const QString & name); + /** * @return Camera attached to this scene. */ - static Camera3D & getCamera() { return mCamera; } + [[nodiscard]] inline static Camera3D & getCamera() { return mCamera; } /** * @return View matrix for the camera attached to this scene. */ - static QMatrix4x4 getViewMatrix() { return mCamera.toMatrix(); } + [[nodiscard]] inline static QMatrix4x4 getViewMatrix() { + return mCamera.toMatrix(); + } /** * @return Projection matrix for the current view into the scene. */ - static QMatrix4x4 & getProjectionMatrix() { return mProjection; } + [[nodiscard]] inline static QMatrix4x4 & getProjectionMatrix() { + return mProjection; + } /** * @return The active skybox for this scene. */ - inline Skybox * getSkybox() { return mSkybox; } + [[nodiscard]] inline Skybox * getSkybox() { return mSkybox; } /** * @return The name for this scene. This is entirely user defined and not @@ -119,14 +137,6 @@ namespace Qtk { return mModels; } - /** - * @return All Qtk::Objects within the scene. - * If any object is invalid, we return an empty vector. - */ - [[nodiscard]] std::vector getObjects() const; - - [[nodiscard]] Object * getObject(const QString & name); - /************************************************************************* * Setters ************************************************************************/ @@ -138,6 +148,13 @@ namespace Qtk { /** * Adds objects to the scene. + * This template provides explicit specializations for valid types. + * Adding any object other than these types will cause errors. + * TODO: Refactor to use Object base class container for scene objects. + * + * If creating a new object type for a scene, it must inherit Qtk::Object + * and provide a specialization for this method. + * * @param object The new object to add to the scene. * @return The object added to the scene. */ @@ -149,17 +166,15 @@ namespace Qtk { inline void setSceneName(QString name) { mSceneName = std::move(name); } signals: + /** + * Signal thrown when the scene is modified by adding or removing objects. + * This can be caught by a main application to update any associated data. + * + * @param sceneName The scene that has been updated. + */ void sceneUpdated(QString sceneName); private: - /************************************************************************* - * Private Members - ************************************************************************/ - - static Camera3D mCamera; - static QMatrix4x4 mProjection; - bool mInit = false; - /************************************************************************* * Private Methods ************************************************************************/ @@ -170,11 +185,14 @@ namespace Qtk { */ void privateDraw(); - private: /************************************************************************* * Private Members ************************************************************************/ + static Camera3D mCamera; + static QMatrix4x4 mProjection; + bool mInit = false; + QString mSceneName; /* The skybox for this scene. */ Skybox * mSkybox {}; diff --git a/src/qtk/mesh.cpp b/src/qtk/shape.cpp similarity index 99% rename from src/qtk/mesh.cpp rename to src/qtk/shape.cpp index 3af81c9..8880e2d 100644 --- a/src/qtk/mesh.cpp +++ b/src/qtk/shape.cpp @@ -1,12 +1,12 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Collection of static mesh data for quick initialization ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ -#include "mesh.h" +#include "shape.h" using namespace Qtk; diff --git a/src/qtk/mesh.h b/src/qtk/shape.h similarity index 84% rename from src/qtk/mesh.h rename to src/qtk/shape.h index 819e386..ab97dcf 100644 --- a/src/qtk/mesh.h +++ b/src/qtk/shape.h @@ -1,12 +1,12 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Collection of static mesh data for quick initialization ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ -#ifndef QTK_MESH_H -#define QTK_MESH_H +#ifndef QTK_SHAPE_H +#define QTK_SHAPE_H #include @@ -17,11 +17,6 @@ #include "qtkapi.h" #include "transform3D.h" -namespace Qtk { - class MeshRenderer; - - class Object; - // Define vertices for drawing a cube using two faces (8 vertex points) // Front Vertices #define VERTEX_FTR QVector3D(0.5f, 0.5f, 0.5f) // 1 @@ -63,7 +58,6 @@ namespace Qtk { VECTOR_BACK, VECTOR_BACK, VECTOR_BACK // clang-format on - // Colors using QVector3Ds as RGB values #define WHITE VECTOR_ONE #define BLACK VECTOR_ZERO @@ -79,6 +73,11 @@ namespace Qtk { #define UV_RIGHT QVector2D(0.0f, 1.0f) #define UV_CORNER QVector2D(1.0f, 1.0f) +namespace Qtk { + class MeshRenderer; + + class Object; + // TODO: Vertices.getData(); Vertices.getStride(); typedef std::vector Vertices; typedef std::vector Colors; @@ -106,6 +105,15 @@ namespace Qtk { * Constructors / Destructors ************************************************************************/ + /** + * + * @param mode OpenGL draw mode to use for this shape. + * @param v Vertex data for this shape. + * @param i Index data for this shape. + * @param c Color data for this shape. + * @param t Texture coordinates for this shape. + * @param n Normals for this shape. + */ explicit ShapeBase( DrawMode mode = QTK_DRAW_ARRAYS, Vertices v = {}, Indices i = {}, Colors c = {}, TexCoords t = {}, Normals n = {}) : @@ -118,24 +126,42 @@ namespace Qtk { * Accessors ************************************************************************/ + /** + * @return Vertex data for this shape. + */ [[nodiscard]] inline const Vertices & getVertices() const { return mVertices; } + /** + * @return Index data for this shape. + */ [[nodiscard]] inline const Indices & getIndexData() const { return mIndices; } + /** + * @return Color data for this shape. + */ [[nodiscard]] inline const Colors & getColors() const { return mColors; } + /** + * @return Texture coordinates for this shape. + */ [[nodiscard]] inline const TexCoords & getTexCoords() const { return mTexCoords; } + /** + * @return Normals for this shape. + */ [[nodiscard]] inline const Normals & getNormals() const { return mNormals; } + /** + * @return Stride for texture coordinates on this shape. + */ [[nodiscard]] inline size_t getTexCoordsStride() const { return mTexCoords.size() * sizeof(mTexCoords[0]); } @@ -146,7 +172,6 @@ namespace Qtk { ************************************************************************/ DrawMode mDrawMode; - Vertices mVertices {}; Colors mColors {}; Indices mIndices {}; @@ -161,6 +186,7 @@ namespace Qtk { ************************************************************************/ friend MeshRenderer; + friend Object; /************************************************************************* @@ -175,30 +201,45 @@ namespace Qtk { * Setters ************************************************************************/ + /** + * @param value Vertex data to use for this shape. + */ virtual inline void setVertices(const Vertices & value) { mVertices = value; } + /** + * @param value Index data to use for this shape. + */ virtual inline void setIndices(const Indices & value) { mIndices = value; } + /** + * @param value Color data to use for this shape. + */ virtual inline void setColors(const Colors & value) { mColors = value; } + /** + * @param value Texture coordinates to use for this shape. + */ virtual inline void setTexCoords(const TexCoords & value) { mTexCoords = value; } + /** + * @param value Normals to use for this shape. + */ virtual inline void setNormals(const Normals & value) { mNormals = value; } + /** + * @param value Shape to copy into this Shape. + */ virtual inline void setShape(const Shape & value) { *this = value; } }; - /* Primitives inherit from ShapeBase, doesn't allow setting shape values. */ - class QTKAPI Mesh {}; - /* Simple Cube shape. */ struct QTKAPI Cube : public ShapeBase { explicit Cube(DrawMode mode = QTK_DRAW_ARRAYS); @@ -210,4 +251,4 @@ namespace Qtk { }; } // namespace Qtk -#endif // QTK_MESH_H +#endif // QTK_SHAPE_H diff --git a/src/qtk/skybox.cpp b/src/qtk/skybox.cpp index 62168cb..8eb19cd 100644 --- a/src/qtk/skybox.cpp +++ b/src/qtk/skybox.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Skybox class using QtOpenGL ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -12,6 +12,20 @@ using namespace Qtk; +/******************************************************************************* + * Constructors / Destructors + ******************************************************************************/ + +Skybox::Skybox(const std::string & name) : + Skybox( + ":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png", + ":/back.png", name) {} + +Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) { + mTexture.setTexture(cubeMap); + init(); +} + Skybox::Skybox( const std::string & right, const std::string & top, const std::string & front, const std::string & left, @@ -27,16 +41,6 @@ Skybox::Skybox( QImage(back.c_str())); } -Skybox::Skybox(const std::string & name) : - Skybox( - ":/right.png", ":/top.png", ":/front.png", ":/left.png", ":/bottom.png", - ":/back.png", name) {} - -Skybox::Skybox(QOpenGLTexture * cubeMap, const std::string & name) { - mTexture.setTexture(cubeMap); - init(); -} - /******************************************************************************* * Public Member Functions ******************************************************************************/ diff --git a/src/qtk/skybox.h b/src/qtk/skybox.h index 7a3b99c..3a15738 100644 --- a/src/qtk/skybox.h +++ b/src/qtk/skybox.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Skybox class using QtOpenGL ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -16,8 +16,8 @@ #include #include "camera3d.h" -#include "mesh.h" #include "qtkapi.h" +#include "shape.h" #include "texture.h" namespace Qtk { @@ -33,11 +33,35 @@ namespace Qtk { ************************************************************************/ // Delegate this constructor to use default skybox images + + /** + * Construct Skybox using default images. + * + * @param name The objectName to use for the Skybox. + */ explicit Skybox(const std::string & name = "Skybox"); + /** + * Construct a skybox with an existing QOpenGLTexture. + * The texture should be a fully initialized cube map. + * + * @param cubeMap QOpenGLTexture to use for the new Skybox. + * @param name The objectName to use for the Skybox. + */ explicit Skybox( QOpenGLTexture * cubeMap, const std::string & name = "Skybox"); + /** + * Construct a Skybox. + * + * @param right Image to use for the right side of the Skybox. + * @param top Image to use for the top side of the Skybox. + * @param front Image to use for the front side of the Skybox. + * @param left Image to use for the left side of the Skybox. + * @param bottom Image to use for the bottom side of the Skybox. + * @param back Image to use for the back side of the Skybox. + * @param name The objectName to use for this Skybox. + */ Skybox( const std::string & right, const std::string & top, const std::string & front, const std::string & left, @@ -50,6 +74,9 @@ namespace Qtk { * Public Methods ************************************************************************/ + /** + * Draws the skybox. + */ void draw(); private: @@ -57,6 +84,9 @@ namespace Qtk { * Private Methods ************************************************************************/ + /** + * Initializes OpenGL buffers and shaders for this skybox. + */ void init(); /************************************************************************* diff --git a/src/qtk/texture.cpp b/src/qtk/texture.cpp index 003faef..fe71b1a 100644 --- a/src/qtk/texture.cpp +++ b/src/qtk/texture.cpp @@ -1,13 +1,11 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Texture class to help with texture and image initializations ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## ##############################################################################*/ -#include - #include #include @@ -59,9 +57,7 @@ QOpenGLTexture * OpenGLTextureFactory::initCubeMap( const QImage & right, const QImage & top, const QImage & front, const QImage & left, const QImage & bottom, const QImage & back) { auto texture = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap); - std::vector faceTextures = {std::move(right), std::move(top), - std::move(front), std::move(left), - std::move(bottom), std::move(back)}; + std::vector faceTextures = {right, top, front, left, bottom, back}; // Initialize skybox cubemap texture texture->create(); texture->bind(); diff --git a/src/qtk/texture.h b/src/qtk/texture.h index 2593c40..19ea18b 100644 --- a/src/qtk/texture.h +++ b/src/qtk/texture.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Texture class to help with texture and image initializations ## ## ## ## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## @@ -156,52 +156,109 @@ namespace Qtk { Texture() = default; + /** + * Copies an existing Texture object. + * + * @param value Texture to copy. + */ Texture(const Texture & value) { mOpenGLTexture = OpenGLTextureFactory::initTexture(value.mPath); mPath = value.mPath; } + /** + * @param path Path to texture to load on disk. + * @param flipX True if texture is to be flipped on the X axis. + * @param flipY True if texture is to be flipped on the Y axis. + */ explicit Texture( const char * path, bool flipX = false, bool flipY = false) : mOpenGLTexture(OpenGLTextureFactory::initTexture(path, flipX, flipY)), mPath(path) {} + /** + * Construct a Texture using an existing QOpenGLTexture. + * + * @param texture OpenGL texture to use for this Texture. + */ explicit Texture(QOpenGLTexture * texture) : mOpenGLTexture(texture) {} ~Texture() { mOpenGLTexture->destroy(); } + /************************************************************************* + * Public Methods + ************************************************************************/ + + /** + * @return True if the OpenGL texture has been initialized. + */ + [[nodiscard]] inline bool hasTexture() const { + return mOpenGLTexture != Q_NULLPTR; + } + /************************************************************************* * Accessors ************************************************************************/ + /** + * @return QOpenGLTexture associated with this Texture. + */ [[nodiscard]] inline QOpenGLTexture & getOpenGLTexture() const { return *mOpenGLTexture; } + /** + * @return Path to this Texture on disk. + */ [[nodiscard]] inline std::string getPath() const { return mPath; } /************************************************************************* * Setters ************************************************************************/ - void setTexture( + /** + * Replaces the current texture with a new texture. + * + * @param path Path to the new texture to load. + * @param flipX True if texture is to be flipped on the X axis. + * @param flipY True if texture is to be flipped on the Y axis. + */ + inline void setTexture( const std::string & path, bool flipX = false, bool flipY = false) { - mOpenGLTexture = - OpenGLTextureFactory::initTexture(path.data(), flipX, flipY); - mPath = path.data(); + setTexture(path.c_str(), flipX, flipY); } - void setTexture( + /** + * @param path Path to the new texture to load. + * @param flipX True if texture is to be flipped on the X axis. + * @param flipY True if texture is to be flipped on the Y axis. + */ + inline void setTexture( const char * path, bool flipX = false, bool flipY = false) { mOpenGLTexture = OpenGLTextureFactory::initTexture(path, flipX, flipY); mPath = path; } + /** + * Sets this Texture to be a cube map with all identical sides. + * + * @param path Path to texture to use for all sides of the cube map. + */ virtual inline void setCubeMap(const char * path) { mOpenGLTexture = OpenGLTextureFactory::initCubeMap(path); mPath = path; } + /** + * Sets this Texture to be a cube map with provided sides. + * + * @param right Path to texture to use for right cube map side. + * @param top Path to texture to use for top cube map side. + * @param front Path to texture to use for front cube map side. + * @param left Path to texture to use for left cube map side. + * @param bottom Path to texture to use for bottom cube map side. + * @param back Path to texture to use for back cube map side. + */ virtual inline void setCubeMap( const char * right, const char * top, const char * front, const char * left, const char * bottom, const char * back) { @@ -209,6 +266,16 @@ namespace Qtk { right, top, front, left, bottom, back); } + /** + * Sets this Texture to be a cube map with provided sides. + * + * @param right Path to texture to use for right cube map side. + * @param top Path to texture to use for top cube map side. + * @param front Path to texture to use for front cube map side. + * @param left Path to texture to use for left cube map side. + * @param bottom Path to texture to use for bottom cube map side. + * @param back Path to texture to use for back cube map side. + */ virtual inline void setCubeMap( const QImage & right, const QImage & top, const QImage & front, const QImage & left, const QImage & bottom, const QImage & back) { @@ -216,18 +283,14 @@ namespace Qtk { right, top, front, left, bottom, back); } - /************************************************************************* - * Public Methods - ************************************************************************/ - - [[nodiscard]] inline bool hasTexture() const { - return mOpenGLTexture != Q_NULLPTR; - } - private: /************************************************************************* * Private Members ************************************************************************/ + + /** + * @param texture QOpenGLTexture to use for this Texture. + */ inline void setTexture(QOpenGLTexture * texture) { mOpenGLTexture = texture; } @@ -236,7 +299,6 @@ namespace Qtk { /* Path to this texture on disk or Qt resource. */ const char * mPath {}; }; - } // namespace Qtk #endif // QTOPENGL_TEXTURE_H diff --git a/src/qtk/transform3D.cpp b/src/qtk/transform3D.cpp index 6ebbb64..3013890 100644 --- a/src/qtk/transform3D.cpp +++ b/src/qtk/transform3D.cpp @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Transform3D class to represent object position in 3D space ## ## From following tutorials at trentreed.net ## ## ## @@ -16,7 +16,7 @@ const QVector3D Transform3D::LocalUp(0.0f, 1.0f, 0.0f); const QVector3D Transform3D::LocalRight(1.0f, 0.0f, 0.0f); /******************************************************************************* - * Transformations + * Public Methods ******************************************************************************/ void Transform3D::translate(const QVector3D & dt) { @@ -29,19 +29,16 @@ void Transform3D::scale(const QVector3D & ds) { mScale *= ds; } -void Transform3D::rotate(const QQuaternion & dr) { - m_dirty = true; - mRotation = dr * mRotation; -} void Transform3D::grow(const QVector3D & ds) { m_dirty = true; mScale += ds; } -/******************************************************************************* - * Setters - ******************************************************************************/ +void Transform3D::rotate(const QQuaternion & dr) { + m_dirty = true; + mRotation = dr * mRotation; +} void Transform3D::setTranslation(const QVector3D & t) { m_dirty = true; @@ -58,12 +55,6 @@ void Transform3D::setRotation(const QQuaternion & r) { mRotation = r; } -/******************************************************************************* - * Accessors - ******************************************************************************/ - -// Produces modelToWorld matrix using current set of transformations -// Transformation * rotation * scale = modelToWorld const QMatrix4x4 & Transform3D::toMatrix() { if(m_dirty) { m_dirty = false; @@ -75,10 +66,6 @@ const QMatrix4x4 & Transform3D::toMatrix() { return mWorld; } -/******************************************************************************* - * Queries - ******************************************************************************/ - QVector3D Transform3D::getForward() const { return mRotation.rotatedVector(LocalForward); } @@ -89,13 +76,10 @@ QVector3D Transform3D::getUp() const { QVector3D Transform3D::getRight() const { return mRotation.rotatedVector(LocalRight); - while(true) { - int xx; - }; } /******************************************************************************* - * QT Streams + * Private Methods ******************************************************************************/ namespace Qtk { diff --git a/src/qtk/transform3D.h b/src/qtk/transform3D.h index cc7992e..71d1f38 100644 --- a/src/qtk/transform3D.h +++ b/src/qtk/transform3D.h @@ -1,6 +1,6 @@ /*############################################################################## ## Author: Shaun Reed ## -## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ## ## About: Transform3D class to represent object position in 3D space ## ## From following tutorials at trentreed.net ## ## ## @@ -35,75 +35,154 @@ namespace Qtk { mTranslation(0.0f, 0.0f, 0.0f) {} /************************************************************************* - * Transformations + * Public Methods ************************************************************************/ + /** + * @param dt Translation from last to current position. + */ void translate(const QVector3D & dt); + /** + * @param dx X translation from last to current position. + * @param dy Y translation from last to current position. + * @param dz Z translation from last to current position. + */ inline void translate(float dx, float dy, float dz) { translate(QVector3D(dx, dy, dz)); } - // Scale object with multiplication + /** + * Scale the object size. + * + * @param ds Scalar vector to apply to the transform. + */ void scale(const QVector3D & ds); + /** + * Scale the object size. + * + * @param dx Amount to scale on the X axis. + * @param dy Amount to scale on the Y axis. + * @param dz Amount to scale on the Z axis. + */ inline void scale(float dx, float dy, float dz) { scale(QVector3D(dx, dy, dz)); } + /** + * Scale the object size. + * + * @param factor Scalar to apply to all axis of the object. + */ inline void scale(float factor) { scale(QVector3D(factor, factor, factor)); } - // Multiplying by a rotation - void rotate(const QQuaternion & dr); - - inline void rotate(float angle, const QVector3D & axis) { - rotate(QQuaternion::fromAxisAndAngle(axis, angle)); - } - - inline void rotate(float angle, float ax, float ay, float az) { - rotate(QQuaternion::fromAxisAndAngle(ax, ay, az, angle)); - } - - // Scale object by addition + /** + * @param ds 3D vector to add to scale axis. + */ void grow(const QVector3D & ds); + /** + * @param dx Amount to grow X axis. + * @param dy Amount to grow Y axis. + * @param dz Amount to grow Z axis. + */ inline void grow(float dx, float dy, float dz) { grow(QVector3D(dx, dy, dz)); } + /** + * @param factor Amount to grow all axis equally. + */ inline void grow(float factor) { grow(QVector3D(factor, factor, factor)); } + /** + * @param dr Rotation to apply to the transform. + */ + void rotate(const QQuaternion & dr); + + /** + * @param angle Angle to rotate. + * @param axis Axis to rotate apply the rotation on. + */ + inline void rotate(float angle, const QVector3D & axis) { + rotate(QQuaternion::fromAxisAndAngle(axis, angle)); + } + + /** + * Apply rotation upon an axis represented by the 3D vector (x, y, z) + * + * @param angle Angle to rotate. + * @param ax X axis to apply the rotation on. + * @param ay Y axis to apply the rotation on. + * @param az Z axis to apply the rotation on. + */ + inline void rotate(float angle, float ax, float ay, float az) { + rotate(QQuaternion::fromAxisAndAngle(ax, ay, az, angle)); + } + /************************************************************************* * Setters ************************************************************************/ - // Set object position + /** + * @param t Position to move the transform to. + */ void setTranslation(const QVector3D & t); + /** + * @param x X position to set transform. + * @param y Y position to set transform. + * @param z Z position to set transform. + */ inline void setTranslation(float x, float y, float z) { setTranslation(QVector3D(x, y, z)); } - // Set object scale + /** + * @param s Scale to set for this transform. + */ void setScale(const QVector3D & s); + /** + * @param x X axis scale to set for this transform. + * @param y Y axis scale to set for this transform. + * @param z Z axis scale to set for this transform. + */ inline void setScale(float x, float y, float z) { setScale(QVector3D(x, y, z)); } + /** + * @param k Scale to set for all axis on this transform. + */ inline void setScale(float k) { setScale(QVector3D(k, k, k)); } - // Set object rotation + /** + * @param r Rotation to set for this transform. + */ void setRotation(const QQuaternion & r); + /** + * @param angle Angle to set for rotation. + * @param axis Axis to set rotation for. + */ inline void setRotation(float angle, const QVector3D & axis) { setRotation(QQuaternion::fromAxisAndAngle(axis, angle)); } + /** + * Sets a rotation upon an axis represented by the 3D vector (x, y, z) + * + * @param angle Angle to set rotation. + * @param ax X axis to set angle for. + * @param ay Y axis to set angle for. + * @param az Z axis to set angle for. + */ inline void setRotation(float angle, float ax, float ay, float az) { setRotation(QQuaternion::fromAxisAndAngle(ax, ay, az, angle)); } @@ -112,31 +191,55 @@ namespace Qtk { * Getters ************************************************************************/ + /** + * @return Translation for this transform. + */ [[nodiscard]] inline const QVector3D & getTranslation() const { return mTranslation; } + /** + * @return Scale for this transform. + */ [[nodiscard]] inline const QVector3D & getScale() const { return mScale; } + /** + * @return Rotation for this transform. + */ [[nodiscard]] inline const QQuaternion & getRotation() const { return mRotation; } + /** + * @return Model to world matrix for this transform. + * transformation * rotation * scale = ModelToWorld + */ const QMatrix4x4 & toMatrix(); + /** + * @return Forward vector for this transform. + */ [[nodiscard]] QVector3D getForward() const; + + /** + * @return Up vector for this transform. + */ [[nodiscard]] QVector3D getUp() const; + + /** + * @return Right vector for this transform. + */ [[nodiscard]] QVector3D getRight() const; /************************************************************************* - * Public members + * Public Members ************************************************************************/ static const QVector3D LocalForward, LocalUp, LocalRight; private: /************************************************************************* - * Private members + * Private Members ************************************************************************/ QVector3D mTranslation; @@ -154,7 +257,6 @@ namespace Qtk { #endif }; -// Qt Streams #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug dbg, const Transform3D & transform); #endif