Improve cmake and GUI (#13)
+ Packaging and CI for Windows, Mac, Linux + Debian package, NSIS Windows installer, OSX appbundle + Example application using libqtk + Component installation for `qtk`, `libqtk`, or `collection` with cmake
This commit was merged in pull request #13.
This commit is contained in:
165
src/CMakeLists.txt
Normal file
165
src/CMakeLists.txt
Normal file
@@ -0,0 +1,165 @@
|
||||
################################################################################
|
||||
## 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
|
||||
|
||||
# We always build libqtk since the plugins and GUI both depend on it.
|
||||
add_subdirectory(qtk)
|
||||
install(
|
||||
FILES
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
COMPONENT libqtk
|
||||
DESTINATION lib/cmake/${PROJECT_NAME}
|
||||
)
|
||||
install(
|
||||
EXPORT qtk_export
|
||||
FILE ${PROJECT_NAME}Targets.cmake
|
||||
NAMESPACE ${PROJECT_NAME}::
|
||||
COMPONENT libqtk
|
||||
DESTINATION lib/cmake/${PROJECT_NAME}
|
||||
)
|
||||
# System install for qtk_library
|
||||
install(
|
||||
TARGETS qtk_library
|
||||
# Associate qtk_library target with qtk-export
|
||||
EXPORT qtk_export
|
||||
COMPONENT libqtk
|
||||
FILE_SET HEADERS DESTINATION include
|
||||
INCLUDES DESTINATION include
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib/static
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
# Qtk Application
|
||||
if(QTK_BUILD_GUI OR QTK_INSTALL_PLUGINS)
|
||||
add_subdirectory(app)
|
||||
endif()
|
||||
|
||||
if(QTK_INSTALL_PLUGINS)
|
||||
# Optionally install custom Qtk plugins for Qt Designer.
|
||||
install(
|
||||
TARGETS qtk_library qtk_plugin_library
|
||||
COMPONENT collection
|
||||
LIBRARY DESTINATION "${QTK_PLUGIN_LIBRARY_DIR}"
|
||||
ARCHIVE DESTINATION "${QTK_PLUGIN_LIBRARY_DIR}"
|
||||
RUNTIME DESTINATION "${QTK_PLUGIN_LIBRARY_DIR}"
|
||||
)
|
||||
install(
|
||||
TARGETS qtk_collection
|
||||
COMPONENT collection
|
||||
LIBRARY DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
|
||||
ARCHIVE DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
|
||||
RUNTIME DESTINATION "${QTK_PLUGIN_INSTALL_DIR}"
|
||||
)
|
||||
endif()
|
||||
|
||||
if(QTK_BUILD_GUI)
|
||||
install(
|
||||
TARGETS qtk_app
|
||||
COMPONENT qtk
|
||||
BUNDLE DESTINATION .
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib/static
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
qt_generate_deploy_app_script(
|
||||
TARGET qtk_app
|
||||
OUTPUT_SCRIPT QTK_DEPLOY_SCRIPT
|
||||
NO_UNSUPPORTED_PLATFORM_ERROR
|
||||
)
|
||||
install(SCRIPT ${QTK_DEPLOY_SCRIPT} COMPONENT qtk)
|
||||
|
||||
if(WIN32)
|
||||
if(MSVC AND TARGET Qt6::qmake)
|
||||
get_target_property(QT6_QMAKE_LOCATION Qt6::qmake IMPORTED_LOCATION)
|
||||
execute_process(
|
||||
COMMAND "${QT6_QMAKE_LOCATION}" -query QT_INSTALL_PREFIX
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE QT6_INSTALL_PREFIX
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
file(TO_NATIVE_PATH "${QT6_INSTALL_PREFIX}/bin" QT6_INSTALL_PREFIX)
|
||||
|
||||
set(VSUSER_FILE "${CMAKE_CURRENT_BINARY_DIR}/qtk_app.vcxproj.user")
|
||||
file(WRITE ${VSUSER_FILE} "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
|
||||
file(APPEND ${VSUSER_FILE} "<Project xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n")
|
||||
file(APPEND ${VSUSER_FILE} " <PropertyGroup>\n")
|
||||
file(APPEND ${VSUSER_FILE} " <LocalDebuggerEnvironment>Path=$(SolutionDir)\\lib\\$(Configuration);${QT6_INSTALL_PREFIX};$(Path)\n")
|
||||
file(APPEND ${VSUSER_FILE} "$(LocalDebuggerEnvironment)</LocalDebuggerEnvironment>\n")
|
||||
file(APPEND ${VSUSER_FILE} " <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>\n")
|
||||
file(APPEND ${VSUSER_FILE} " </PropertyGroup>\n")
|
||||
file(APPEND ${VSUSER_FILE} "</Project>\n")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
write_basic_package_version_file(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
COMPATIBILITY AnyNewerVersion
|
||||
)
|
||||
configure_package_config_file(
|
||||
"${CMAKE_SOURCE_DIR}/cmake/templates/Config.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
INSTALL_DESTINATION lib/cmake/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE")
|
||||
set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}")
|
||||
set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}")
|
||||
set(CPACK_PACKAGE_VENDOR "Shaun Reed")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Qt OpenGL 3D graphics library.")
|
||||
set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/shaunrd0/qtk")
|
||||
set(CPACK_SOURCE_IGNORE_FILES build*;install;\.git;\.github;\.idea)
|
||||
set(CPACK_PACKAGE_DIRECTORY packages/)
|
||||
set(CPACK_PACKAGE_CONTACT "shaunreed.com")
|
||||
#set(CPACK_PACKAGE_ICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
|
||||
set(CPACK_THREADS 0)
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "Qtk")
|
||||
|
||||
# Remove any assimp components if defined by submodule.
|
||||
if (QTK_UPDATE_SUBMODULES)
|
||||
get_cmake_property(CPACK_COMPONENTS_ALL COMPONENTS)
|
||||
list(FILTER CPACK_COMPONENTS_ALL EXCLUDE REGEX .*assimp.*)
|
||||
list(REMOVE_ITEM CPACK_COMPONENTS_ALL Unspecified)
|
||||
endif()
|
||||
|
||||
# Windows
|
||||
set(CPACK_NSIS_MODIFY_PATH ON)
|
||||
set(CPACK_NSIS_ENABLE_UNINSTALL_BEFORE_INSTALL ON)
|
||||
# https://nsis.sourceforge.io/Reference/CreateShortCut
|
||||
set(
|
||||
CPACK_NSIS_CREATE_ICONS_EXTRA
|
||||
"CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qtk.lnk' '$INSTDIR\\\\bin\\\\qtk_app.exe'"
|
||||
)
|
||||
set(
|
||||
CPACK_NSIS_DELETE_ICONS_EXTRA
|
||||
"Delete '$SMPROGRAMS\\\\$START_MENU\\\\Qtk.lnk'"
|
||||
)
|
||||
# TODO: Icons for NSIS installer.
|
||||
#set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
|
||||
#set(CPACK_NSIS_MUI_UNIICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
|
||||
|
||||
# Debian
|
||||
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE ${CPACK_PACKAGE_HOMEPAGE_URL})
|
||||
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
|
||||
|
||||
# OSX
|
||||
set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_BUNDLE_PLIST $<TARGET_BUNDLE_CONTENT_DIR:qtk_app>/Info.plist)
|
||||
set(CPACK_BUNDLE_ICON ${QTK_OSX_ICONS})
|
||||
|
||||
# Platform defaults for source bundles.
|
||||
if(WIN32)
|
||||
set(CPACK_SOURCE_GENERATOR ZIP)
|
||||
else()
|
||||
set(CPACK_SOURCE_GENERATOR TGZ)
|
||||
endif()
|
||||
|
||||
include(CPack)
|
||||
71
src/app/CMakeLists.txt
Normal file
71
src/app/CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
||||
################################################################################
|
||||
## 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 Widget Library
|
||||
################################################################################
|
||||
# Create a library of widgets used to build Qtk GUI
|
||||
set(
|
||||
QTK_PLUGIN_LIBRARY_SOURCES
|
||||
qtkwidget.cpp
|
||||
debugconsole.cpp debugconsole.ui
|
||||
toolbox.cpp toolbox.ui
|
||||
treeview.cpp treeview.ui
|
||||
qtkmainwindow.cpp qtkmainwindow.h qtkmainwindow.ui
|
||||
)
|
||||
set(
|
||||
QTK_PLUGIN_LIBRARY_HEADERS
|
||||
qtkwidget.h
|
||||
debugconsole.h
|
||||
toolbox.h
|
||||
treeview.h
|
||||
)
|
||||
qt_add_library(qtk_plugin_library STATIC EXCLUDE_FROM_ALL)
|
||||
target_sources(
|
||||
qtk_plugin_library PRIVATE
|
||||
"${QTK_PLUGIN_LIBRARY_SOURCES}"
|
||||
"${QTK_PLUGIN_LIBRARY_HEADERS}"
|
||||
)
|
||||
target_link_libraries(qtk_plugin_library PUBLIC Qt6::UiPlugin qtk_library)
|
||||
|
||||
################################################################################
|
||||
# Qtk Widget Collection Plugin
|
||||
################################################################################
|
||||
# Create a Qt Designer plugin for a collection of widgets from our library.
|
||||
qt_add_plugin(qtk_collection SHARED)
|
||||
target_sources(
|
||||
qtk_collection PRIVATE
|
||||
widgetplugincollection.cpp widgetplugincollection.h
|
||||
widgetplugin.cpp widgetplugin.h
|
||||
)
|
||||
target_link_libraries(qtk_collection PUBLIC qtk_plugin_library)
|
||||
|
||||
################################################################################
|
||||
# Final Qtk Application
|
||||
################################################################################
|
||||
|
||||
set(
|
||||
QTK_APP_SOURCES
|
||||
qtkscene.cpp qtkscene.h
|
||||
main.cpp
|
||||
)
|
||||
|
||||
qt_add_executable(qtk_app ${QTK_APP_SOURCES})
|
||||
target_link_libraries(qtk_app PRIVATE qtk_plugin_library)
|
||||
|
||||
set_target_properties(
|
||||
qtk_app PROPERTIES
|
||||
WIN32_EXECUTABLE TRUE
|
||||
MACOSX_BUNDLE TRUE
|
||||
MACOSX_BUNDLE_BUNDLE_NAME Qtk
|
||||
MACOSX_BUNDLE_ICON_FILE ${QTK_OSX_ICONS}
|
||||
MACOSX_BUNDLE_GUI_IDENTIFIER ${CMAKE_PROJECT_NAME}
|
||||
MACOSX_BUNDLE_INFO_STRING ${CMAKE_PROJECT_DESCRIPTION}
|
||||
MACOSX_BUNDLE_COPYRIGHT "All Content (c) 2023 Shaun Reed, all rights reserved"
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
)
|
||||
33
src/app/debugconsole.cpp
Normal file
33
src/app/debugconsole.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QWindow>
|
||||
|
||||
#include "debugconsole.h"
|
||||
#include "ui_debugconsole.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
DebugConsole::DebugConsole(QWidget * owner, const QString & key) :
|
||||
DebugConsole(owner, key, key + "Debugger") {}
|
||||
|
||||
DebugConsole::DebugConsole(
|
||||
QWidget * owner, const QString & key, const QString & name) {
|
||||
ui_ = new Ui::DebugConsole;
|
||||
ui_->setupUi(this);
|
||||
setObjectName(name);
|
||||
mConsole = ui_->textEdit;
|
||||
setWidget(mConsole);
|
||||
setWindowTitle(name + " Debug Console");
|
||||
|
||||
auto qtkWidget = dynamic_cast<QtkWidget *>(owner);
|
||||
if(qtkWidget) {
|
||||
connect(qtkWidget, &QtkWidget::sendLog, this, &DebugConsole::sendLog);
|
||||
}
|
||||
}
|
||||
140
src/app/debugconsole.h
Normal file
140
src/app/debugconsole.h
Normal file
@@ -0,0 +1,140 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTK_DEBUGCONSOLE_H
|
||||
#define QTK_DEBUGCONSOLE_H
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDockWidget>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include "qtkwidget.h"
|
||||
|
||||
namespace Ui {
|
||||
class DebugConsole;
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
class DebugConsole : public QDockWidget {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Construct a new DebugConsole.
|
||||
* Assigns a default name to the console using `key + "Debugger"`
|
||||
*
|
||||
* @param owner Parent widget for this console or nullptr if no parent.
|
||||
* If this parameter inherits from QMainWindow we will add this dock
|
||||
* widget to the window.
|
||||
* @param key The objectName associated with the attached QtkWidget.
|
||||
*/
|
||||
DebugConsole(QWidget * owner, const QString & key);
|
||||
|
||||
/**
|
||||
* Construct a new DebugConsole.
|
||||
*
|
||||
* @param owner Parent widget for this console or nullptr if no parent.
|
||||
* If this parameter inherits from QMainWindow we will add this dock
|
||||
* widget to the window.
|
||||
* @param key The objectName associated with the attached QtkWidget.
|
||||
* @param name The objectName to associate with this DebugConsole.
|
||||
*/
|
||||
DebugConsole(QWidget * owner, const QString & key, const QString & name);
|
||||
|
||||
~DebugConsole() = default;
|
||||
|
||||
public slots:
|
||||
/*************************************************************************
|
||||
* Public Qt slots
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Log a message to the DebugConsole text view.
|
||||
*
|
||||
* @param message The message to log.
|
||||
* @param context The DebugContext to use for the message.
|
||||
* Default value is Status.
|
||||
*/
|
||||
inline void sendLog(QString message, DebugContext context = Status) {
|
||||
mConsole->setTextColor(logColor(context));
|
||||
mConsole->append(logPrefix(message, context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the window title for the DebugConsole. This will appear in the
|
||||
* widget title bar and within any context menu actions.
|
||||
*
|
||||
* @param name Base name for the DebugConsole window.
|
||||
*/
|
||||
inline void setTitle(QString name) {
|
||||
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:
|
||||
return Qt::GlobalColor::darkGray;
|
||||
case Debug:
|
||||
return Qt::GlobalColor::white;
|
||||
case Warn:
|
||||
return Qt::GlobalColor::yellow;
|
||||
case Error:
|
||||
return Qt::GlobalColor::red;
|
||||
case Fatal:
|
||||
return Qt::GlobalColor::magenta;
|
||||
default:
|
||||
return Qt::GlobalColor::darkYellow;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
switch(context) {
|
||||
case Status:
|
||||
prefix = "[Status]: ";
|
||||
break;
|
||||
case Debug:
|
||||
prefix = "[Debug]: ";
|
||||
break;
|
||||
case Warn:
|
||||
prefix = "[Warn]: ";
|
||||
break;
|
||||
case Error:
|
||||
prefix = "[Error]: ";
|
||||
break;
|
||||
case Fatal:
|
||||
prefix = "[Fatal]: ";
|
||||
break;
|
||||
default:
|
||||
prefix = "[No Context]: ";
|
||||
break;
|
||||
}
|
||||
message = prefix + message.replace("\n", "\t\n" + prefix);
|
||||
return message;
|
||||
}
|
||||
|
||||
Ui::DebugConsole * ui_;
|
||||
QTextEdit * mConsole;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_DEBUGCONSOLE_H
|
||||
33
src/app/debugconsole.ui
Normal file
33
src/app/debugconsole.ui
Normal file
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>DebugConsole</class>
|
||||
<widget class="QDockWidget" name="DebugConsole">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Debug Console</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="textEdit">
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
28
src/app/main.cpp
Normal file
28
src/app/main.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QApplication>
|
||||
|
||||
#include "qtkmainwindow.h"
|
||||
#include "qtkscene.h"
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
Q_INIT_RESOURCE(resources);
|
||||
|
||||
QApplication a(argc, argv);
|
||||
|
||||
auto window = MainWindow::getMainWindow();
|
||||
|
||||
// Qtk currently uses the decorator pattern to save / load scenes.
|
||||
// This is a temporary solution and will be improved in the future.
|
||||
auto emptyScene = new Qtk::SceneEmpty;
|
||||
window->getQtkWidget()->setScene(new QtkScene(emptyScene));
|
||||
|
||||
window->show();
|
||||
return QApplication::exec();
|
||||
}
|
||||
80
src/app/qtkmainwindow.cpp
Normal file
80
src/app/qtkmainwindow.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 "qtkmainwindow.h"
|
||||
#include "qtkscene.h"
|
||||
#include "ui_qtkmainwindow.h"
|
||||
|
||||
MainWindow * MainWindow::mainWindow_ = Q_NULLPTR;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors / Destructors
|
||||
******************************************************************************/
|
||||
|
||||
MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
|
||||
ui_ = new Ui::MainWindow;
|
||||
setObjectName("MainWindow");
|
||||
// For use in design mode using Qt Creator
|
||||
// + We can use the `ui` member to access nested widgets by name
|
||||
ui_->setupUi(this);
|
||||
ui_->menuView->addAction(ui_->toolBar->toggleViewAction());
|
||||
|
||||
// Initialize static container for all active QtkWidgets
|
||||
auto qtkWidgets = findChildren<Qtk::QtkWidget *>();
|
||||
for(auto & qtkWidget : qtkWidgets) {
|
||||
qtkWidget->setScene(new Qtk::SceneEmpty);
|
||||
views_.emplace(qtkWidget->getScene()->getSceneName(), qtkWidget);
|
||||
ui_->menuView->addAction(qtkWidget->getActionToggleConsole());
|
||||
connect(
|
||||
qtkWidget->getScene(), &Qtk::Scene::sceneUpdated, this,
|
||||
&MainWindow::refreshScene);
|
||||
}
|
||||
|
||||
auto docks = findChildren<QDockWidget *>();
|
||||
for(auto & dock : docks) {
|
||||
addDockWidget(Qt::RightDockWidgetArea, dock);
|
||||
ui_->menuView->addAction(dock->toggleViewAction());
|
||||
}
|
||||
|
||||
// Set the window icon used for Qtk.
|
||||
setWindowIcon(Qtk::getIcon());
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {
|
||||
delete ui_;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
MainWindow * MainWindow::getMainWindow() {
|
||||
if(mainWindow_ == Q_NULLPTR) {
|
||||
mainWindow_ = new MainWindow;
|
||||
}
|
||||
return mainWindow_;
|
||||
}
|
||||
|
||||
Qtk::QtkWidget * MainWindow::getQtkWidget(int64_t index) {
|
||||
if(views_.size() <= index) {
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
return views_.begin(index)->second;
|
||||
}
|
||||
|
||||
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()->getScene());
|
||||
}
|
||||
92
src/app/qtkmainwindow.h
Normal file
92
src/app/qtkmainwindow.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
#include "debugconsole.h"
|
||||
#include "qtkwidget.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* MainWindow class to provide an example of using a QtkWidget within a Qt
|
||||
* window application.
|
||||
*/
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* This ctor also initializes the Scene for each QtkWidget in the window.
|
||||
* To load a different scene this would need to be updated.
|
||||
*
|
||||
* @param parent The parent for this QMainWindow
|
||||
*/
|
||||
explicit MainWindow(QWidget * parent = nullptr);
|
||||
|
||||
~MainWindow() override;
|
||||
|
||||
/***************************************************************************
|
||||
* Public Methods
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* Allows widgets to retrieve an instance of this root QMainWindow.
|
||||
* @return this
|
||||
*/
|
||||
static MainWindow * getMainWindow();
|
||||
|
||||
Qtk::QtkWidget * getQtkWidget(int64_t index = 0);
|
||||
|
||||
/**
|
||||
* Accessor for retrieving a QtkWidget by it's objectName.
|
||||
* This function will not construct a new QtkWidget if none is found.
|
||||
*
|
||||
* @param name The objectName associated with the QtkWidget.
|
||||
* @return Pointer to an active QtkWidget or Q_NULLPTR is not found.
|
||||
*/
|
||||
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:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
/** Do not allow copying */
|
||||
MainWindow(const MainWindow &) {};
|
||||
|
||||
Ui::MainWindow * ui_ {};
|
||||
static MainWindow * mainWindow_;
|
||||
|
||||
/**
|
||||
* Maps a scene name to the QtkWidget viewing it.
|
||||
* TODO: Value should be a vector of QtkWidget * for multiple scene views.
|
||||
*/
|
||||
std::unordered_map<QString, Qtk::QtkWidget *> views_ {};
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
||||
342
src/app/qtkmainwindow.ui
Normal file
342
src/app/qtkmainwindow.ui
Normal file
@@ -0,0 +1,342 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>824</width>
|
||||
<height>601</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Qtk - MainWindow</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset>
|
||||
<normaloff>../resources/icon.png</normaloff>../resources/icon.png</iconset>
|
||||
</property>
|
||||
<property name="unifiedTitleAndToolBarOnMac">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>View 1</string>
|
||||
</attribute>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="Qtk::QtkWidget" name="qtk::QtkWidget">
|
||||
<property name="toolTip">
|
||||
<string>A custom widget tool tip.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Custom widget what's this?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>View 2</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="Qtk::TreeView" name="qtk::TreeView">
|
||||
<property name="toolTip">
|
||||
<string>A custom widget tool tip.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Custom widget what's this?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Qtk::ToolBox" name="qtk::ToolBox">
|
||||
<property name="toolTip">
|
||||
<string>A custom widget tool tip.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Custom widget what's this?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>824</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuTest">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionNew"/>
|
||||
<addaction name="actionOpen"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionSave"/>
|
||||
<addaction name="actionSave_as"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionExit"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
<string>View</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuTab_Position">
|
||||
<property name="title">
|
||||
<string>Tab Position</string>
|
||||
</property>
|
||||
<addaction name="actionTop"/>
|
||||
<addaction name="actionBottom"/>
|
||||
<addaction name="actionLeft"/>
|
||||
<addaction name="actionRight"/>
|
||||
</widget>
|
||||
<addaction name="menuTab_Position"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuEdit">
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<addaction name="actionUndo"/>
|
||||
<addaction name="actionRedo"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuHelp">
|
||||
<property name="title">
|
||||
<string>Help</string>
|
||||
</property>
|
||||
<addaction name="actionAbout"/>
|
||||
</widget>
|
||||
<addaction name="menuTest"/>
|
||||
<addaction name="menuEdit"/>
|
||||
<addaction name="menuView"/>
|
||||
<addaction name="menuHelp"/>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>24</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<property name="floatable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionLoad_Model"/>
|
||||
<addaction name="actionDelete_Object"/>
|
||||
</widget>
|
||||
<action name="actionOpen">
|
||||
<property name="icon">
|
||||
<iconset resource="../../resources/resources.qrc">
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/folder-open.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/folder-open.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Open...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave">
|
||||
<property name="icon">
|
||||
<iconset resource="../../resources/resources.qrc">
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/floppy-disk.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/floppy-disk.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_as">
|
||||
<property name="text">
|
||||
<string>Save as...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExit">
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionShow_Console">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Show Console</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoad_Model">
|
||||
<property name="icon">
|
||||
<iconset resource="../../resources/resources.qrc">
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Load Model</string>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font/>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete_Object">
|
||||
<property name="icon">
|
||||
<iconset resource="../../resources/resources.qrc">
|
||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete Object</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNew">
|
||||
<property name="text">
|
||||
<string>New</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTop">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Top</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionBottom">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Bottom</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLeft">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Left</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRight">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Right</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAbout">
|
||||
<property name="text">
|
||||
<string>About</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionNested_Widgets">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Nested Widgets</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUndo">
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRedo">
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>Qtk::QtkWidget</class>
|
||||
<extends>QOpenGLWidget</extends>
|
||||
<header>qtkwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Qtk::TreeView</class>
|
||||
<extends>QDockWidget</extends>
|
||||
<header>treeview.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>Qtk::ToolBox</class>
|
||||
<extends>QDockWidget</extends>
|
||||
<header>toolbox.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>actionExit</sender>
|
||||
<signal>triggered()</signal>
|
||||
<receiver>MainWindow</receiver>
|
||||
<slot>close()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>411</x>
|
||||
<y>300</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
542
src/app/qtkscene.cpp
Normal file
542
src/app/qtkscene.cpp
Normal file
@@ -0,0 +1,542 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 "qtkscene.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
QtkScene::QtkScene(Qtk::Scene * scene) : Qtk::SceneInterface(scene) {
|
||||
setSceneName("Qtk Scene");
|
||||
getCamera().getTransform().setTranslation(0.0f, 0.0f, 20.0f);
|
||||
getCamera().getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
QtkScene::~QtkScene() {
|
||||
delete mTestPhong;
|
||||
delete mTestSpecular;
|
||||
delete mTestDiffuse;
|
||||
delete mTestAmbient;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
void QtkScene::init() {
|
||||
// Add a skybox to the scene using default cube map images and settings.
|
||||
setSkybox(new Qtk::Skybox("Skybox"));
|
||||
|
||||
/* Create a red cube with a mini master chief on top. */
|
||||
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
|
||||
myCube->setColor(RED);
|
||||
addObject(myCube);
|
||||
|
||||
auto mySpartan =
|
||||
new Model("My spartan", ":/models/models/spartan/spartan.obj");
|
||||
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
|
||||
mySpartan->getTransform().setScale(0.5f);
|
||||
addObject(mySpartan);
|
||||
|
||||
//
|
||||
// Create simple shapes using MeshRenderer class and data in mesh.h
|
||||
|
||||
auto mesh = addObject(
|
||||
new Qtk::MeshRenderer("rightTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-5.0f, 0.0f, -2.0f);
|
||||
|
||||
mesh =
|
||||
addObject(new Qtk::MeshRenderer("centerCube", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-7.0f, 0.0f, -2.0f);
|
||||
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("leftTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-9.0f, 0.0f, -2.0f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("topTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-7.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("bottomTriangle", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-7.0f, -2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
mesh->setColor(GREEN);
|
||||
|
||||
|
||||
//
|
||||
// 3D Model loading
|
||||
|
||||
auto model = addObject(
|
||||
new Qtk::Model("backpack", ":/models/models/backpack/backpack.obj"));
|
||||
// Sometimes model textures need flipped in certain directions
|
||||
model->flipTexture("diffuse.jpg", false, true);
|
||||
model->getTransform().setTranslation(0.0f, 0.0f, -10.0f);
|
||||
|
||||
model = addObject(new Qtk::Model("bird", ":/models/models/bird/bird.obj"));
|
||||
model->getTransform().setTranslation(2.0f, 2.0f, -10.0f);
|
||||
// Sometimes the models are very large
|
||||
model->getTransform().scale(0.0025f);
|
||||
model->getTransform().rotate(-110.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
model = addObject(
|
||||
new Qtk::Model("alien", ":/models/models/alien-hominid/alien.obj"));
|
||||
model->getTransform().setTranslation(2.0f, -1.0f, -5.0f);
|
||||
model->getTransform().scale(0.15f);
|
||||
|
||||
model = addObject(
|
||||
new Qtk::Model("My scythe", ":/models/models/scythe/scythe.obj"));
|
||||
model->getTransform().setTranslation(-6.0f, 0.0f, -10.0f);
|
||||
model->getTransform().rotate(-90.0f, 1.0f, 0.0f, 0.0f);
|
||||
model->getTransform().rotate(90.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
model = addObject(
|
||||
new Qtk::Model("masterChief", ":/models/models/spartan/spartan.obj"));
|
||||
model->getTransform().setTranslation(-1.5f, 0.5f, -2.0f);
|
||||
|
||||
|
||||
//
|
||||
// Simple cube lighting examples.
|
||||
|
||||
/* Phong lighting example on a basic cube. */
|
||||
mTestPhong = new Qtk::MeshRenderer("phong", Qtk::Cube());
|
||||
mTestPhong->getTransform().setTranslation(3.0f, 0.0f, -2.0f);
|
||||
// NOTE: You no longer need to manually bind shader program to set uniforms.
|
||||
// + You can still bind it if you want to for performance reasons.
|
||||
// + Qtk will only bind / release if the shader program is not already bound.
|
||||
mTestPhong->setShaders(
|
||||
":/shaders/solid-phong.vert", ":/shaders/solid-phong.frag");
|
||||
|
||||
// For example this would technically not be efficient, because each one of
|
||||
// these calls will bind, set, release. We could instead bind, set N uniforms,
|
||||
// and release when we are finished.
|
||||
// mTestPhong->bindShaders();
|
||||
mTestPhong->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestPhong->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestPhong->setUniform("uAmbientStrength", 0.2f);
|
||||
mTestPhong->setUniform("uSpecularStrength", 0.50f);
|
||||
mTestPhong->setUniform("uSpecularShine", 256);
|
||||
// mTestPhong->releaseShaders();
|
||||
mTestPhong->reallocateNormals(mTestPhong->getNormals());
|
||||
// NOTE: This is only an example and I won't worry about this kind of
|
||||
// efficiency while initializing the following objects.
|
||||
|
||||
// Phong lighting example light source. This is just for visual reference.
|
||||
// + We refer to the position of this object in draw() to update lighting.
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("phongLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(3.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
/* Example of a cube with no lighting applied */
|
||||
mesh = addObject(new Qtk::MeshRenderer("noLight", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, -2.0f);
|
||||
mesh->setShaders(
|
||||
":/shaders/solid-perspective.vert", ":/shaders/solid-perspective.frag");
|
||||
mesh->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
// No light source needed for this lighting technique
|
||||
|
||||
/* Initialize Ambient example cube */
|
||||
mTestAmbient = new Qtk::MeshRenderer("ambient", Cube());
|
||||
mTestAmbient->getTransform().setTranslation(7.0f, 0.0f, -2.0f);
|
||||
mTestAmbient->setShaders(
|
||||
":/shaders/solid-ambient.vert", ":/shaders/solid-ambient.frag");
|
||||
// Changing these uniform values will alter lighting effects.
|
||||
mTestAmbient->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestAmbient->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestAmbient->setUniform("uAmbientStrength", 0.2f);
|
||||
mTestAmbient->reallocateNormals(mTestAmbient->getNormals());
|
||||
// No light source needed for this lighting technique
|
||||
|
||||
/* Initialize Diffuse example cube */
|
||||
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube());
|
||||
mTestDiffuse->getTransform().setTranslation(9.0f, 0.0f, -2.0f);
|
||||
mTestDiffuse->setShaders(
|
||||
":/shaders/solid-diffuse.vert", ":/shaders/solid-diffuse.frag");
|
||||
mTestDiffuse->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestDiffuse->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestDiffuse->setUniform("uAmbientStrength", 0.2f);
|
||||
mTestDiffuse->reallocateNormals(mTestDiffuse->getNormals());
|
||||
|
||||
// Diffuse lighting example light source. This is just for visual reference.
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("diffuseLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(9.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
/* Initialize Specular example cube */
|
||||
mTestSpecular = new Qtk::MeshRenderer("specular", Cube());
|
||||
mTestSpecular->getTransform().setTranslation(11.0f, 0.0f, -2.0f);
|
||||
mTestSpecular->setShaders(
|
||||
":/shaders/solid-specular.vert", ":/shaders/solid-specular.frag");
|
||||
mTestSpecular->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mTestSpecular->setUniform("uLightColor", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mTestSpecular->setUniform("uAmbientStrength", 0.2f);
|
||||
mTestSpecular->setUniform("uSpecularStrength", 0.50f);
|
||||
mTestSpecular->setUniform("uSpecularShine", 256);
|
||||
mTestSpecular->reallocateNormals(mTestSpecular->getNormals());
|
||||
|
||||
// Specular lighting example light source. This is just for visual reference.
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("specularLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(11.0f, 2.0f, -2.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
|
||||
|
||||
/* Test basic cube with phong.vert and phong.frag shaders */
|
||||
mesh = addObject(new Qtk::MeshRenderer("testPhong", Cube(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, 10.0f);
|
||||
mesh->setShaders(":/shaders/phong.vert", ":/shaders/phong.frag");
|
||||
// WARNING: Set color before reallocating normals.
|
||||
mesh->setColor(QVector3D(0.0f, 0.25f, 0.0f));
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
mesh->setUniform("uMaterial.ambient", QVector3D(0.0f, 0.3f, 0.0f));
|
||||
mesh->setUniform("uMaterial.diffuse", QVector3D(0.0f, 0.2f, 0.0f));
|
||||
mesh->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
mesh->setUniform("uMaterial.ambientStrength", 1.0f);
|
||||
mesh->setUniform("uMaterial.diffuseStrength", 1.0f);
|
||||
mesh->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
mesh->setUniform("uMaterial.shine", 64.0f);
|
||||
mesh->setUniform("uLight.ambient", QVector3D(0.25f, 0.2f, 0.075f));
|
||||
mesh->setUniform("uLight.diffuse", QVector3D(0.75f, 0.6f, 0.22f));
|
||||
mesh->setUniform("uLight.specular", QVector3D(0.62f, 0.55f, 0.37f));
|
||||
mesh->setUniform("uColor", QVector3D(0.0f, 0.25f, 0.0f));
|
||||
|
||||
// Light source for testPhong cube
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("testLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 1.25f, 10.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
mesh->setDrawType(GL_LINE_LOOP);
|
||||
mesh->setColor(RED);
|
||||
|
||||
|
||||
//
|
||||
// Building more complex objects for showing examples of lighting techniques
|
||||
|
||||
/* Test alien Model with phong lighting and specular mapping. */
|
||||
model = addObject(new Qtk::Model(
|
||||
"alienTest", ":/models/models/alien-hominid/alien.obj",
|
||||
":/shaders/model-specular.vert", ":/shaders/model-specular.frag"));
|
||||
model->getTransform().setTranslation(3.0f, -1.0f, 10.0f);
|
||||
model->getTransform().scale(0.15f);
|
||||
model->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.ambientStrength", 0.8f);
|
||||
model->setUniform("uMaterial.diffuseStrength", 0.8f);
|
||||
model->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
model->setUniform("uMaterial.shine", 32.0f);
|
||||
|
||||
model->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Light source for alienTest object.
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"alienTestLight", Triangle(Qtk::QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(4.0f, 1.5f, 10.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
// This function changes values we have allocated in a buffer, so init() after
|
||||
mesh->setColor(GREEN);
|
||||
|
||||
/* Test spartan Model with phong lighting, specular and normal mapping. */
|
||||
model = addObject(new Qtk::Model(
|
||||
"spartanTest", ":/models/models/spartan/spartan.obj",
|
||||
":/shaders/model-normals.vert", ":/shaders/model-normals.frag"));
|
||||
model->getTransform().setTranslation(0.0f, -1.0f, 10.0f);
|
||||
model->getTransform().scale(2.0f);
|
||||
model->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uMaterial.ambientStrength", 1.0f);
|
||||
model->setUniform("uMaterial.diffuseStrength", 1.0f);
|
||||
model->setUniform("uMaterial.specularStrength", 1.0f);
|
||||
model->setUniform("uMaterial.shine", 128.0f);
|
||||
model->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.diffuse", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
model->setUniform("uLight.specular", QVector3D(1.0f, 1.0f, 1.0f));
|
||||
|
||||
// Light source for spartanTest object.
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(1.0f, 1.5f, 10.0f);
|
||||
mesh->getTransform().scale(0.25f);
|
||||
// This function changes values we have allocated in a buffer, so init() after
|
||||
mesh->setColor(GREEN);
|
||||
|
||||
|
||||
//
|
||||
// Test drawing simple geometry with various OpenGL drawing modes
|
||||
|
||||
// RGB Normals cube to show normals are correct with QTK_DRAW_ARRAYS
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("rgbNormalsCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, 4.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// RGB Normals cube to show normals are correct with QTK_DRAW_ELEMENTS_NORMALS
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"rgbNormalsCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 0.0f, 2.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
Texture crateTexture;
|
||||
crateTexture.setTexture(":/textures/crate.png");
|
||||
Cube cube;
|
||||
auto * m = new MeshRenderer("Test Crate", Cube(QTK_DRAW_ARRAYS));
|
||||
m->getTransform().setTranslation(0, 0, 13);
|
||||
m->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
m->setTexture(crateTexture);
|
||||
m->setUniform("uTexture", 0);
|
||||
m->reallocateTexCoords(cube.getTexCoords());
|
||||
addObject(m);
|
||||
|
||||
// Texturing a cube using texture coordinates and glDrawArrays
|
||||
// + Texturing with UVs using glDrawElements requires
|
||||
// QTK_DRAW_ELEMENTS_NORMALS
|
||||
// + UVs required duplicating element position data from QTK_DRAW_ELEMENTS
|
||||
// + This is because the same position must use different UV coordinates
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("uvCubeArraysTest", Cube(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(-3.0f, 0.0f, -2.0f);
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
mesh->setTexture(crateTexture);
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
|
||||
// Test drawing a cube with texture coordinates using glDrawElements
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"uvCubeElementsTest", Cube(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mesh->getTransform().setTranslation(-1.7f, 0.0f, -2.0f);
|
||||
mesh->setTexture(":/textures/crate.png");
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
mesh->bindShaders();
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords(), 3);
|
||||
mesh->releaseShaders();
|
||||
mesh->getTransform().rotate(45.0f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
// Texturing a cube using a cube map
|
||||
// + Cube map texturing works with both QTK_DRAW_ARRAYS and QTK_DRAW_ELEMENTS
|
||||
mesh =
|
||||
addObject(new Qtk::MeshRenderer("testCubeMap", Cube(QTK_DRAW_ELEMENTS)));
|
||||
mesh->getTransform().setTranslation(-3.0f, 1.0f, -2.0f);
|
||||
mesh->getTransform().setRotation(45.0f, 0.0f, 1.0f, 0.0f);
|
||||
mesh->setShaders(
|
||||
":/shaders/texture-cubemap.vert", ":/shaders/texture-cubemap.frag");
|
||||
mesh->setCubeMap(":/textures/crate.png");
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
|
||||
// Create a cube with custom shaders
|
||||
// + Apply RGB normals shader and spin the cube for a neat effect
|
||||
mesh =
|
||||
addObject(new Qtk::MeshRenderer("rgbNormalsCube", Cube(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(5.0f, 2.0f, -2.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ARRAYS
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"rgbTriangleArraysTest", Triangle(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(7.0f, 0.0f, 2.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// RGB Normals triangle to show normals are correct with QTK_DRAW_ELEMENTS
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"rgbTriangleElementsTest", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mesh->getTransform().setTranslation(7.0f, 0.0f, 4.0f);
|
||||
mesh->setShaders(":/shaders/rgb-normals.vert", ":/shaders/rgb-normals.frag");
|
||||
mesh->reallocateNormals(mesh->getNormals());
|
||||
|
||||
// Test drawing triangle with glDrawArrays with texture coordinates
|
||||
mesh = addObject(
|
||||
new Qtk::MeshRenderer("testTriangleArraysUV", Triangle(QTK_DRAW_ARRAYS)));
|
||||
mesh->getTransform().setTranslation(-3.0f, 2.0f, -2.0f);
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
|
||||
mesh->setTexture(":/textures/crate.png");
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
|
||||
// Test drawing triangle with glDrawElements with texture coordinates
|
||||
mesh = addObject(new Qtk::MeshRenderer(
|
||||
"testTriangleElementsUV", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
|
||||
mesh->getTransform().setTranslation(-2.5f, 0.0f, -1.0f);
|
||||
mesh->setShaders(":/shaders/texture2d.vert", ":/shaders/texture2d.frag");
|
||||
mesh->setTexture(":/textures/crate.png");
|
||||
mesh->setUniform("uTexture", 0);
|
||||
mesh->reallocateTexCoords(mesh->getTexCoords());
|
||||
}
|
||||
|
||||
void QtkScene::draw() {
|
||||
// WARNING: We must call the base class draw() function first.
|
||||
// + This will handle rendering core scene components like the Skybox.
|
||||
Scene::draw();
|
||||
|
||||
mTestPhong->bindShaders();
|
||||
mTestPhong->setUniform(
|
||||
"uModelInverseTransposed",
|
||||
mTestPhong->getTransform().toMatrix().normalMatrix());
|
||||
mTestPhong->setUniform(
|
||||
"uLightPosition",
|
||||
MeshRenderer::getInstance("phongLight")->getTransform().getTranslation());
|
||||
mTestPhong->setUniform(
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestPhong->releaseShaders();
|
||||
mTestPhong->draw();
|
||||
|
||||
mTestAmbient->bindShaders();
|
||||
mTestAmbient->setUniform(
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestAmbient->releaseShaders();
|
||||
mTestAmbient->draw();
|
||||
|
||||
mTestDiffuse->bindShaders();
|
||||
mTestDiffuse->setUniform(
|
||||
"uModelInverseTransposed",
|
||||
mTestDiffuse->getTransform().toMatrix().normalMatrix());
|
||||
mTestDiffuse->setUniform(
|
||||
"uLightPosition", MeshRenderer::getInstance("diffuseLight")
|
||||
->getTransform()
|
||||
.getTranslation());
|
||||
mTestDiffuse->setUniform(
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestDiffuse->releaseShaders();
|
||||
mTestDiffuse->draw();
|
||||
|
||||
mTestSpecular->bindShaders();
|
||||
mTestSpecular->setUniform(
|
||||
"uModelInverseTransposed",
|
||||
mTestSpecular->getTransform().toMatrix().normalMatrix());
|
||||
mTestSpecular->setUniform(
|
||||
"uLightPosition", MeshRenderer::getInstance("specularLight")
|
||||
->getTransform()
|
||||
.getTranslation());
|
||||
mTestSpecular->setUniform(
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
mTestSpecular->releaseShaders();
|
||||
mTestSpecular->draw();
|
||||
}
|
||||
|
||||
void QtkScene::update() {
|
||||
auto mySpartan = Model::getInstance("My spartan");
|
||||
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
auto myCube = MeshRenderer::getInstance("My cube");
|
||||
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
auto position = MeshRenderer::getInstance("alienTestLight")
|
||||
->getTransform()
|
||||
.getTranslation();
|
||||
auto alien = Model::getInstance("alienTest");
|
||||
alien->setUniform("uLight.position", position);
|
||||
alien->setUniform(
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
auto posMatrix = alien->getTransform().toMatrix();
|
||||
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
alien->setUniform("uMVP.model", posMatrix);
|
||||
alien->setUniform("uMVP.view", QtkScene::getCamera().toMatrix());
|
||||
alien->setUniform("uMVP.projection", QtkScene::getProjectionMatrix());
|
||||
alien->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
position = MeshRenderer::getInstance("spartanTestLight")
|
||||
->getTransform()
|
||||
.getTranslation();
|
||||
auto spartan = Model::getInstance("spartanTest");
|
||||
spartan->setUniform("uLight.position", position);
|
||||
spartan->setUniform(
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
posMatrix = spartan->getTransform().toMatrix();
|
||||
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
spartan->setUniform("uMVP.model", posMatrix);
|
||||
spartan->setUniform("uMVP.view", QtkScene::getCamera().toMatrix());
|
||||
spartan->setUniform("uMVP.projection", QtkScene::getProjectionMatrix());
|
||||
spartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
|
||||
|
||||
auto phong = MeshRenderer::getInstance("testPhong");
|
||||
phong->getTransform().rotate(0.75f, 1.0f, 0.5f, 0.0f);
|
||||
phong->bindShaders();
|
||||
position =
|
||||
MeshRenderer::getInstance("testLight")->getTransform().getTranslation();
|
||||
phong->setUniform("uLight.position", position);
|
||||
phong->setUniform(
|
||||
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
|
||||
posMatrix = phong->getTransform().toMatrix();
|
||||
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
|
||||
phong->setUniform("uMVP.model", posMatrix);
|
||||
phong->setUniform("uMVP.view", QtkScene::getCamera().toMatrix());
|
||||
phong->setUniform("uMVP.projection", QtkScene::getProjectionMatrix());
|
||||
phong->releaseShaders();
|
||||
|
||||
// Rotate lighting example cubes
|
||||
mTestPhong->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
|
||||
MeshRenderer::getInstance("noLight")->getTransform().rotate(
|
||||
0.75f, 0.5f, 0.3f, 0.2f);
|
||||
mTestAmbient->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
|
||||
mTestDiffuse->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
|
||||
mTestSpecular->getTransform().rotate(0.75f, 0.5f, 0.3f, 0.2f);
|
||||
|
||||
// Examples of various translations and rotations
|
||||
|
||||
// Rotate in multiple directions simultaneously
|
||||
MeshRenderer::getInstance("rgbNormalsCube")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.2f, 0.4f, 0.6f);
|
||||
|
||||
// Pitch forward and roll sideways
|
||||
MeshRenderer::getInstance("leftTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 1.0f, 0.0f, 0.0f);
|
||||
MeshRenderer::getInstance("rightTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Move between two positions over time
|
||||
static float translateX = 0.025f;
|
||||
float limit = -9.0f; // Origin position.x - 2.0f
|
||||
float posX = MeshRenderer::getInstance("topTriangle")
|
||||
->getTransform()
|
||||
.getTranslation()
|
||||
.x();
|
||||
if(posX < limit || posX > limit + 4.0f) {
|
||||
translateX = -translateX;
|
||||
}
|
||||
MeshRenderer::getInstance("topTriangle")
|
||||
->getTransform()
|
||||
.translate(translateX, 0.0f, 0.0f);
|
||||
MeshRenderer::getInstance("bottomTriangle")
|
||||
->getTransform()
|
||||
.translate(-translateX, 0.0f, 0.0f);
|
||||
// And lets rotate the triangles in two directions at once
|
||||
MeshRenderer::getInstance("topTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.2f, 0.0f, 0.4f);
|
||||
MeshRenderer::getInstance("bottomTriangle")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.0f, 0.2f, 0.4f);
|
||||
// And make the bottom triangle green, instead of RGB
|
||||
|
||||
// Rotate center cube in several directions simultaneously
|
||||
// + Not subject to gimbal lock since we are using quaternions :)
|
||||
MeshRenderer::getInstance("centerCube")
|
||||
->getTransform()
|
||||
.rotate(0.75f, 0.2f, 0.4f, 0.6f);
|
||||
}
|
||||
75
src/app/qtkscene.h
Normal file
75
src/app/qtkscene.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Example Qtk scene ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTK_EXAMPLE_SCENE_H
|
||||
#define QTK_EXAMPLE_SCENE_H
|
||||
|
||||
#include <qtk/scene.h>
|
||||
|
||||
/**
|
||||
* Example scene using QtkWidget to render 3D models and simple geometry within
|
||||
* QtOpenGLWidgets. This scene also shows some examples of using GLSL shaders to
|
||||
* apply the basic lighting techniques leading up to Phong.
|
||||
*
|
||||
* The Qtk::Scene base class provides containers for N pointers to MeshRenderer
|
||||
* and Model objects. We can create and insert as many as we like within this
|
||||
* child class implementation. This child class does not need to manually draw
|
||||
* objects inserted into these containers. The child class would only need to
|
||||
* update uniform or other data that may change per-frame.
|
||||
* See scene.h and `init()` for more information.
|
||||
*
|
||||
* To modify the scene objects should be initialized within the `init()` public
|
||||
* method. Any required movement or updates should be applied within `draw()` or
|
||||
* `update()`.
|
||||
*
|
||||
* To create your own Scene from scratch see Qtk::Scene.
|
||||
*/
|
||||
class QtkScene : public Qtk::SceneInterface {
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
QtkScene(Qtk::Scene * scene);
|
||||
|
||||
~QtkScene();
|
||||
|
||||
/***************************************************************************
|
||||
* Inherited Public Overrides
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* Initialize objects within the scene
|
||||
*/
|
||||
void init() override;
|
||||
|
||||
/**
|
||||
* Called when OpenGL repaints the widget.
|
||||
*/
|
||||
void draw() override;
|
||||
|
||||
/**
|
||||
* Called when the Qt `frameSwapped` signal is caught.
|
||||
* See definition of `QtkWidget::initializeGL()`
|
||||
*/
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
// Additional example objects created within this example.
|
||||
// + The base class Scene manages objects stored within mMeshes or mModels
|
||||
Qtk::MeshRenderer * mTestPhong {};
|
||||
Qtk::MeshRenderer * mTestSpecular {};
|
||||
Qtk::MeshRenderer * mTestDiffuse {};
|
||||
Qtk::MeshRenderer * mTestAmbient {};
|
||||
};
|
||||
|
||||
#endif // QTK_EXAMPLE_SCENE_H
|
||||
@@ -1,17 +1,21 @@
|
||||
/*##############################################################################
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <input.h>
|
||||
#include <mesh.h>
|
||||
#include <qtkwidget.h>
|
||||
#include <scene.h>
|
||||
#include <qtk/input.h>
|
||||
#include <qtk/scene.h>
|
||||
#include <qtk/shape.h>
|
||||
|
||||
#include "debugconsole.h"
|
||||
#include "qtkmainwindow.h"
|
||||
#include "qtkwidget.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
@@ -19,17 +23,26 @@ using namespace Qtk;
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||
initializeWidget();
|
||||
}
|
||||
QtkWidget::QtkWidget(QWidget * parent) : QtkWidget(parent, "QtkWidget") {}
|
||||
|
||||
QtkWidget::QtkWidget(QWidget * parent) :
|
||||
QOpenGLWidget(parent), mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||
initializeWidget();
|
||||
}
|
||||
QtkWidget::QtkWidget(QWidget * parent, const QString & name) :
|
||||
QtkWidget(parent, name, Q_NULLPTR) {}
|
||||
|
||||
QtkWidget::QtkWidget(const QSurfaceFormat & format) :
|
||||
mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||
QtkWidget::QtkWidget(QWidget * parent, const QString & name, Scene * scene) :
|
||||
QOpenGLWidget(parent), mDebugLogger(Q_NULLPTR),
|
||||
mConsole(new DebugConsole(this, name)), mScene(Q_NULLPTR) {
|
||||
setScene(scene);
|
||||
setObjectName(name);
|
||||
QSurfaceFormat format;
|
||||
format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setVersion(4, 6);
|
||||
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
|
||||
format.setSamples(4);
|
||||
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
|
||||
format.setDepthBufferSize(16);
|
||||
// If QTK_DEBUG is set, enable debug context
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
setFormat(format);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
}
|
||||
@@ -40,16 +53,24 @@ QtkWidget::~QtkWidget() {
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Inherited Virtual Methods
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
QAction * QtkWidget::getActionToggleConsole() {
|
||||
auto action = new QAction(mScene->getSceneName() + " debug console");
|
||||
action->setCheckable(true);
|
||||
action->setChecked(mConsoleActive);
|
||||
action->setStatusTip("Add a debug console for this QtkWidget.");
|
||||
connect(action, &QAction::triggered, this, &QtkWidget::toggleConsole);
|
||||
return action;
|
||||
}
|
||||
|
||||
void QtkWidget::initializeGL() {
|
||||
initializeOpenGLFunctions();
|
||||
// Connect the frameSwapped signal to call the update() function
|
||||
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
|
||||
|
||||
// Initialize OpenGL debug context
|
||||
#ifdef QTK_DEBUG
|
||||
mDebugLogger = new QOpenGLDebugLogger(this);
|
||||
if(mDebugLogger->initialize()) {
|
||||
qDebug() << "GL_DEBUG Debug Logger" << mDebugLogger << "\n";
|
||||
@@ -58,7 +79,6 @@ void QtkWidget::initializeGL() {
|
||||
SLOT(messageLogged(QOpenGLDebugMessage)));
|
||||
mDebugLogger->startLogging();
|
||||
}
|
||||
#endif // QTK_DEBUG
|
||||
|
||||
printContextInformation();
|
||||
|
||||
@@ -87,10 +107,64 @@ void QtkWidget::paintGL() {
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::setScene(Qtk::Scene * scene) {
|
||||
if(mScene != Q_NULLPTR) {
|
||||
delete mScene;
|
||||
connect(
|
||||
scene, &Qtk::Scene::sceneUpdated, MainWindow::getMainWindow(),
|
||||
&MainWindow::refreshScene);
|
||||
}
|
||||
|
||||
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<QDockWidget *>(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();
|
||||
|
||||
@@ -104,19 +178,24 @@ void QtkWidget::update() {
|
||||
void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
|
||||
QString error;
|
||||
|
||||
DebugContext context;
|
||||
// Format based on severity
|
||||
switch(msg.severity()) {
|
||||
case QOpenGLDebugMessage::NotificationSeverity:
|
||||
error += "--";
|
||||
context = Status;
|
||||
break;
|
||||
case QOpenGLDebugMessage::HighSeverity:
|
||||
error += "!!";
|
||||
context = Fatal;
|
||||
break;
|
||||
case QOpenGLDebugMessage::MediumSeverity:
|
||||
error += "!~";
|
||||
context = Error;
|
||||
break;
|
||||
case QOpenGLDebugMessage::LowSeverity:
|
||||
error += "~~";
|
||||
context = Warn;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -159,58 +238,53 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
|
||||
}
|
||||
#undef CASE
|
||||
|
||||
error += ")";
|
||||
qDebug() << qPrintable(error) << "\n" << qPrintable(msg.message()) << "\n";
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 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());
|
||||
error += ")\n" + msg.message() + "\n";
|
||||
qDebug() << qPrintable(error);
|
||||
sendLog("(OpenGL) " + error.replace("\n", "\n(OpenGL) "), context);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Private Methods
|
||||
******************************************************************************/
|
||||
|
||||
void QtkWidget::initializeWidget() {
|
||||
QSurfaceFormat format;
|
||||
format.setRenderableType(QSurfaceFormat::OpenGL);
|
||||
format.setProfile(QSurfaceFormat::CoreProfile);
|
||||
format.setVersion(4, 6);
|
||||
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
|
||||
format.setSamples(4);
|
||||
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
|
||||
format.setDepthBufferSize(16);
|
||||
// If QTK_DEBUG is set, enable debug context
|
||||
#ifdef QTK_DEBUG
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
#endif
|
||||
setFormat(format);
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
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() {
|
||||
@@ -239,46 +313,9 @@ void QtkWidget::printContextInformation() {
|
||||
}
|
||||
#undef CASE
|
||||
|
||||
// qPrintable() will print our QString w/o quotes around it.
|
||||
qDebug() << qPrintable(glType) << qPrintable(glVersion) << "("
|
||||
<< qPrintable(glProfile) << ")"
|
||||
<< "\nOpenGL Vendor: " << qPrintable(glVendor)
|
||||
<< "\nRendering Device: " << qPrintable(glRenderer) << "\n";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
auto message = QString(glType) + glVersion + "(" + glProfile + ")"
|
||||
+ "\nOpenGL Vendor: " + glVendor
|
||||
+ "\nRendering Device: " + glRenderer;
|
||||
qDebug() << qPrintable(message);
|
||||
sendLog("(OpenGL) " + message.replace("\n", "\n(OpenGL) "), Status);
|
||||
}
|
||||
@@ -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 ##
|
||||
##############################################################################*/
|
||||
@@ -10,22 +10,26 @@
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <QDockWidget>
|
||||
#include <QMatrix4x4>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLWidget>
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <scene.h>
|
||||
#include <qtk/qtkapi.h>
|
||||
#include <qtk/scene.h>
|
||||
|
||||
namespace Qtk {
|
||||
class DebugConsole;
|
||||
|
||||
/**
|
||||
* QtkWidget class to define required QOpenGLWidget functionality.
|
||||
*
|
||||
* This object has a Scene attached which manages the objects to render.
|
||||
* Client input is passed through this widget to control the camera view.
|
||||
*/
|
||||
class QTKAPI QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
class QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
|
||||
Q_OBJECT;
|
||||
|
||||
public:
|
||||
@@ -33,40 +37,41 @@ namespace Qtk {
|
||||
* Contructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Default ctor will configure a QSurfaceFormat with default settings.
|
||||
*/
|
||||
QtkWidget();
|
||||
|
||||
/**
|
||||
* Qt Designer will call this ctor when creating this widget as a child.
|
||||
*
|
||||
* @param parent The parent QWidget
|
||||
* @param parent Pointer to a parent widget for this QtkWidget or nullptr.
|
||||
*/
|
||||
explicit QtkWidget(QWidget * parent);
|
||||
explicit QtkWidget(QWidget * parent = nullptr);
|
||||
|
||||
/**
|
||||
* Allow constructing the widget with a preconfigured QSurfaceFormat.
|
||||
* Default construct a QtkWidget.
|
||||
*
|
||||
* @param format QSurfaceFormat already configured by the caller.
|
||||
* @param parent Pointer to a parent widget or nullptr if no parent.
|
||||
* @param name An objectName for the new QtkWidget.
|
||||
*/
|
||||
explicit QtkWidget(const QSurfaceFormat & format);
|
||||
explicit QtkWidget(QWidget * parent, const QString & name);
|
||||
|
||||
~QtkWidget() override;
|
||||
/**
|
||||
* Construct a custom QtkWidget.
|
||||
*
|
||||
* @param parent Pointer to a parent widget or nullptr if no parent.
|
||||
* @param name An objectName for the new QtkWidget.
|
||||
* @param scene Pointer to a custom class inheriting from Qtk::Scene.
|
||||
*/
|
||||
QtkWidget(QWidget * parent, const QString & name, Qtk::Scene * scene);
|
||||
|
||||
~QtkWidget();
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
// clang-format off
|
||||
void teardownGL() { /* Nothing to teardown yet... */ }
|
||||
// clang-format on
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Public Inherited Virtual Methods
|
||||
************************************************************************/
|
||||
/**
|
||||
* Constructs a QAction to hide / show this DebugConsole.
|
||||
* @return QAction to toggle visibility of this DebugConsole.
|
||||
*/
|
||||
QAction * getActionToggleConsole();
|
||||
|
||||
/**
|
||||
* Called when the widget is first constructed.
|
||||
@@ -90,66 +95,110 @@ namespace Qtk {
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return The active scene being viewed in this widget.
|
||||
*/
|
||||
inline Qtk::Scene * getScene() { return mScene; }
|
||||
|
||||
/**
|
||||
* @return Pointer to the QOpenGLDebugLogger attached to this widget.
|
||||
*/
|
||||
inline QOpenGLDebugLogger * getOpenGLDebugLogger() {
|
||||
return mDebugLogger;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
inline void setScene(Qtk::Scene * scene) {
|
||||
delete mScene;
|
||||
mScene = scene;
|
||||
}
|
||||
/**
|
||||
* @param scene The new scene to view.
|
||||
*/
|
||||
void setScene(Qtk::Scene * scene);
|
||||
|
||||
protected slots:
|
||||
/*************************************************************************
|
||||
* Qt Slots
|
||||
************************************************************************/
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* Called when the `frameSwapped` signal is caught.
|
||||
* See definition of initializeGL()
|
||||
* Toggle visibility of the DebugConsole associated with this QtkWidget.
|
||||
*/
|
||||
void update();
|
||||
void toggleConsole();
|
||||
|
||||
#ifdef QTK_DEBUG
|
||||
signals:
|
||||
/**
|
||||
* Called when the `messageLogged` signal is caught.
|
||||
* See definition of initializeGL()
|
||||
*
|
||||
* @param msg The message logged.
|
||||
* Log a message to the DebugConsole associated with this widget.
|
||||
* @param message The message to log.
|
||||
* @param context The context of the log message.
|
||||
*/
|
||||
static void messageLogged(const QOpenGLDebugMessage & msg);
|
||||
#endif
|
||||
void sendLog(const QString & message, DebugContext context = Status);
|
||||
|
||||
protected:
|
||||
/*************************************************************************
|
||||
* 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()
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Called when the `messageLogged` signal is caught.
|
||||
* See definition of initializeGL()
|
||||
*
|
||||
* @param msg The message logged.
|
||||
*/
|
||||
void messageLogged(const QOpenGLDebugMessage & msg);
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
void initializeWidget();
|
||||
/**
|
||||
* 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
|
||||
************************************************************************/
|
||||
|
||||
QOpenGLDebugLogger * mDebugLogger;
|
||||
Qtk::Scene * mScene;
|
||||
Qtk::DebugConsole * mConsole;
|
||||
bool mConsoleActive = false;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
6
src/app/resources.h.in
Normal file
6
src/app/resources.h.in
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef QTK_RESOURCES_H_IN_H
|
||||
#define QTK_RESOURCES_H_IN_H
|
||||
|
||||
// Not currently in use, but will be in the future.
|
||||
|
||||
#endif // QTK_RESOURCES_H_IN_H
|
||||
@@ -1,23 +1,20 @@
|
||||
/*##############################################################################
|
||||
## 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: Toolbox plugin for object details and options ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_QTKAPI_H
|
||||
#define QTK_QTKAPI_H
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include "toolbox.h"
|
||||
#include "ui_toolbox.h"
|
||||
|
||||
#ifdef QTK_SHARED
|
||||
#if defined(QTK_EXPORT)
|
||||
#define QTKAPI Q_DECL_EXPORT
|
||||
#else
|
||||
#define QTKAPI Q_DECL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define QTKAPI
|
||||
#endif
|
||||
Qtk::ToolBox::ToolBox(QWidget * parent) :
|
||||
QDockWidget(parent), ui(new Ui::ToolBox) {
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
#endif // QTK_QTKAPI_H
|
||||
Qtk::ToolBox::~ToolBox() {
|
||||
delete ui;
|
||||
}
|
||||
42
src/app/toolbox.h
Normal file
42
src/app/toolbox.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef TOOLBOX_H
|
||||
#define TOOLBOX_H
|
||||
|
||||
#include <QDesignerExportWidget>
|
||||
#include <QDockWidget>
|
||||
|
||||
namespace Ui {
|
||||
class ToolBox;
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
class ToolBox : public QDockWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Contructors / Destructors
|
||||
*************************************************************************/
|
||||
|
||||
explicit ToolBox(QWidget * parent = nullptr);
|
||||
|
||||
~ToolBox();
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
Ui::ToolBox * ui;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // TOOLBOX_H
|
||||
56
src/app/toolbox.ui
Normal file
56
src/app/toolbox.ui
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ToolBox</class>
|
||||
<widget class="QDockWidget" name="ToolBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Object Details</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QToolBox" name="toolBox">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>382</width>
|
||||
<height>201</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Shaders</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>382</width>
|
||||
<height>201</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Properties</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
63
src/app/treeview.cpp
Normal file
63
src/app/treeview.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include "treeview.h"
|
||||
#include "qtkmainwindow.h"
|
||||
#include "ui_treeview.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
Qtk::TreeView::TreeView(QWidget * parent) :
|
||||
QDockWidget(parent), ui(new Ui::TreeView) {
|
||||
ui->setupUi(this);
|
||||
connect(
|
||||
ui->treeWidget, &QTreeWidget::itemDoubleClicked, this,
|
||||
&TreeView::itemFocus);
|
||||
}
|
||||
|
||||
Qtk::TreeView::~TreeView() {
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
void Qtk::TreeView::updateView(const Qtk::Scene * scene) {
|
||||
ui->treeWidget->clear();
|
||||
ui->treeWidget->setColumnCount(1);
|
||||
mSceneName = scene->getSceneName();
|
||||
auto objects = scene->getObjects();
|
||||
for(const auto & object : objects) {
|
||||
auto item =
|
||||
new QTreeWidgetItem(QStringList(QString(object->getName().c_str())));
|
||||
ui->treeWidget->insertTopLevelItem(0, item);
|
||||
}
|
||||
}
|
||||
|
||||
void Qtk::TreeView::itemFocus(QTreeWidgetItem * item, int column) {
|
||||
QString name = item->text(column);
|
||||
auto scene = MainWindow::getMainWindow()->getQtkWidget()->getScene();
|
||||
auto & transform = scene->getCamera().getTransform();
|
||||
auto object = scene->getObject(name);
|
||||
if(object == Q_NULLPTR) {
|
||||
qDebug() << "Attempt to get non-existing object with name '" << name
|
||||
<< "'\n";
|
||||
}
|
||||
Transform3D * objectTransform;
|
||||
if(object->getType() == Object::QTK_MESH) {
|
||||
objectTransform = &dynamic_cast<MeshRenderer *>(object)->getTransform();
|
||||
} else if(object->getType() == Object::QTK_MODEL) {
|
||||
objectTransform = &dynamic_cast<Model *>(object)->getTransform();
|
||||
}
|
||||
transform.setTranslation(objectTransform->getTranslation());
|
||||
transform.translate(0.0f, 0.0f, 3.0f);
|
||||
}
|
||||
73
src/app/treeview.h
Normal file
73
src/app/treeview.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef TREEVIEW_H
|
||||
#define TREEVIEW_H
|
||||
|
||||
#include <QDesignerCustomWidgetInterface>
|
||||
#include <QDesignerExportWidget>
|
||||
#include <QDockWidget>
|
||||
|
||||
#include <qtk/scene.h>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
namespace Ui {
|
||||
class TreeView;
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
class TreeView : public QDockWidget {
|
||||
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.
|
||||
*/
|
||||
void updateView(const Scene * scene);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* Focus the camera on an item when it is double clicked.
|
||||
* Triggered by QTreeWidget::itemDoubleClicked signal.
|
||||
*
|
||||
* @param item The item that was double clicked
|
||||
* @param column The column of the item that was double clicked.
|
||||
* This param is currently not used but required for this signal.
|
||||
*/
|
||||
void itemFocus(QTreeWidgetItem * item, int column);
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
Ui::TreeView * ui;
|
||||
|
||||
/**
|
||||
* The name of the scene last loaded by this TreeWidget.
|
||||
* Used to load object data from a target scene.
|
||||
*/
|
||||
QString mSceneName;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // TREEVIEW_H
|
||||
44
src/app/treeview.ui
Normal file
44
src/app/treeview.ui
Normal file
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TreeView</class>
|
||||
<widget class="QDockWidget" name="TreeView">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Scene Tree View</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="indentation">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
98
src/app/widgetplugin.cpp
Normal file
98
src/app/widgetplugin.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include <QIcon>
|
||||
#include <QtPlugin>
|
||||
#include <utility>
|
||||
|
||||
#include <qtk/qtkapi.h>
|
||||
|
||||
#include "widgetplugin.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
WidgetPlugin::WidgetPlugin(
|
||||
QString group, QString class_name, QString include,
|
||||
WidgetPlugin::Factory factory) :
|
||||
m_group(std::move(group)),
|
||||
m_className(std::move(class_name)), m_includeFile(std::move(include)),
|
||||
m_factory(std::move(factory)), m_objectName(class_name) {}
|
||||
|
||||
WidgetPlugin::WidgetPlugin(QObject * parent) : QObject(parent) {}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
QString WidgetPlugin::group() const {
|
||||
return m_group;
|
||||
}
|
||||
|
||||
QString WidgetPlugin::name() const {
|
||||
return m_className;
|
||||
}
|
||||
|
||||
QString WidgetPlugin::includeFile() const {
|
||||
return m_includeFile;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void WidgetPlugin::initialize(QDesignerFormEditorInterface *) {
|
||||
if(m_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_initialized = true;
|
||||
}
|
||||
QString WidgetPlugin::domXml() const {
|
||||
return
|
||||
"<ui language=\"c++\">\n"
|
||||
" <widget class=\"" + m_className + "\" name=\"" + m_objectName + "\">\n"
|
||||
" <property name=\"geometry\">\n"
|
||||
" <rect>\n"
|
||||
" <x>0</x>\n"
|
||||
" <y>0</y>\n"
|
||||
" <width>100</width>\n"
|
||||
" <height>100</height>\n"
|
||||
" </rect>\n"
|
||||
" </property>\n"
|
||||
" <property name=\"toolTip\" >\n"
|
||||
" <string>" + toolTip() + "</string>\n"
|
||||
" </property>\n"
|
||||
" <property name=\"whatsThis\" >\n"
|
||||
" <string>" + whatsThis() + "</string>\n"
|
||||
" </property>\n"
|
||||
" </widget>\n"
|
||||
"</ui>\n";
|
||||
}
|
||||
124
src/app/widgetplugin.h
Normal file
124
src/app/widgetplugin.h
Normal file
@@ -0,0 +1,124 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef QTK_WIDGETPLUGIN_H
|
||||
#define QTK_WIDGETPLUGIN_H
|
||||
|
||||
#include <QDesignerCustomWidgetInterface>
|
||||
#include <QDesignerExportWidget>
|
||||
|
||||
class QDESIGNER_WIDGET_EXPORT WidgetPlugin :
|
||||
public QObject,
|
||||
public QDesignerCustomWidgetInterface {
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QDesignerCustomWidgetInterface)
|
||||
|
||||
using Factory = std::function<QWidget *(QWidget *)>;
|
||||
|
||||
public:
|
||||
/***************************************************************************
|
||||
* Contructors / Destructors
|
||||
**************************************************************************/
|
||||
|
||||
WidgetPlugin(
|
||||
QString group, QString class_name, QString include, Factory factory);
|
||||
|
||||
explicit WidgetPlugin(QObject * parent = nullptr);
|
||||
|
||||
~WidgetPlugin() = default;
|
||||
|
||||
/***************************************************************************
|
||||
* Public Methods
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
* @return The name of the group to which this widget belongs.
|
||||
*/
|
||||
[[nodiscard]] QString group() const override;
|
||||
|
||||
/**
|
||||
* Must return the _class name_ of the widget.
|
||||
*
|
||||
* @return The class name for the associated widget.
|
||||
*/
|
||||
[[nodiscard]] QString name() const override;
|
||||
|
||||
/**
|
||||
* If this path changes for a custom widget, it must be removed and added
|
||||
* back in Qt Designer for the XML surrounding this value to be regenerated.
|
||||
*
|
||||
* See the `<customwidget>` XML in any `.ui` file using a custom widget.
|
||||
*
|
||||
* @return Path to the include file for UIC to use when generating code.
|
||||
*/
|
||||
[[nodiscard]] QString includeFile() const override;
|
||||
|
||||
/**
|
||||
* @param parent Parent widget to the new instance of this widget.
|
||||
* @return A new instance of this custom widget.
|
||||
*/
|
||||
[[nodiscard]] QWidget * createWidget(QWidget * parent) override;
|
||||
|
||||
/**
|
||||
* @return Short description used in Qt Designer tool tips.
|
||||
*/
|
||||
[[nodiscard]] QString toolTip() const override;
|
||||
|
||||
/**
|
||||
* @return Widget description used in `What's this?` within Qt Creator.
|
||||
*/
|
||||
[[nodiscard]] QString whatsThis() const override;
|
||||
|
||||
/**
|
||||
* @return Icon used to represent the widget in Qt Designer's GUI.
|
||||
*/
|
||||
[[nodiscard]] QIcon icon() const override;
|
||||
|
||||
/**
|
||||
* Whether or not this widget should act as a container for other widgets.
|
||||
*
|
||||
* @return True if this custom widget is meant to be a container.
|
||||
*/
|
||||
[[nodiscard]] bool isContainer() const override;
|
||||
|
||||
/**
|
||||
* @return True if this widget has been initialized.
|
||||
*/
|
||||
[[nodiscard]] bool isInitialized() const override;
|
||||
|
||||
/**
|
||||
* Initializes an instance of this custom widget.
|
||||
* @param core
|
||||
*/
|
||||
void initialize(QDesignerFormEditorInterface * core) override;
|
||||
|
||||
/**
|
||||
* Default XML for an instance of this custom widget within a `.ui` file.
|
||||
*
|
||||
* Any property available for the widget in Qt Designer can be set using XML
|
||||
* properties, as seen here with `toolTip` and `whatsThis`.
|
||||
*
|
||||
* @return XML inserted for each instance of this widget.
|
||||
*/
|
||||
[[nodiscard]] QString domXml() const override;
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
bool m_initialized = false;
|
||||
QString m_group;
|
||||
QString m_className;
|
||||
QString m_objectName;
|
||||
QString m_includeFile;
|
||||
Factory m_factory;
|
||||
};
|
||||
|
||||
#endif // QTK_WIDGETPLUGIN_H
|
||||
43
src/app/widgetplugincollection.cpp
Normal file
43
src/app/widgetplugincollection.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#include "widgetplugincollection.h"
|
||||
#include "debugconsole.h"
|
||||
#include "qtkwidget.h"
|
||||
#include "toolbox.h"
|
||||
#include "treeview.h"
|
||||
#include "widgetplugin.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
WidgetPluginCollection::WidgetPluginCollection(QObject * parent) :
|
||||
QObject(parent), m_collectionName("Qtk Widget Collection") {
|
||||
m_collection = {
|
||||
new WidgetPlugin(
|
||||
m_collectionName, "Qtk::QtkWidget", "qtkwidget.h",
|
||||
[](QWidget * parent) { return new Qtk::QtkWidget(parent); }),
|
||||
new WidgetPlugin(
|
||||
m_collectionName, "Qtk::TreeView", "treeview.h",
|
||||
[](QWidget * parent) { return new Qtk::TreeView(parent); }),
|
||||
new WidgetPlugin(
|
||||
m_collectionName, "Qtk::ToolBox", "toolbox.h",
|
||||
[](QWidget * parent) { return new Qtk::ToolBox(parent); }),
|
||||
};
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
QList<QDesignerCustomWidgetInterface *> WidgetPluginCollection::customWidgets()
|
||||
const {
|
||||
return m_collection;
|
||||
}
|
||||
50
src/app/widgetplugincollection.h
Normal file
50
src/app/widgetplugincollection.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
################################################################################
|
||||
*/
|
||||
|
||||
#ifndef QTK_WIDGETPLUGINCOLLECTION_H
|
||||
#define QTK_WIDGETPLUGINCOLLECTION_H
|
||||
|
||||
#include <QDesignerCustomWidgetCollectionInterface>
|
||||
|
||||
class WidgetPluginCollection :
|
||||
public QObject,
|
||||
public QDesignerCustomWidgetCollectionInterface {
|
||||
Q_OBJECT
|
||||
// Since we're exporting a collection, this is the only plugin metadata
|
||||
// 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<QDesignerCustomWidgetInterface *> customWidgets() const;
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
* Private Members
|
||||
**************************************************************************/
|
||||
|
||||
QList<QDesignerCustomWidgetInterface *> m_collection;
|
||||
QString m_collectionName;
|
||||
};
|
||||
|
||||
#endif // QTK_WIDGETPLUGINCOLLECTION_H
|
||||
89
src/input.h
89
src/input.h
@@ -1,89 +0,0 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Input class from tutorials followed at trentreed.net ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTOPENGL_INPUT_H
|
||||
#define QTOPENGL_INPUT_H
|
||||
|
||||
#include <QPoint>
|
||||
#include <Qt>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <qtkwidget.h>
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI Input {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
friend class Qtk::QtkWidget;
|
||||
|
||||
/**
|
||||
* Possible key states
|
||||
*/
|
||||
enum InputState {
|
||||
InputInvalid,
|
||||
InputRegistered,
|
||||
InputUnregistered,
|
||||
InputTriggered,
|
||||
InputPressed,
|
||||
InputReleased
|
||||
};
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
// State checking
|
||||
inline static bool keyTriggered(Qt::Key key) {
|
||||
return keyState(key) == InputTriggered;
|
||||
}
|
||||
|
||||
inline static bool keyPressed(Qt::Key key) {
|
||||
return keyState(key) == InputPressed;
|
||||
}
|
||||
|
||||
inline static bool keyReleased(Qt::Key key) {
|
||||
return keyState(key) == InputReleased;
|
||||
}
|
||||
|
||||
inline static bool buttonTriggered(Qt::MouseButton button) {
|
||||
return buttonState(button) == InputTriggered;
|
||||
}
|
||||
|
||||
inline static bool buttonPressed(Qt::MouseButton button) {
|
||||
return buttonState(button) == InputPressed;
|
||||
}
|
||||
|
||||
inline static bool buttonReleased(Qt::MouseButton button) {
|
||||
return buttonState(button) == InputReleased;
|
||||
}
|
||||
|
||||
// Implementation
|
||||
static InputState keyState(Qt::Key key);
|
||||
static InputState buttonState(Qt::MouseButton button);
|
||||
|
||||
static QPoint mousePosition();
|
||||
static QPoint mouseDelta();
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
// 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();
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTOPENGL_INPUT_H
|
||||
@@ -1,137 +0,0 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: MeshRenderer class for quick object creation and drawing ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MESHRENDERER_H
|
||||
#define QTK_MESHRENDERER_H
|
||||
|
||||
#include <mesh.h>
|
||||
#include <object.h>
|
||||
#include <qtkapi.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI MeshRenderer : public Object {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/* Static QHash of all mesh objects within the scene. */
|
||||
typedef QHash<QString, MeshRenderer *> MeshManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
// Delegate constructors
|
||||
MeshRenderer(
|
||||
const char * name, Vertices vertices, Indices indices,
|
||||
DrawMode mode = QTK_DRAW_ARRAYS) :
|
||||
MeshRenderer(
|
||||
name, ShapeBase(mode, std::move(vertices), std::move(indices))) {}
|
||||
|
||||
explicit MeshRenderer(const char * name) :
|
||||
MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS)) {}
|
||||
|
||||
// Constructor
|
||||
MeshRenderer(const char * name, const ShapeBase & shape);
|
||||
~MeshRenderer() override;
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
void init();
|
||||
void draw();
|
||||
|
||||
inline void enableAttributeArray(int location) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mVAO.bind();
|
||||
mProgram.enableAttributeArray(location);
|
||||
mVAO.release();
|
||||
}
|
||||
|
||||
void reallocateTexCoords(const TexCoords & t, unsigned dims = 2);
|
||||
|
||||
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; }
|
||||
|
||||
// Shader settings
|
||||
inline void setShaderVertex(const std::string & vert) {
|
||||
mVertexShader = vert;
|
||||
}
|
||||
|
||||
inline void setShaderFragment(const std::string & frag) {
|
||||
mFragmentShader = frag;
|
||||
}
|
||||
|
||||
void setShaders(const std::string & vert, const std::string & frag);
|
||||
|
||||
template <typename T> inline void setUniform(int location, T value) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(location, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
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
|
||||
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
|
||||
void setShape(const Shape & value) override;
|
||||
void setColor(const QVector3D & color);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Retrieve a mesh by name stored within static QHash private member
|
||||
* @param name The name of the MeshRenderer we want to retrieve.
|
||||
* @return Pointer to the MeshRenderer, or nullptr if not found.
|
||||
*/
|
||||
static MeshRenderer * getInstance(const QString & name);
|
||||
|
||||
Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
static MeshManager sInstances;
|
||||
|
||||
int mDrawType {};
|
||||
std::string mVertexShader {}, mFragmentShader {};
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MESHRENDERER_H
|
||||
262
src/model.h
262
src/model.h
@@ -1,262 +0,0 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
||||
## About: Model classes for importing with Assimp ##
|
||||
## From following tutorials on learnopengl.com ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MODEL_H
|
||||
#define QTK_MODEL_H
|
||||
|
||||
// QT
|
||||
#include <QObject>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
|
||||
// Assimp
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
// QTK
|
||||
#include <object.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<ModelVertex> Vertices;
|
||||
typedef std::vector<GLuint> Indices;
|
||||
typedef std::vector<ModelTexture> 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.
|
||||
*/
|
||||
class QTKAPI Model : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/* ModelManager typedef that will manage global model access. */
|
||||
typedef QHash<QString, Model *> ModelManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors, Destructors
|
||||
************************************************************************/
|
||||
|
||||
// Default model shaders are provided but we can override them in the ctor
|
||||
inline Model(
|
||||
const char * name, const char * path,
|
||||
const char * vertexShader = ":/model-basic.vert",
|
||||
const char * fragmentShader = ":/model-basic.frag") :
|
||||
mName(name),
|
||||
mModelPath(path), mVertexShader(vertexShader),
|
||||
mFragmentShader(fragmentShader) {
|
||||
loadModel(path);
|
||||
}
|
||||
|
||||
inline ~Model() override { mManager.remove(mName); }
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
void draw();
|
||||
void draw(QOpenGLShaderProgram & shader);
|
||||
|
||||
/**
|
||||
* Flip a texture associated with this model
|
||||
*
|
||||
* @param fileName The name of the texture to flip as it is stored on disk
|
||||
* @param flipX Flip the texture along the X axis
|
||||
* @param flipY Flip the texture along the Y axis
|
||||
*/
|
||||
void flipTexture(
|
||||
const std::string & fileName, bool flipX = false, bool flipY = true);
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Sets a uniform value
|
||||
*
|
||||
* @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 <typename T> void setUniform(const char * location, T value) {
|
||||
for(auto & mesh : mMeshes) {
|
||||
mesh.mProgram->bind();
|
||||
mesh.mProgram->setUniformValue(location, value);
|
||||
mesh.mProgram->release();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Accessor function for retrieving a ModelMesh globally.
|
||||
* The mesh is retrieved from the mManager private member.
|
||||
*
|
||||
* @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);
|
||||
|
||||
Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Loads a model in .obj, .fbx, .gltf, and other formats.
|
||||
* 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.
|
||||
* 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);
|
||||
|
||||
void processNode(aiNode * node, const aiScene * scene);
|
||||
|
||||
ModelMesh processMesh(aiMesh * mesh, const aiScene * scene);
|
||||
|
||||
ModelMesh::Textures loadMaterialTextures(
|
||||
aiMaterial * mat, aiTextureType type, const std::string & typeName);
|
||||
|
||||
void sortModels();
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
/* The position of this model in 3D space */
|
||||
Transform3D mTransform;
|
||||
|
||||
/* Static QHash used to store and access models globally. */
|
||||
static ModelManager mManager;
|
||||
|
||||
/* Container to store N loaded textures for this model. */
|
||||
ModelMesh::Textures mTexturesLoaded {};
|
||||
/* Container to store N loaded meshes for this model. */
|
||||
std::vector<ModelMesh> mMeshes {};
|
||||
/* The directory this model and it's textures are stored. */
|
||||
std::string mDirectory {};
|
||||
/* File names for shaders and 3D model on disk. */
|
||||
const char *mVertexShader, *mFragmentShader, *mModelPath;
|
||||
/* Name of the model object within the scene. */
|
||||
const char * mName;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MODEL_H
|
||||
79
src/qtk/CMakeLists.txt
Normal file
79
src/qtk/CMakeLists.txt
Normal file
@@ -0,0 +1,79 @@
|
||||
################################################################################
|
||||
## 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
|
||||
################################################################################
|
||||
set(
|
||||
QTK_LIBRARY_PUBLIC_HEADERS
|
||||
camera3d.h
|
||||
input.h
|
||||
meshrenderer.h
|
||||
model.h
|
||||
modelmesh.h
|
||||
object.h
|
||||
qtkapi.h
|
||||
qtkiostream.h
|
||||
qtkiosystem.h
|
||||
scene.h
|
||||
shape.h
|
||||
skybox.h
|
||||
texture.h
|
||||
transform3D.h
|
||||
)
|
||||
|
||||
set(
|
||||
QTK_LIBRARY_SOURCES
|
||||
camera3d.cpp
|
||||
input.cpp
|
||||
meshrenderer.cpp
|
||||
model.cpp
|
||||
modelmesh.cpp
|
||||
object.cpp
|
||||
qtkiostream.cpp
|
||||
qtkiosystem.cpp
|
||||
scene.cpp
|
||||
shape.cpp
|
||||
skybox.cpp
|
||||
texture.cpp
|
||||
transform3D.cpp
|
||||
)
|
||||
|
||||
qt6_add_big_resources(QTK_LIBRARY_SOURCES "${QTK_RESOURCES}/resources.qrc")
|
||||
qt_add_library(qtk_library STATIC EXCLUDE_FROM_ALL)
|
||||
target_sources(qtk_library PRIVATE ${QTK_LIBRARY_SOURCES})
|
||||
target_sources(
|
||||
qtk_library PUBLIC
|
||||
FILE_SET HEADERS
|
||||
BASE_DIRS $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}/src>
|
||||
BASE_DIRS $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include>
|
||||
FILES ${QTK_LIBRARY_PUBLIC_HEADERS}
|
||||
)
|
||||
|
||||
if(QTK_DEBUG)
|
||||
target_compile_definitions(qtk_library PUBLIC QTK_DEBUG)
|
||||
endif()
|
||||
|
||||
set_target_properties(
|
||||
qtk_library PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
qtk_library PUBLIC
|
||||
Qt6::Core Qt6::OpenGLWidgets Qt6::Widgets
|
||||
)
|
||||
|
||||
if(QTK_UPDATE_SUBMODULES OR NOT ASSIMP_NEW_INTERFACE)
|
||||
target_link_libraries(qtk_library PUBLIC assimp)
|
||||
elseif(ASSIMP_NEW_INTERFACE)
|
||||
target_link_libraries(qtk_library PUBLIC assimp::assimp)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(qtk_library PUBLIC OpenGL::GL)
|
||||
endif()
|
||||
@@ -1,24 +1,27 @@
|
||||
/*##############################################################################
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <camera3d.h>
|
||||
#include "camera3d.h"
|
||||
|
||||
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()
|
||||
@@ -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 ##
|
||||
@@ -11,14 +11,14 @@
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <transform3D.h>
|
||||
#include "qtkapi.h"
|
||||
#include "transform3D.h"
|
||||
|
||||
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
|
||||
@@ -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 ##
|
||||
@@ -11,13 +11,20 @@
|
||||
|
||||
#include <QCursor>
|
||||
|
||||
#include <input.h>
|
||||
#include "input.h"
|
||||
|
||||
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 <typename T> struct InputInstance : std::pair<T, Input::InputState> {
|
||||
typedef std::pair<T, Input::InputState> base_class;
|
||||
|
||||
@@ -28,6 +35,7 @@ template <typename T> struct InputInstance : std::pair<T, Input::InputState> {
|
||||
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 <typename TPair>
|
||||
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 <typename TPair> static inline void UpdateStates(TPair & instance) {
|
||||
switch(instance.second) {
|
||||
case Input::InputRegistered:
|
||||
@@ -77,11 +115,12 @@ template <typename TPair> static inline void UpdateStates(TPair & instance) {
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TPair>
|
||||
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 <typename Container> static inline void Update(Container & container) {
|
||||
typedef typename Container::iterator Iter;
|
||||
typedef typename Container::value_type TPair;
|
||||
@@ -96,27 +135,9 @@ template <typename Container> 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;
|
||||
}
|
||||
155
src/qtk/input.h
Normal file
155
src/qtk/input.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTOPENGL_INPUT_H
|
||||
#define QTOPENGL_INPUT_H
|
||||
|
||||
#include <QPoint>
|
||||
#include <Qt>
|
||||
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI Input {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* 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, // 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* @return Delta movement of mouse from previous to current position.
|
||||
*/
|
||||
static QPoint mouseDelta();
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTOPENGL_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: MeshRenderer class for quick object creation and drawing ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
@@ -8,41 +8,41 @@
|
||||
|
||||
#include <QImageReader>
|
||||
|
||||
#include <meshrenderer.h>
|
||||
#include <scene.h>
|
||||
#include <texture.h>
|
||||
#include "meshrenderer.h"
|
||||
#include "scene.h"
|
||||
#include "texture.h"
|
||||
|
||||
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), mVertexShader(":/multi-color.vert"),
|
||||
mFragmentShader(":/multi-color.frag"), mDrawType(GL_TRIANGLES) {
|
||||
Object(name, shape, QTK_MESH), mVertexShader(":/shaders/multi-color.vert"),
|
||||
mFragmentShader(":/shaders/multi-color.frag"), mDrawType(GL_TRIANGLES) {
|
||||
mShape = Shape(shape);
|
||||
init();
|
||||
sInstances.insert(name, this);
|
||||
}
|
||||
|
||||
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];
|
||||
sInstances.remove(mName.c_str());
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* 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];
|
||||
}
|
||||
226
src/qtk/meshrenderer.h
Normal file
226
src/qtk/meshrenderer.h
Normal file
@@ -0,0 +1,226 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MESHRENDERER_H
|
||||
#define QTK_MESHRENDERER_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "object.h"
|
||||
#include "qtkapi.h"
|
||||
#include "shape.h"
|
||||
|
||||
namespace Qtk {
|
||||
class QTKAPI MeshRenderer : public Object {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/** Static QHash of all mesh objects within the scene. */
|
||||
typedef QHash<QString, MeshRenderer *> MeshManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Initializes OpenGL buffers and settings for this MeshRenderer.
|
||||
*/
|
||||
void init();
|
||||
|
||||
/**
|
||||
* Draws this MeshRenderer.
|
||||
*/
|
||||
void draw();
|
||||
|
||||
/**
|
||||
* 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
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* 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; }
|
||||
|
||||
/**
|
||||
* @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 <typename T> 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 <typename T>
|
||||
inline void setUniform(const char * location, T value) {
|
||||
ShaderBindScope lock(&mProgram, mBound);
|
||||
mProgram.setUniformValue(location, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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");
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Retrieve a mesh by name stored within static QHash private member
|
||||
* @param name The name of the MeshRenderer we want to retrieve.
|
||||
* @return Pointer to the MeshRenderer, or nullptr if not found.
|
||||
*/
|
||||
static MeshRenderer * getInstance(const QString & name);
|
||||
|
||||
/**
|
||||
* @return Transform3D attached to this MeshRenderer.
|
||||
*/
|
||||
inline Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
static MeshManager sInstances;
|
||||
|
||||
int mDrawType {};
|
||||
std::string mVertexShader {}, mFragmentShader {};
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MESHRENDERER_H
|
||||
@@ -1,160 +1,37 @@
|
||||
/*##############################################################################
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <model.h>
|
||||
#include <resourcemanager.h>
|
||||
#include <scene.h>
|
||||
#include <texture.h>
|
||||
#include "model.h"
|
||||
#include "qtkiosystem.h"
|
||||
#include "scene.h"
|
||||
#include "texture.h"
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,34 +53,38 @@ 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) {
|
||||
Assimp::Importer import;
|
||||
|
||||
// JIC a relative path was used, get the absolute file path
|
||||
QFileInfo info(path.c_str());
|
||||
info.makeAbsolute();
|
||||
mDirectory = path[0] == ':' ? RM::getPath(path)
|
||||
: info.absoluteFilePath().toStdString();
|
||||
// If using a Qt Resource path, use QtkIOSystem for file handling.
|
||||
if(path.front() == ':') {
|
||||
import.SetIOHandler(new QtkIOSystem());
|
||||
}
|
||||
// Used as base path for loading model textures.
|
||||
mDirectory = path.substr(0, path.find_last_of('/'));
|
||||
|
||||
// Import the model, converting non-triangular geometry to triangles
|
||||
// + And flipping texture UVs, etc..
|
||||
// Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
|
||||
const aiScene * scene = import.ReadFile(
|
||||
mDirectory, aiProcess_Triangulate | aiProcess_FlipUVs
|
||||
| aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace
|
||||
| aiProcess_OptimizeMeshes | aiProcess_SplitLargeMeshes);
|
||||
path.c_str(), aiProcess_Triangulate | aiProcess_FlipUVs
|
||||
| aiProcess_GenSmoothNormals
|
||||
| aiProcess_CalcTangentSpace | aiProcess_OptimizeMeshes
|
||||
| aiProcess_SplitLargeMeshes);
|
||||
|
||||
// If there were errors, print and return
|
||||
if(!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) {
|
||||
qDebug() << "Error::ASSIMP::" << import.GetErrorString() << "\n";
|
||||
return;
|
||||
}
|
||||
// If there were no errors, find the directory that contains this model
|
||||
mDirectory = mDirectory.substr(0, mDirectory.find_last_of('/'));
|
||||
|
||||
// Pass the pointers to the root node and the scene to recursive function
|
||||
// + Base case breaks when no nodes left to process on model
|
||||
@@ -212,10 +93,10 @@ 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(mName, this);
|
||||
mManager.insert(getName().c_str(), this);
|
||||
}
|
||||
|
||||
void Model::processNode(aiNode * node, const aiScene * scene) {
|
||||
@@ -300,7 +181,6 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
|
||||
if(mesh->mMaterialIndex >= 0) {
|
||||
// Get the material attached to the model using Assimp
|
||||
aiMaterial * material = scene->mMaterials[mesh->mMaterialIndex];
|
||||
|
||||
// Get all diffuse textures from the material
|
||||
ModelMesh::Textures diffuseMaps = loadMaterialTextures(
|
||||
material, aiTextureType_DIFFUSE, "texture_diffuse");
|
||||
@@ -320,7 +200,9 @@ ModelMesh Model::processMesh(aiMesh * mesh, const aiScene * scene) {
|
||||
textures.insert(textures.end(), normalMaps.begin(), normalMaps.end());
|
||||
}
|
||||
|
||||
return {vertices, indices, textures, mVertexShader, mFragmentShader};
|
||||
return {
|
||||
vertices, indices, textures, mVertexShader.c_str(),
|
||||
mFragmentShader.c_str()};
|
||||
}
|
||||
|
||||
ModelMesh::Textures Model::loadMaterialTextures(
|
||||
@@ -364,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
|
||||
204
src/qtk/model.h
Normal file
204
src/qtk/model.h
Normal file
@@ -0,0 +1,204 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_MODEL_H
|
||||
#define QTK_MODEL_H
|
||||
|
||||
// Qt
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
// Assimp
|
||||
#include <assimp/postprocess.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
// Qtk
|
||||
#include "modelmesh.h"
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Model object that has a ModelMesh.
|
||||
* Top-level object that represents 3D models stored within a scene.
|
||||
*/
|
||||
class QTKAPI Model : public Object {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Typedefs
|
||||
************************************************************************/
|
||||
|
||||
/** ModelManager typedef that will manage global model access. */
|
||||
typedef QHash<QString, Model *> ModelManager;
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors, Destructors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* 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 = ":/shaders/model-basic.vert",
|
||||
const char * fragmentShader = ":/shaders/model-basic.frag") :
|
||||
Object(name, QTK_MODEL),
|
||||
mModelPath(path), mVertexShader(vertexShader),
|
||||
mFragmentShader(fragmentShader) {
|
||||
loadModel(mModelPath);
|
||||
}
|
||||
|
||||
inline ~Model() override { mManager.remove(getName().c_str()); }
|
||||
|
||||
/*************************************************************************
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Flip a texture associated with this model
|
||||
*
|
||||
* @param fileName The name of the texture to flip as it is stored on disk
|
||||
* @param flipX Flip the texture along the X axis
|
||||
* @param flipY Flip the texture along the Y axis
|
||||
*/
|
||||
void flipTexture(
|
||||
const std::string & fileName, bool flipX = false, bool flipY = true);
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* 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 <typename T>
|
||||
inline void setUniform(const char * location, T value) {
|
||||
for(auto & mesh : mMeshes) {
|
||||
mesh.mProgram->bind();
|
||||
mesh.mProgram->setUniformValue(location, value);
|
||||
mesh.mProgram->release();
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Accessor function for retrieving a ModelMesh globally.
|
||||
* The mesh is retrieved from the mManager private member.
|
||||
*
|
||||
* @param name The name of the model to load as it was constructed.
|
||||
* @return Pointer to the model stored within the scene.
|
||||
*/
|
||||
[[nodiscard]] static Model * getInstance(const char * name);
|
||||
|
||||
/**
|
||||
* @return Transform3D attached to this Model.
|
||||
*/
|
||||
inline Transform3D & getTransform() { return mTransform; }
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Loads a model in .obj, .fbx, .gltf, and other formats.
|
||||
* For a full list of formats see assimp documentation:
|
||||
* https://github.com/assimp/assimp/blob/master/doc/Fileformats.md
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* 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 ModelManager mManager;
|
||||
|
||||
/** Container to store N loaded textures for this model. */
|
||||
ModelMesh::Textures mTexturesLoaded {};
|
||||
/** Container to store N loaded meshes for this model. */
|
||||
std::vector<ModelMesh> mMeshes {};
|
||||
/** The directory this model and it's textures are stored. */
|
||||
std::string mDirectory {};
|
||||
/** File names for shaders and 3D model on disk. */
|
||||
std::string mVertexShader, mFragmentShader, mModelPath;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MODEL_H
|
||||
129
src/qtk/modelmesh.cpp
Normal file
129
src/qtk/modelmesh.cpp
Normal file
@@ -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 "modelmesh.h"
|
||||
#include "scene.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
|
||||
bool status = 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();
|
||||
}
|
||||
139
src/qtk/modelmesh.h
Normal file
139
src/qtk/modelmesh.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*##############################################################################
|
||||
## 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
|
||||
|
||||
#include <QOpenGLFunctions>
|
||||
|
||||
#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<ModelVertex> Vertices;
|
||||
typedef std::vector<GLuint> Indices;
|
||||
typedef std::vector<ModelTexture> 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
|
||||
@@ -1,11 +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: Object class for storing object data ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <object.h>
|
||||
#include "object.h"
|
||||
|
||||
using namespace Qtk;
|
||||
@@ -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,11 +13,13 @@
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
|
||||
#include <mesh.h>
|
||||
#include <qtkapi.h>
|
||||
#include <texture.h>
|
||||
#include "qtkapi.h"
|
||||
#include "shape.h"
|
||||
#include "texture.h"
|
||||
|
||||
namespace Qtk {
|
||||
class Model;
|
||||
|
||||
/**
|
||||
* Object base class for objects that can exist within a scene.
|
||||
* An object could be a Cube, Skybox, 3D Model, or other standalone entities.
|
||||
@@ -31,19 +33,32 @@ namespace Qtk {
|
||||
************************************************************************/
|
||||
|
||||
friend MeshRenderer;
|
||||
friend Model;
|
||||
|
||||
/**
|
||||
* Enum flag to identify Object type without casting.
|
||||
*/
|
||||
enum Type { QTK_OBJECT, QTK_MESH, QTK_MODEL };
|
||||
|
||||
/*************************************************************************
|
||||
* Constructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
// Initialize an object with no shape data assigned
|
||||
explicit Object(const char * name) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false) {}
|
||||
explicit Object(const char * name, Type type) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mBound(false),
|
||||
mType(type) {
|
||||
initResources();
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
// Initialize an object with shape data assigned
|
||||
Object(const char * name, const ShapeBase & shape) :
|
||||
Object(const char * name, const ShapeBase & shape, Type type) :
|
||||
mName(name), mVBO(QOpenGLBuffer::VertexBuffer), mShape(shape),
|
||||
mBound(false) {}
|
||||
mBound(false), mType(type) {
|
||||
initResources();
|
||||
setObjectName(name);
|
||||
}
|
||||
|
||||
~Object() override = default;
|
||||
|
||||
@@ -77,6 +92,10 @@ namespace Qtk {
|
||||
return mShape.mVertices;
|
||||
}
|
||||
|
||||
[[nodiscard]] inline std::string getName() const { return mName; }
|
||||
|
||||
[[nodiscard]] inline const Type & getType() const { return mType; }
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
@@ -141,8 +160,9 @@ namespace Qtk {
|
||||
Transform3D mTransform;
|
||||
Shape mShape;
|
||||
Texture mTexture;
|
||||
const char * mName;
|
||||
std::string mName;
|
||||
bool mBound;
|
||||
Type mType = QTK_OBJECT;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
62
src/qtk/qtkapi.h
Normal file
62
src/qtk/qtkapi.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
#ifndef QTK_QTKAPI_H
|
||||
#define QTK_QTKAPI_H
|
||||
|
||||
#include <QFile>
|
||||
#include <QWidget>
|
||||
#include <QtCore/QtGlobal>
|
||||
|
||||
#ifdef QTK_SHARED
|
||||
#if defined(QTK_EXPORT)
|
||||
#define QTKAPI Q_DECL_EXPORT
|
||||
#else
|
||||
#define QTKAPI Q_DECL_IMPORT
|
||||
#endif
|
||||
#else
|
||||
#define QTKAPI
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize Qt resources required by the Qtk library.
|
||||
* This cannot be defined within any namespace, but can be called by ctors.
|
||||
* See object.h for example.
|
||||
*/
|
||||
inline void initResources() {
|
||||
Q_INIT_RESOURCE(resources);
|
||||
}
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Flag to set context for debug messages.
|
||||
*/
|
||||
enum DebugContext { Status, Debug, Warn, Error, Fatal };
|
||||
|
||||
/**
|
||||
* Find top level parent for a widget.
|
||||
*
|
||||
* @param widget Widget to start the search from.
|
||||
* @return Top level parent widget or Q_NULLPTR if no parent
|
||||
*/
|
||||
static QWidget * topLevelParent(QWidget * widget) {
|
||||
QString name = widget->objectName();
|
||||
while(widget->parentWidget() != Q_NULLPTR) {
|
||||
widget = widget->parentWidget();
|
||||
}
|
||||
return widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Default icon to use for Qtk desktop application.
|
||||
*/
|
||||
static QIcon getIcon() {
|
||||
return QIcon(":/icons/icon.png");
|
||||
}
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_QTKAPI_H
|
||||
82
src/qtk/qtkiostream.cpp
Normal file
82
src/qtk/qtkiostream.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO stream for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "qtkiostream.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
QtkIOStream::QtkIOStream(const char * pFile, const char * pMode) :
|
||||
mFile(pFile) {
|
||||
QString mode(pMode);
|
||||
bool read = mode.contains('r');
|
||||
bool write = mode.contains('w');
|
||||
if(read && write) {
|
||||
mFile.open(QIODevice::ReadWrite);
|
||||
} else if(read) {
|
||||
mFile.open(QIODevice::ReadOnly);
|
||||
} else if(write) {
|
||||
mFile.open(QIODevice::WriteOnly);
|
||||
} else {
|
||||
qDebug() << "[Qtk::QtkIOStream] Invalid file open mode: " << mode << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
size_t QtkIOStream::Read(void * pvBuffer, size_t pSize, size_t pCount) {
|
||||
size_t read = 0;
|
||||
do {
|
||||
auto readSize = mFile.read((char *)pvBuffer + read, pSize);
|
||||
if(readSize < 0) {
|
||||
qDebug() << "[Qtk::QtkIOStream] Failed to read (" << pSize
|
||||
<< ") bytes from file at: " << mFile.filesystemFileName().c_str()
|
||||
<< "\n";
|
||||
return -1;
|
||||
}
|
||||
read += readSize;
|
||||
} while(pCount--);
|
||||
return read;
|
||||
}
|
||||
|
||||
size_t QtkIOStream::Write(const void * pvBuffer, size_t pSize, size_t pCount) {
|
||||
size_t wrote = 0;
|
||||
do {
|
||||
auto writeSize = mFile.write((char *)pvBuffer + wrote, pSize);
|
||||
if(writeSize < 0) {
|
||||
qDebug() << "[Qtk::QtkIOStream] Failed to write buffer with size ("
|
||||
<< pSize
|
||||
<< ") to file at: " << mFile.filesystemFileName().c_str()
|
||||
<< "\n";
|
||||
return -1;
|
||||
}
|
||||
wrote += writeSize;
|
||||
} while(pCount--);
|
||||
return wrote;
|
||||
}
|
||||
|
||||
aiReturn QtkIOStream::Seek(size_t pOffset, aiOrigin pOrigin) {
|
||||
return mFile.seek(pOffset) ? aiReturn_SUCCESS : aiReturn_FAILURE;
|
||||
}
|
||||
|
||||
size_t QtkIOStream::Tell() const {
|
||||
return mFile.pos();
|
||||
}
|
||||
|
||||
size_t QtkIOStream::FileSize() const {
|
||||
return mFile.size();
|
||||
}
|
||||
|
||||
void QtkIOStream::Flush() {
|
||||
mFile.flush();
|
||||
}
|
||||
85
src/qtk/qtkiostream.h
Normal file
85
src/qtk/qtkiostream.h
Normal file
@@ -0,0 +1,85 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO stream for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#ifndef QTK_QTKIOSTREAM_H
|
||||
#define QTK_QTKIOSTREAM_H
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Custom Assimp IO stream to support QtkIOSystem file handling.
|
||||
* Allows direct use of Qt Resource paths for loading models in Assimp.
|
||||
*/
|
||||
class QtkIOStream : public Assimp::IOStream {
|
||||
friend class QtkIOSystem;
|
||||
|
||||
protected:
|
||||
/** Constructor protected for private usage by QtkIOSystem */
|
||||
QtkIOStream(const char * pFile, const char * pMode);
|
||||
|
||||
public:
|
||||
~QtkIOStream() = default;
|
||||
|
||||
/**
|
||||
* Reads data into pvBuffer in pCount batches of length pSize.
|
||||
* The final pvBuffer will contain data read from all batches.
|
||||
*
|
||||
* @param pvBuffer Buffer to read data into.
|
||||
* @param pSize Size in bytes for each read.
|
||||
* @param pCount Number of reads to perform.
|
||||
* @return Length of total bytes read into pvBuffer, or -1 on failure.
|
||||
*/
|
||||
size_t Read(void * pvBuffer, size_t pSize, size_t pCount) override;
|
||||
|
||||
/**
|
||||
* Writes data from pvBuffer in pCount batches of length pSize.
|
||||
* The final mFile member will contain all input data from pvBuffer.
|
||||
*
|
||||
* @param pvBuffer Buffer to write data from.
|
||||
* @param pSize Size in bytes for each write.
|
||||
* @param pCount Number of writes to perfom.
|
||||
* @return Length of total bytes wrote into buffer, or -1 on failure.
|
||||
*/
|
||||
size_t Write(const void * pvBuffer, size_t pSize, size_t pCount) override;
|
||||
|
||||
/**
|
||||
* Change the current read position in the mFile Qt resource.
|
||||
*
|
||||
* @param pOffset Offset position to set.
|
||||
* @param pOrigin Origin position to use for relative offset.
|
||||
* @return aiReturn_SUCCESS, or aiReturn_FAILURE on failure.
|
||||
*/
|
||||
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
|
||||
|
||||
/**
|
||||
* @return The current position in mFile.
|
||||
*/
|
||||
[[nodiscard]] size_t Tell() const override;
|
||||
|
||||
/**
|
||||
* @return The total size of mFile.
|
||||
*/
|
||||
[[nodiscard]] size_t FileSize() const override;
|
||||
|
||||
/**
|
||||
* Flushes buffered data to mFile.
|
||||
*/
|
||||
void Flush() override;
|
||||
|
||||
private:
|
||||
// Corresponding file for Qt Resource path.
|
||||
QFile mFile;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_QTKIOSTREAM_H
|
||||
39
src/qtk/qtkiosystem.cpp
Normal file
39
src/qtk/qtkiosystem.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO system for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "qtkiosystem.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Member Functions
|
||||
******************************************************************************/
|
||||
|
||||
bool QtkIOSystem::Exists(const char * pFile) const {
|
||||
return QFileInfo::exists(pFile);
|
||||
}
|
||||
|
||||
char QtkIOSystem::getOsSeparator() const {
|
||||
#ifndef _WIN32
|
||||
return '/';
|
||||
#else
|
||||
return '\\';
|
||||
#endif
|
||||
}
|
||||
|
||||
Assimp::IOStream * QtkIOSystem::Open(const char * pFile, const char * pMode) {
|
||||
if(!QFileInfo::exists(pFile)) {
|
||||
qDebug() << "[Qtk::QtkIOSystem] failed to open file: " << pFile << "\n";
|
||||
return nullptr;
|
||||
}
|
||||
return new QtkIOStream(pFile, pMode);
|
||||
}
|
||||
|
||||
void QtkIOSystem::Close(Assimp::IOStream * pFile) {
|
||||
delete pFile;
|
||||
}
|
||||
53
src/qtk/qtkiosystem.h
Normal file
53
src/qtk/qtkiosystem.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
||||
## About: Custom IO system for Qtk to support Qt Resource paths in Assimp ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <assimp/IOStream.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include "qtkapi.h"
|
||||
#include "qtkiostream.h"
|
||||
|
||||
#ifndef QTK_QTKIOSYSTEM_H
|
||||
#define QTK_QTKIOSYSTEM_H
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* Assimp IO system for loading models with assimp, using Qt Resource paths.
|
||||
*/
|
||||
class QtkIOSystem : public Assimp::IOSystem {
|
||||
public:
|
||||
QtkIOSystem() = default;
|
||||
~QtkIOSystem() = default;
|
||||
|
||||
/**
|
||||
* @param pFile File path to check.
|
||||
* @return True if the file exists, else false.
|
||||
*/
|
||||
bool Exists(const char * pFile) const override;
|
||||
|
||||
/**
|
||||
* @return Path separator for platform OS.
|
||||
*/
|
||||
[[nodiscard]] char getOsSeparator() const override;
|
||||
|
||||
/**
|
||||
* @param pFile File to open for read / writing.
|
||||
* @param pMode Mode to open file. See `man fopen`.
|
||||
* @return QtkIOStream for the opened file.
|
||||
*/
|
||||
Assimp::IOStream * Open(
|
||||
const char * pFile, const char * pMode = "rb") override;
|
||||
|
||||
/**
|
||||
* @param pFile File to close.
|
||||
*/
|
||||
void Close(Assimp::IOStream * pFile) override;
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_QTKIOSYSTEM_H
|
||||
93
src/qtk/scene.cpp
Normal file
93
src/qtk/scene.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include "scene.h"
|
||||
#include "camera3d.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
Camera3D Scene::mCamera;
|
||||
QMatrix4x4 Scene::mProjection;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors / Destructors
|
||||
******************************************************************************/
|
||||
|
||||
Scene::Scene() : mSceneName("Default Scene") {
|
||||
mCamera.getTransform().setTranslation(0.0f, 0.0f, 20.0f);
|
||||
mCamera.getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
Scene::~Scene() {
|
||||
for(auto & mesh : mMeshes) {
|
||||
delete mesh;
|
||||
}
|
||||
for(auto & model : mModels) {
|
||||
delete model;
|
||||
}
|
||||
delete mSkybox;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
void Scene::draw() {
|
||||
if(!mInit) {
|
||||
initializeOpenGLFunctions();
|
||||
init();
|
||||
mInit = true;
|
||||
}
|
||||
if(mSkybox != Q_NULLPTR) {
|
||||
mSkybox->draw();
|
||||
}
|
||||
for(auto & model : mModels) {
|
||||
model->draw();
|
||||
}
|
||||
for(const auto & mesh : mMeshes) {
|
||||
mesh->draw();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Object *> Scene::getObjects() const {
|
||||
// All scene objects must inherit from Qtk::Object.
|
||||
std::vector<Object *> objects(mMeshes.begin(), mMeshes.end());
|
||||
for(auto model : mModels) {
|
||||
objects.push_back(dynamic_cast<Object *>(model));
|
||||
if(objects.back() == nullptr) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return objects;
|
||||
}
|
||||
|
||||
Object * Scene::getObject(const QString & name) {
|
||||
for(auto object : getObjects()) {
|
||||
if(object->getName() == name.toStdString()) {
|
||||
return object;
|
||||
}
|
||||
}
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
void Scene::setSkybox(Skybox * skybox) {
|
||||
delete mSkybox;
|
||||
mSkybox = skybox;
|
||||
}
|
||||
|
||||
template <> MeshRenderer * Scene::addObject(MeshRenderer * object) {
|
||||
mMeshes.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
}
|
||||
|
||||
template <> Model * Scene::addObject(Model * object) {
|
||||
mModels.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
}
|
||||
221
src/qtk/scene.h
Normal file
221
src/qtk/scene.h
Normal file
@@ -0,0 +1,221 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTK_SCENE_H
|
||||
#define QTK_SCENE_H
|
||||
|
||||
#include <QMatrix4x4>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "camera3d.h"
|
||||
#include "meshrenderer.h"
|
||||
#include "model.h"
|
||||
#include "skybox.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* An abstract Scene class to inherit from when building new scenes.
|
||||
*
|
||||
* This class provides the following objects to any inheriting scene:
|
||||
* Skybox, Camera
|
||||
* This class also provides containers for N instances of these objects:
|
||||
* MeshRenderers, Models
|
||||
*
|
||||
* To inherit from this class and define our own scene we must:
|
||||
*
|
||||
* Override and define the `init()` virtual member function. If we want our
|
||||
* scene to render using a Skybox, we should also initialize the mSkybox
|
||||
* member within the overridden definition of `init()` using
|
||||
* `Scene::setSkybox(...)`
|
||||
*
|
||||
* If the scene is to render any kind of movement we are required to override
|
||||
* the `update()` virtual method.
|
||||
*
|
||||
* If the child scene adds any objects which are not managed (drawn) by this
|
||||
* base class, the child scene class must also override the `draw()` method.
|
||||
*/
|
||||
class Scene : public QObject, protected QOpenGLFunctions {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Contructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
Scene();
|
||||
|
||||
virtual ~Scene();
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Initialize objects within the scene
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
/**
|
||||
* Function called during OpenGL drawing event.
|
||||
*
|
||||
* This function is only called when the widget is redrawn.
|
||||
*/
|
||||
virtual void draw();
|
||||
|
||||
/**
|
||||
* Function called to update the QOpenGLWidget. Does not trigger a redraw.
|
||||
*
|
||||
* Calling this several times will still result in only one repaint.
|
||||
*/
|
||||
virtual void update() {}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @return All Qtk::Objects within the scene.
|
||||
* If any object is invalid, we return an empty vector.
|
||||
*/
|
||||
[[nodiscard]] std::vector<Object *> 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.
|
||||
*/
|
||||
[[nodiscard]] inline static Camera3D & getCamera() { return mCamera; }
|
||||
|
||||
/**
|
||||
* @return View matrix for the camera attached to this scene.
|
||||
*/
|
||||
[[nodiscard]] inline static QMatrix4x4 getViewMatrix() {
|
||||
return mCamera.toMatrix();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Projection matrix for the current view into the scene.
|
||||
*/
|
||||
[[nodiscard]] inline static QMatrix4x4 & getProjectionMatrix() {
|
||||
return mProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The active skybox for this scene.
|
||||
*/
|
||||
[[nodiscard]] inline Skybox * getSkybox() { return mSkybox; }
|
||||
|
||||
/**
|
||||
* @return The name for this scene. This is entirely user defined and not
|
||||
* a Qt objectName.
|
||||
*/
|
||||
[[nodiscard]] inline QString getSceneName() const { return mSceneName; }
|
||||
|
||||
/**
|
||||
* @return All MeshRenderers within the scene.
|
||||
*/
|
||||
[[nodiscard]] inline const std::vector<MeshRenderer *> & getMeshes()
|
||||
const {
|
||||
return mMeshes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return All Models within the scene.
|
||||
*/
|
||||
[[nodiscard]] inline const std::vector<Model *> & getModels() const {
|
||||
return mModels;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* @param skybox New skybox to use for this scene.
|
||||
*/
|
||||
void setSkybox(Skybox * skybox);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
template <typename T> T * addObject(T * object);
|
||||
|
||||
/**
|
||||
* @param name The name to use for this scene.
|
||||
*/
|
||||
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;
|
||||
|
||||
QString mSceneName;
|
||||
/* The skybox for this scene. */
|
||||
Skybox * mSkybox {};
|
||||
/* MeshRenderers used simple geometry. */
|
||||
std::vector<MeshRenderer *> mMeshes {};
|
||||
/* Models used for storing 3D models in the scene. */
|
||||
std::vector<Model *> mModels {};
|
||||
};
|
||||
|
||||
class SceneEmpty : public Scene {
|
||||
public:
|
||||
void init() override { setSceneName("Empty Scene"); }
|
||||
|
||||
void draw() override { Scene::draw(); }
|
||||
|
||||
void update() override { Scene::update(); }
|
||||
};
|
||||
|
||||
class SceneInterface : public Scene {
|
||||
public:
|
||||
explicit SceneInterface(Scene * scene) : mScene(scene) {}
|
||||
|
||||
void init() override { mScene->init(); }
|
||||
|
||||
void draw() override { mScene->draw(); }
|
||||
|
||||
void update() override { mScene->update(); }
|
||||
|
||||
protected:
|
||||
Scene * mScene;
|
||||
};
|
||||
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_SCENE_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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <mesh.h>
|
||||
#include "shape.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
@@ -1,25 +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: 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 <utility>
|
||||
|
||||
#include <QOpenGLWidget>
|
||||
#include <QVector2D>
|
||||
#include <QVector3D>
|
||||
#include <utility>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <transform3D.h>
|
||||
|
||||
namespace Qtk {
|
||||
class MeshRenderer;
|
||||
|
||||
class Object;
|
||||
#include "qtkapi.h"
|
||||
#include "transform3D.h"
|
||||
|
||||
// Define vertices for drawing a cube using two faces (8 vertex points)
|
||||
// Front Vertices
|
||||
@@ -62,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
|
||||
@@ -78,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<QVector3D> Vertices;
|
||||
typedef std::vector<QVector3D> Colors;
|
||||
@@ -105,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 = {}) :
|
||||
@@ -117,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]);
|
||||
}
|
||||
@@ -145,7 +172,6 @@ namespace Qtk {
|
||||
************************************************************************/
|
||||
|
||||
DrawMode mDrawMode;
|
||||
|
||||
Vertices mVertices {};
|
||||
Colors mColors {};
|
||||
Indices mIndices {};
|
||||
@@ -160,6 +186,7 @@ namespace Qtk {
|
||||
************************************************************************/
|
||||
|
||||
friend MeshRenderer;
|
||||
|
||||
friend Object;
|
||||
|
||||
/*************************************************************************
|
||||
@@ -174,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);
|
||||
@@ -209,4 +251,4 @@ namespace Qtk {
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_MESH_H
|
||||
#endif // QTK_SHAPE_H
|
||||
@@ -1,17 +1,32 @@
|
||||
/*##############################################################################
|
||||
## 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <scene.h>
|
||||
#include <skybox.h>
|
||||
#include <texture.h>
|
||||
#include "skybox.h"
|
||||
#include "scene.h"
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors / Destructors
|
||||
******************************************************************************/
|
||||
|
||||
Skybox::Skybox(const std::string & name) :
|
||||
Skybox(
|
||||
":/textures/skybox/right.png", ":/textures/skybox/top.png",
|
||||
":/textures/skybox/front.png", ":/textures/skybox/left.png",
|
||||
":/textures/skybox/bottom.png", ":/textures/skybox/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 +42,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
|
||||
******************************************************************************/
|
||||
@@ -73,8 +78,10 @@ void Skybox::init() {
|
||||
|
||||
// Set up shader program
|
||||
mProgram.create();
|
||||
mProgram.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/skybox.vert");
|
||||
mProgram.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/skybox.frag");
|
||||
mProgram.addShaderFromSourceFile(
|
||||
QOpenGLShader::Vertex, ":/shaders/skybox.vert");
|
||||
mProgram.addShaderFromSourceFile(
|
||||
QOpenGLShader::Fragment, ":/shaders/skybox.frag");
|
||||
mProgram.link();
|
||||
mProgram.bind();
|
||||
|
||||
@@ -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 ##
|
||||
@@ -15,10 +15,10 @@
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
|
||||
#include <camera3d.h>
|
||||
#include <mesh.h>
|
||||
#include <qtkapi.h>
|
||||
#include <texture.h>
|
||||
#include "camera3d.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();
|
||||
|
||||
/*************************************************************************
|
||||
@@ -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 ##
|
||||
@@ -8,9 +8,8 @@
|
||||
|
||||
#include <QDebug>
|
||||
#include <QImageReader>
|
||||
#include <utility>
|
||||
|
||||
#include <texture.h>
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
@@ -20,8 +19,8 @@ QImage * OpenGLTextureFactory::initImage(
|
||||
QImageReader::setAllocationLimit(512);
|
||||
auto loadedImage = new QImage(QImage(image).mirrored(flipX, flipY));
|
||||
if(loadedImage->isNull()) {
|
||||
qDebug() << "Error loading image: " << image << "\n";
|
||||
qDebug() << QImageReader::supportedImageFormats();
|
||||
qDebug() << "[Qtk::OpenGLTextureFactory] Error loading image: " << image
|
||||
<< "\nSupported types: " << QImageReader::supportedImageFormats();
|
||||
return Q_NULLPTR;
|
||||
}
|
||||
|
||||
@@ -58,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<QImage> faceTextures = {std::move(right), std::move(top),
|
||||
std::move(front), std::move(left),
|
||||
std::move(bottom), std::move(back)};
|
||||
std::vector<QImage> faceTextures = {right, top, front, left, bottom, back};
|
||||
// Initialize skybox cubemap texture
|
||||
texture->create();
|
||||
texture->bind();
|
||||
@@ -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 ##
|
||||
@@ -9,11 +9,12 @@
|
||||
#ifndef QTOPENGL_TEXTURE_H
|
||||
#define QTOPENGL_TEXTURE_H
|
||||
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
#include <utility>
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLTexture>
|
||||
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
@@ -155,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) {
|
||||
@@ -208,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) {
|
||||
@@ -215,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;
|
||||
}
|
||||
@@ -235,7 +299,6 @@ namespace Qtk {
|
||||
/* Path to this texture on disk or Qt resource. */
|
||||
const char * mPath {};
|
||||
};
|
||||
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTOPENGL_TEXTURE_H
|
||||
@@ -1,13 +1,13 @@
|
||||
/*##############################################################################
|
||||
## 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 ##
|
||||
## ##
|
||||
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <transform3D.h>
|
||||
#include "transform3D.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
@@ -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 {
|
||||
@@ -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 ##
|
||||
## ##
|
||||
@@ -15,12 +15,10 @@
|
||||
#include <QVector3D>
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#endif
|
||||
|
||||
#include <qtkapi.h>
|
||||
#include "qtkapi.h"
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
@@ -37,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));
|
||||
}
|
||||
@@ -114,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;
|
||||
@@ -156,7 +257,6 @@ namespace Qtk {
|
||||
#endif
|
||||
};
|
||||
|
||||
// Qt Streams
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
QDebug operator<<(QDebug dbg, const Transform3D & transform);
|
||||
#endif
|
||||
@@ -1,2 +0,0 @@
|
||||
|
||||
#define QTK_RESOURCES "@QTK_RESOURCES@"
|
||||
@@ -1,53 +0,0 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#include <camera3d.h>
|
||||
#include <resourcemanager.h>
|
||||
#include <scene.h>
|
||||
#include <texture.h>
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
Camera3D Scene::mCamera;
|
||||
QMatrix4x4 Scene::mProjection;
|
||||
|
||||
/*******************************************************************************
|
||||
* Constructors, Destructors
|
||||
******************************************************************************/
|
||||
|
||||
Scene::Scene() {
|
||||
mCamera.getTransform().setTranslation(0.0f, 0.0f, 20.0f);
|
||||
mCamera.getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
Scene::~Scene() {
|
||||
for(auto & mesh : mMeshes) {
|
||||
delete mesh;
|
||||
}
|
||||
for(auto & model : mModels) {
|
||||
delete model;
|
||||
}
|
||||
delete mSkybox;
|
||||
}
|
||||
|
||||
void Scene::privateDraw() {
|
||||
if(!mInit) {
|
||||
initializeOpenGLFunctions();
|
||||
init();
|
||||
mInit = true;
|
||||
}
|
||||
if(mSkybox != Q_NULLPTR) {
|
||||
mSkybox->draw();
|
||||
}
|
||||
for(auto & model : mModels) {
|
||||
model->draw();
|
||||
}
|
||||
for(const auto & mesh : mMeshes) {
|
||||
mesh->draw();
|
||||
}
|
||||
}
|
||||
125
src/scene.h
125
src/scene.h
@@ -1,125 +0,0 @@
|
||||
/*##############################################################################
|
||||
## Author: Shaun Reed ##
|
||||
## Legal: All Content (c) 2022 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 ##
|
||||
##############################################################################*/
|
||||
|
||||
#ifndef QTK_SCENE_H
|
||||
#define QTK_SCENE_H
|
||||
|
||||
#include <camera3d.h>
|
||||
#include <meshrenderer.h>
|
||||
#include <model.h>
|
||||
#include <skybox.h>
|
||||
|
||||
#include <QMatrix4x4>
|
||||
|
||||
namespace Qtk {
|
||||
/**
|
||||
* An abstract Scene class to inherit from when building new scenes.
|
||||
*
|
||||
* This class provides the following objects to any inheriting scene:
|
||||
* Skybox, Camera
|
||||
* This class also provides containers for N instances of these objects:
|
||||
* MeshRenderers, Models
|
||||
*
|
||||
* To inherit from this class and define our own scene we must:
|
||||
*
|
||||
* Override and define the `init()` virtual member function. If we want our
|
||||
* scene to render using a Skybox, we should also initialize the mSkybox
|
||||
* member within the overridden definition of `init()` using
|
||||
* `Scene::setSkybox(...)`
|
||||
*
|
||||
* If the scene is to render any kind of movement we are required to override
|
||||
* the `update()` virtual method.
|
||||
*
|
||||
* If the child scene adds any objects which are not managed (drawn) by this
|
||||
* base class, the child scene class must also override the `draw()` method.
|
||||
*/
|
||||
class Scene : protected QOpenGLFunctions {
|
||||
public:
|
||||
/*************************************************************************
|
||||
* Contructors / Destructors
|
||||
************************************************************************/
|
||||
|
||||
Scene();
|
||||
|
||||
~Scene();
|
||||
|
||||
/*************************************************************************
|
||||
* Public Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Initialize objects within the scene
|
||||
*/
|
||||
virtual void init() = 0;
|
||||
|
||||
/**
|
||||
* Function called during OpenGL drawing event.
|
||||
*
|
||||
* This function is only called when the widget is redrawn.
|
||||
*/
|
||||
virtual void draw() { privateDraw(); };
|
||||
|
||||
/**
|
||||
* Function called to update the QOpenGLWidget. Does not trigger a redraw.
|
||||
*
|
||||
* Calling this several times will still result in only one repaint.
|
||||
*/
|
||||
virtual void update() {}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
||||
static Camera3D & getCamera() { return mCamera; }
|
||||
|
||||
static QMatrix4x4 getViewMatrix() { return mCamera.toMatrix(); }
|
||||
|
||||
static QMatrix4x4 & getProjectionMatrix() { return mProjection; }
|
||||
|
||||
inline Skybox * getSkybox() { return mSkybox; }
|
||||
|
||||
/*************************************************************************
|
||||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
inline void setSkybox(Skybox * skybox) { mSkybox = skybox; }
|
||||
|
||||
private:
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
||||
static Camera3D mCamera;
|
||||
static QMatrix4x4 mProjection;
|
||||
bool mInit = false;
|
||||
|
||||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
|
||||
/**
|
||||
* Handles drawing members encapsulated by this base class.
|
||||
* Child classes do not need to draw these objects manually.
|
||||
*/
|
||||
void privateDraw();
|
||||
|
||||
protected:
|
||||
/*************************************************************************
|
||||
* Protected Members
|
||||
************************************************************************/
|
||||
|
||||
/* The skybox for this scene. */
|
||||
Skybox * mSkybox {};
|
||||
/* MeshRenderers used simple geometry. */
|
||||
std::vector<MeshRenderer *> mMeshes {};
|
||||
/* Models used for storing 3D models in the scene. */
|
||||
std::vector<Model *> mModels {};
|
||||
};
|
||||
} // namespace Qtk
|
||||
|
||||
#endif // QTK_SCENE_H
|
||||
Reference in New Issue
Block a user