Remove large resources. (#16)

This commit is contained in:
2025-03-22 20:55:59 +00:00
parent d0c8316f79
commit d827d02a15
185 changed files with 2504 additions and 527675 deletions

View File

@@ -2,70 +2,99 @@
## 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 ##
## All Content (c) 2025 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 Plugins
################################################################################
# Create a Qt Designer plugin for a collection of widgets from our library.
qt_add_plugin(qtk_plugins SHARED)
target_sources(
qtk_plugins PRIVATE
widgetplugincollection.cpp widgetplugincollection.h
widgetplugin.cpp widgetplugin.h
)
target_link_libraries(qtk_plugins PUBLIC qtk_plugin_library)
################################################################################
# Final Qtk Application
# Qtk Application
################################################################################
set(
QTK_GUI_SOURCES
qtkscene.cpp qtkscene.h
main.cpp
)
# Build without the example scene if QTK_GUI_SCENE is unset.
if (QTK_GUI_SCENE)
set(QTK_GUI_SOURCES
qtkmainwindow.cpp qtkmainwindow.h qtkmainwindow.ui
# This scene will clone a git repository for required 3D models.
qtkscene.cpp qtkscene.h
main.cpp
)
qt6_add_big_resources(QTK_GUI_SOURCES "${QTK_RESOURCES}/resources.qrc")
else()
# The scene will use a default skybox with no models or examples.
# Models can be added by click-and-dragging an .obj into the scene.
set(QTK_GUI_SOURCES
qtkmainwindow.cpp qtkmainwindow.h qtkmainwindow.ui
main.cpp
)
qt6_add_big_resources(
QTK_GUI_SOURCES
"${QTK_RESOURCES}/minimal_resources.qrc"
)
endif()
qt_add_executable(qtk_gui ${QTK_GUI_SOURCES})
target_link_libraries(qtk_gui PRIVATE qtk_plugin_library)
set_target_properties(
qtk_gui PROPERTIES
WIN32_EXECUTABLE TRUE
if (QTK_GUI_SCENE)
target_compile_definitions(qtk_gui PRIVATE -DQTK_GUI_SCENE)
endif()
if (WIN32)
set_target_properties(qtk_gui PROPERTIES WIN32_EXECUTABLE TRUE)
elseif(APPLE)
set_target_properties(
qtk_gui PROPERTIES
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME Qtk
MACOSX_BUNDLE_ICON_FILE ${QTK_OSX_ICONS}
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_COPYRIGHT ${QTK_COPYRIGHT}
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)
)
endif()
# qt_generate_deploy_app_script supports Windows and OSX in QtCore >= 6.3.
# qt_generate_deploy_app_script is supported on Linux in QtCore >= 6.5.0.
if((Qt6_VERSION VERSION_GREATER_EQUAL "6.3.0" AND (WIN32 OR APPLE))
OR Qt6_VERSION VERSION_GREATER_EQUAL "6.5.0")
install(
TARGETS qtk_gui
COMPONENT qtk_gui
BUNDLE DESTINATION .
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
RUNTIME DESTINATION bin
)
qt_generate_deploy_app_script(
TARGET qtk_gui
OUTPUT_SCRIPT QTK_DEPLOY_SCRIPT
NO_UNSUPPORTED_PLATFORM_ERROR
)
install(SCRIPT ${QTK_DEPLOY_SCRIPT} COMPONENT qtk_gui)
endif()
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_gui.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()

View File

@@ -1,33 +0,0 @@
/*##############################################################################
## 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);
}
}

View File

@@ -1,140 +0,0 @@
/*##############################################################################
## 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

View File

@@ -1,33 +0,0 @@
<?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>

View File

@@ -9,20 +9,22 @@
#include <QApplication>
#include "qtkmainwindow.h"
#include "qtkscene.h"
int main(int argc, char * argv[]) {
Q_INIT_RESOURCE(resources);
int main(int argc, char * argv[])
{
initResources();
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));
// NOTE: We set the scene here and not in QtkMainWindow to detach the scene
// from the QtkWidget plugin (qtk_plugin_library build target).
// Once we can save / load scenes, this call, and QtkScene, can be removed.
window->setScene(new AppScene);
window->show();
return QApplication::exec();
}

View File

@@ -7,16 +7,14 @@
##############################################################################*/
#include "qtkmainwindow.h"
#include "qtkscene.h"
#include "ui_qtkmainwindow.h"
MainWindow * MainWindow::mainWindow_ = Q_NULLPTR;
/*******************************************************************************
* Constructors / Destructors
******************************************************************************/
MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent)
{
ui_ = new Ui::MainWindow;
setObjectName("MainWindow");
// For use in design mode using Qt Creator
@@ -26,19 +24,28 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
// Initialize static container for all active QtkWidgets
auto qtkWidgets = findChildren<Qtk::QtkWidget *>();
for(auto & qtkWidget : qtkWidgets) {
qtkWidget->setScene(new Qtk::SceneEmpty);
for (auto & qtkWidget : qtkWidgets) {
qtkWidget->setMainWindow(this);
// NOTE: Set a temporary scene for the widget to use for initialization.
// This should be replaced by loading a scene, or creating a new (unsaved)
// scene when Qtk is opened.
qtkWidget->setScene(new EmptyScene);
views_.emplace(qtkWidget->getScene()->getSceneName(), qtkWidget);
// Add GUI 'view' toolbar option to show debug console.
ui_->menuView->addAction(qtkWidget->getActionToggleConsole());
// Refresh GUI widgets when scene or objects are updated.
connect(
qtkWidget->getScene(), &Qtk::Scene::sceneUpdated, this,
&MainWindow::refreshScene);
connect(
qtkWidget, &Qtk::QtkWidget::objectFocusChanged, ui_->qtk__ToolBox,
&Qtk::ToolBox::updateFocus);
connect(qtkWidget->getScene(),
&Qtk::Scene::sceneUpdated,
this,
&MainWindow::refreshScene);
// Update the ToolBox details panel when an item is double-clicked.
connect(qtkWidget,
&Qtk::QtkWidget::objectFocusChanged,
ui_->qtk__ToolBox,
&Qtk::ToolBox::updateFocus);
}
// TODO: Fix / use MainWindow in Qt Designer to add these dock widgets.
@@ -55,10 +62,11 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
ui_->menuView->addAction(ui_->qtk__TreeView->toggleViewAction());
// Set the window icon used for Qtk.
setWindowIcon(Qtk::getIcon());
setWindowIcon(getIcon());
}
MainWindow::~MainWindow() {
MainWindow::~MainWindow()
{
delete ui_;
}
@@ -66,28 +74,41 @@ MainWindow::~MainWindow() {
* Public Methods
******************************************************************************/
MainWindow * MainWindow::getMainWindow() {
if(mainWindow_ == Q_NULLPTR) {
mainWindow_ = new MainWindow;
}
return mainWindow_;
MainWindow * MainWindow::getMainWindow()
{
static auto * window = new MainWindow;
return window;
}
Qtk::QtkWidget * MainWindow::getQtkWidget(int64_t index) {
if(views_.size() <= index) {
Qtk::QtkWidget * MainWindow::getQtkWidget(int64_t index)
{
if (views_.size() <= index) {
return Q_NULLPTR;
}
return views_.begin(index)->second;
auto it = views_.begin();
std::advance(it, index);
return it->second;
}
Qtk::QtkWidget * MainWindow::getQtkWidget(const QString & name) {
if(!views_.count(name)) {
Qtk::QtkWidget * MainWindow::getQtkWidget(const QString & name)
{
if (!views_.count(name)) {
return Q_NULLPTR;
}
return views_[name];
}
void MainWindow::refreshScene(const QString & sceneName) {
void MainWindow::refreshScene(const QString & sceneName)
{
// TODO: Select TreeView using sceneName
ui_->qtk__TreeView->updateView(getQtkWidget()->getScene());
}
void MainWindow::setScene(Qtk::Scene * scene)
{
connect(scene,
&Qtk::Scene::sceneUpdated,
MainWindow::getMainWindow(),
&MainWindow::refreshScene);
ui_->qtk__QtkWidget->setScene(scene);
}

View File

@@ -14,18 +14,81 @@
#include <QMainWindow>
#include <QPlainTextEdit>
#include "debugconsole.h"
#include "qtkwidget.h"
#include "designer-plugins/debugconsole.h"
namespace Ui {
namespace Ui
{
class MainWindow;
}
/**
* An empty scene used for initializing all QtkWidgets within the MainWindow.
* This serves as a temporary placeholder for QtkScene (for example), which is
* defined in the separate qtk_gui target. The reason for this separation is to
* support the use of QtkWidgets (the qtk_plugins target) within the Qt Designer
* application without implementations provided in the Qtk Desktop Application.
*
* For the Qtk application, this should be replaced by loading the previous
* scene or creating a new _unsaved_ scene when the application is opened.
* Currently we have essentially hard-coded QtkScene to use as examples for
* testing the application. This means that the only way to create or modify a
* scene is to write code. Any modifications made in the application, such as
* moving or resizing objects, will not persist and cannot be saved.
*
* For users of Qtk Designer Plugins, this means that installing
* the `qtk_plugins` target to Qt Designer allows use all of the designer's
* features to build an interface and position or resize a QtkWidget as needed.
* The QtkWidget also appears as widget in the IDE's toolbars and can be added
* to any new application easily, once the plugins are installed.
*
* Once the application is designed, you can define a custom scene and use the
* Qtk API or Qt OpenGL funtions directly to render to it.
*
* Any application using a QtkWidget can set a custom scene in their main
* function. See the MainWindow::MainWindow constructor as an example.
*/
class EmptyScene : public Qtk::Scene
{
void init() override
{
setSkybox(new Qtk::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",
"Skybox"));
setSceneName("Empty Scene");
}
};
/*
* Conditionally include the QtkScene header if the example is enabled.
* Set AppScene type to use in main() for creating the scene.
* Define helper function to initialize Qt resources for the application.
* These resources are different based on if the example is enabled.
*/
#ifdef QTK_GUI_SCENE
#include "qtkscene.h"
using AppScene = QtkScene;
inline void initResources()
{
Q_INIT_RESOURCE(resources);
}
#else
using AppScene = EmptyScene;
inline void initResources()
{
Q_INIT_RESOURCE(minimal_resources);
}
#endif
/**
* MainWindow class to provide an example of using a QtkWidget within a Qt
* window application.
*/
class MainWindow : public QMainWindow {
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
@@ -64,6 +127,16 @@ class MainWindow : public QMainWindow {
*/
Qtk::QtkWidget * getQtkWidget(const QString & name);
/**
* @param scene The new scene to view.
*/
void setScene(Qtk::Scene * scene);
/**
* @return Default icon to use for Qtk desktop application.
*/
static QIcon getIcon() { return QIcon(":/icons/icon.png"); }
public slots:
/**
* Trigger a refresh for widgets related to a scene that has been updated.
@@ -80,7 +153,6 @@ class MainWindow : public QMainWindow {
MainWindow(const MainWindow &) {};
Ui::MainWindow * ui_ {};
static MainWindow * mainWindow_;
/**
* Maps a scene name to the QtkWidget viewing it.

View File

@@ -21,7 +21,7 @@
</property>
<property name="windowIcon">
<iconset>
<normaloff>../resources/icon.png</normaloff>../resources/icon.png</iconset>
<normaloff>../resources/icons/icon.png</normaloff>../resources/icons/icon.png</iconset>
</property>
<property name="unifiedTitleAndToolBarOnMac">
<bool>true</bool>
@@ -310,19 +310,19 @@
<customwidget>
<class>Qtk::QtkWidget</class>
<extends>QOpenGLWidget</extends>
<header>qtkwidget.h</header>
<header>designer-plugins/qtkwidget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>Qtk::TreeView</class>
<extends>QDockWidget</extends>
<header>treeview.h</header>
<header>designer-plugins/treeview.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>Qtk::ToolBox</class>
<extends>QDockWidget</extends>
<header>toolbox.h</header>
<header>designer-plugins/toolbox.h</header>
<container>1</container>
</customwidget>
</customwidgets>

View File

@@ -6,6 +6,10 @@
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include <QCoreApplication>
#include <QDir>
#include <QProcess>
#include "qtkscene.h"
using namespace Qtk;
@@ -14,13 +18,15 @@ using namespace Qtk;
* Constructors, Destructors
******************************************************************************/
QtkScene::QtkScene(Qtk::Scene * scene) : Qtk::SceneInterface(scene) {
QtkScene::QtkScene()
{
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() {
QtkScene::~QtkScene()
{
delete mTestPhong;
delete mTestSpecular;
delete mTestDiffuse;
@@ -31,9 +37,40 @@ QtkScene::~QtkScene() {
* Public Member Functions
******************************************************************************/
void QtkScene::init() {
void QtkScene::init()
{
// Clone qtk-resources if it doesn't already exist.
QDir repoDir("resources/");
if (!repoDir.exists()) {
qDebug() << "Cloning qtk-resources repository to " << repoDir.absolutePath()
<< "...";
// Run git clone
QProcess gitProcess;
gitProcess.setWorkingDirectory(QCoreApplication::applicationDirPath());
gitProcess.start("git",
{"clone",
"https://git.shaunreed.com/shaunrd0/qtk-resources.git",
repoDir.absolutePath()});
// Wait indefinitely for the process to complete
gitProcess.waitForFinished(-1);
// Check the result
if (gitProcess.exitCode() == 0) {
qDebug() << "Repository cloned successfully.";
} else {
qDebug() << "Git clone failed:" << gitProcess.readAllStandardError();
}
}
// Add a skybox to the scene using default cube map images and settings.
setSkybox(new Qtk::Skybox("Skybox"));
setSkybox(new Qtk::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",
"Skybox"));
/* Create a red cube with a mini master chief on top. */
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
@@ -41,8 +78,7 @@ void QtkScene::init() {
myCube->getTransform().setTranslation(5.0f, 0.0f, 0.0f);
addObject(myCube);
auto mySpartan =
new Model("My spartan", ":/models/models/spartan/spartan.obj");
auto mySpartan = new Model("My spartan", QTK_SPARTAN);
mySpartan->getTransform().setTranslation(5.0f, 0.5f, 0.0f);
mySpartan->getTransform().setScale(0.5f);
addObject(mySpartan);
@@ -79,31 +115,27 @@ void QtkScene::init() {
//
// 3D Model loading
auto model = addObject(
new Qtk::Model("backpack", ":/models/models/backpack/backpack.obj"));
auto model = addObject(new Qtk::Model("backpack", QTK_BACKPACK));
// 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 = addObject(new Qtk::Model("bird", QTK_BIRD));
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 = addObject(new Qtk::Model("alien", QTK_ALIEN));
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 = addObject(new Qtk::Model("My scythe", QTK_SCYTHE));
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 = addObject(new Qtk::Model("masterChief", QTK_SPARTAN));
model->getTransform().setTranslation(-1.5f, 0.5f, -2.0f);
@@ -111,13 +143,13 @@ void QtkScene::init() {
// Simple cube lighting examples.
/* Phong lighting example on a basic cube. */
mTestPhong = new Qtk::MeshRenderer("phong", Qtk::Cube());
mTestPhong = addObject(new Qtk::MeshRenderer("phongCube", 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");
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,
@@ -143,16 +175,16 @@ void QtkScene::init() {
/* 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->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 = addObject(new Qtk::MeshRenderer("ambientCube", Cube()));
mTestAmbient->getTransform().setTranslation(7.0f, 0.0f, -2.0f);
mTestAmbient->setShaders(
":/shaders/solid-ambient.vert", ":/shaders/solid-ambient.frag");
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));
@@ -161,10 +193,10 @@ void QtkScene::init() {
// No light source needed for this lighting technique
/* Initialize Diffuse example cube */
mTestDiffuse = new Qtk::MeshRenderer("diffuse", Cube());
mTestDiffuse = addObject(new Qtk::MeshRenderer("diffuseCube", Cube()));
mTestDiffuse->getTransform().setTranslation(9.0f, 0.0f, -2.0f);
mTestDiffuse->setShaders(
":/shaders/solid-diffuse.vert", ":/shaders/solid-diffuse.frag");
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);
@@ -177,10 +209,10 @@ void QtkScene::init() {
mesh->getTransform().scale(0.25f);
/* Initialize Specular example cube */
mTestSpecular = new Qtk::MeshRenderer("specular", Cube());
mTestSpecular = addObject(new Qtk::MeshRenderer("specularCube", Cube()));
mTestSpecular->getTransform().setTranslation(11.0f, 0.0f, -2.0f);
mTestSpecular->setShaders(
":/shaders/solid-specular.vert", ":/shaders/solid-specular.frag");
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);
@@ -228,9 +260,10 @@ void QtkScene::init() {
// 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 = addObject(new Qtk::Model("alienTest",
QTK_ALIEN,
":/shaders/model-phong.vert",
":/shaders/model-phong.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));
@@ -238,7 +271,7 @@ void QtkScene::init() {
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.specularStrength", 0.5f);
model->setUniform("uMaterial.shine", 32.0f);
model->setUniform("uLight.ambient", QVector3D(1.0f, 1.0f, 1.0f));
@@ -246,17 +279,18 @@ void QtkScene::init() {
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 = 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 = addObject(new Qtk::Model("spartanTest",
QTK_SPARTAN,
":/shaders/model-phong.vert",
":/shaders/model-phong.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));
@@ -290,8 +324,8 @@ void QtkScene::init() {
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 = 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());
@@ -321,8 +355,8 @@ void QtkScene::init() {
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 = 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");
@@ -339,8 +373,8 @@ void QtkScene::init() {
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->setShaders(":/shaders/texture-cubemap.vert",
":/shaders/texture-cubemap.frag");
mesh->setCubeMap(":/textures/crate.png");
mesh->setUniform("uTexture", 0);
mesh->reallocateTexCoords(mesh->getTexCoords());
@@ -354,15 +388,15 @@ void QtkScene::init() {
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 = 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 = 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());
@@ -378,8 +412,8 @@ void QtkScene::init() {
mesh->reallocateTexCoords(mesh->getTexCoords());
// Test drawing triangle with glDrawElements with texture coordinates
mesh = addObject(new Qtk::MeshRenderer(
"testTriangleElementsUV", Triangle(QTK_DRAW_ELEMENTS_NORMALS)));
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");
@@ -387,26 +421,25 @@ void QtkScene::init() {
mesh->reallocateTexCoords(mesh->getTexCoords());
}
void QtkScene::draw() {
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();
const QVector3D cameraPosition = getCamera().getTransform().getTranslation();
mTestPhong->bindShaders();
mTestPhong->setUniform(
"uModelInverseTransposed",
mTestPhong->getTransform().toMatrix().normalMatrix());
mTestPhong->setUniform("uModelInverseTransposed",
mTestPhong->getTransform().toMatrix().normalMatrix());
mTestPhong->setUniform(
"uLightPosition",
MeshRenderer::getInstance("phongLight")->getTransform().getTranslation());
mTestPhong->setUniform(
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestPhong->setUniform("uCameraPosition", cameraPosition);
mTestPhong->releaseShaders();
mTestPhong->draw();
mTestAmbient->bindShaders();
mTestAmbient->setUniform(
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestAmbient->setUniform("uCameraPosition", cameraPosition);
mTestAmbient->releaseShaders();
mTestAmbient->draw();
@@ -414,12 +447,11 @@ void QtkScene::draw() {
mTestDiffuse->setUniform(
"uModelInverseTransposed",
mTestDiffuse->getTransform().toMatrix().normalMatrix());
mTestDiffuse->setUniform(
"uLightPosition", MeshRenderer::getInstance("diffuseLight")
->getTransform()
.getTranslation());
mTestDiffuse->setUniform(
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestDiffuse->setUniform("uLightPosition",
MeshRenderer::getInstance("diffuseLight")
->getTransform()
.getTranslation());
mTestDiffuse->setUniform("uCameraPosition", cameraPosition);
mTestDiffuse->releaseShaders();
mTestDiffuse->draw();
@@ -427,70 +459,86 @@ void QtkScene::draw() {
mTestSpecular->setUniform(
"uModelInverseTransposed",
mTestSpecular->getTransform().toMatrix().normalMatrix());
mTestSpecular->setUniform(
"uLightPosition", MeshRenderer::getInstance("specularLight")
->getTransform()
.getTranslation());
mTestSpecular->setUniform(
"uCameraPosition", QtkScene::getCamera().getTransform().getTranslation());
mTestSpecular->setUniform("uLightPosition",
MeshRenderer::getInstance("specularLight")
->getTransform()
.getTranslation());
mTestSpecular->setUniform("uCameraPosition", cameraPosition);
mTestSpecular->releaseShaders();
mTestSpecular->draw();
}
void QtkScene::update() {
auto mySpartan = Model::getInstance("My spartan");
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
void QtkScene::update()
{
auto getModel = Model::getInstance;
const QVector3D cameraPosition = getCamera().getTransform().getTranslation();
auto myCube = MeshRenderer::getInstance("My cube");
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
// Models may have failed to load, so we should check before accessing.
if (auto mySpartan = getModel("My spartan"); mySpartan) {
mySpartan->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);
if (auto myCube = getModel("My cube"); myCube) {
myCube->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);
// Helper lambda to set the light position used by GLSL shaders on the model.
// TODO: This could be a helper function on the Model class.
auto setLightPosition = [](const std::string & lightName, Model * model) {
if (auto light = Model::getInstance(lightName.c_str()); light) {
QVector3D position = light->getTransform().getTranslation();
model->setUniform("uLight.position", position);
} else {
qDebug() << "[QtkScene] Failed to set light position: "
<< lightName.c_str();
}
};
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();
QMatrix4x4 posMatrix;
if (auto alien = getModel("alienTest"); alien) {
setLightPosition("alienTestLight", alien);
alien->setUniform("uCameraPosition", cameraPosition);
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);
}
if (auto spartan = getModel("spartanTest"); spartan) {
setLightPosition("spartanTestLight", spartan);
spartan->setUniform("uCameraPosition", cameraPosition);
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);
}
if (auto phong = getModel("testPhong"); phong) {
setLightPosition("testLight", phong);
phong->getTransform().rotate(0.75f, 1.0f, 0.5f, 0.0f);
phong->bindShaders();
phong->setUniform("uCameraPosition", cameraPosition);
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();
}
// MeshRenderers are lower level opengl objects baked into the source code.
auto getMesh = MeshRenderer::getInstance;
// 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);
getMesh("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);
@@ -498,46 +546,27 @@ void QtkScene::update() {
// Examples of various translations and rotations
// Rotate in multiple directions simultaneously
MeshRenderer::getInstance("rgbNormalsCube")
->getTransform()
.rotate(0.75f, 0.2f, 0.4f, 0.6f);
getMesh("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);
getMesh("leftTriangle")->getTransform().rotate(0.75f, 1.0f, 0.0f, 0.0f);
getMesh("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) {
float posX = getMesh("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);
getMesh("topTriangle")->getTransform().translate(translateX, 0.0f, 0.0f);
getMesh("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);
getMesh("topTriangle")->getTransform().rotate(0.75f, 0.2f, 0.0f, 0.4f);
getMesh("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);
getMesh("centerCube")->getTransform().rotate(0.75f, 0.2f, 0.4f, 0.6f);
}

View File

@@ -11,6 +11,12 @@
#include <qtk/scene.h>
#define QTK_SPARTAN "resources/models/spartan/spartan.obj"
#define QTK_BACKPACK "resources/models/backpack/backpack.obj"
#define QTK_BIRD "resources/models/bird/bird.obj"
#define QTK_ALIEN "resources/models/alien-hominid/alien.obj"
#define QTK_SCYTHE "resources/models/scythe/scythe.obj"
/**
* Example scene using QtkWidget to render 3D models and simple geometry within
* QtOpenGLWidgets. This scene also shows some examples of using GLSL shaders to
@@ -29,13 +35,14 @@
*
* To create your own Scene from scratch see Qtk::Scene.
*/
class QtkScene : public Qtk::SceneInterface {
class QtkScene : public Qtk::Scene
{
public:
/***************************************************************************
* Contructors / Destructors
**************************************************************************/
QtkScene(Qtk::Scene * scene);
QtkScene();
~QtkScene();

View File

@@ -1,357 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## 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 <QMimeData>
#include <QVBoxLayout>
#include <qtk/input.h>
#include <qtk/scene.h>
#include <qtk/shape.h>
#include <QVBoxLayout>
#include <qtk/input.h>
#include <qtk/scene.h>
#include <qtk/shape.h>
#include "debugconsole.h"
#include "qtkmainwindow.h"
#include "qtkwidget.h"
using namespace Qtk;
/*******************************************************************************
* Constructors, Destructors
******************************************************************************/
QtkWidget::QtkWidget(QWidget * parent) : QtkWidget(parent, "QtkWidget") {}
QtkWidget::QtkWidget(QWidget * parent, const QString & name) :
QtkWidget(parent, name, Q_NULLPTR) {}
QtkWidget::QtkWidget(QWidget * parent, const QString & name, Scene * scene) :
QOpenGLWidget(parent), mDebugLogger(Q_NULLPTR),
mConsole(new DebugConsole(this, name)), mScene(Q_NULLPTR) {
setAcceptDrops(true);
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);
}
QtkWidget::~QtkWidget() {
makeCurrent();
teardownGL();
}
/*******************************************************************************
* 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()));
toggleConsole();
// Initialize OpenGL debug context
mDebugLogger = new QOpenGLDebugLogger(this);
if(mDebugLogger->initialize()) {
qDebug() << "GL_DEBUG Debug Logger" << mDebugLogger << "\n";
connect(
mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)), this,
SLOT(messageLogged(QOpenGLDebugMessage)));
mDebugLogger->startLogging();
}
printContextInformation();
// Initialize opengl settings
glEnable(GL_MULTISAMPLE);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.1f, 1.0f);
glClearDepth(1.0f);
glClearColor(0.0f, 0.25f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void QtkWidget::resizeGL(int width, int height) {
Scene::getProjectionMatrix().setToIdentity();
Scene::getProjectionMatrix().perspective(
45.0f, float(width) / float(height), 0.1f, 1000.0f);
}
void QtkWidget::paintGL() {
// Clear buffers and draw the scene if it is valid.
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
if(mScene != Q_NULLPTR) {
mScene->draw();
}
}
void QtkWidget::setScene(Scene * scene) {
if(mScene != Q_NULLPTR) {
delete mScene;
connect(
scene, &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, mConsole);
mConsole->setHidden(false);
mConsoleActive = true;
}
}
/*******************************************************************************
* Protected Methods
******************************************************************************/
void QtkWidget::dragEnterEvent(QDragEnterEvent * event) {
if(event->mimeData()->hasFormat("text/plain")) {
event->acceptProposedAction();
}
}
void QtkWidget::dropEvent(QDropEvent * event) {
mConsole->sendLog(event->mimeData()->text());
auto urls = event->mimeData()->urls();
if(!urls.isEmpty()) {
if(urls.size() > 1) {
qDebug() << "Cannot accept drop of multiple files.";
event->ignore();
return;
}
// TODO: Support other object types.
auto url = urls.front();
if(url.fileName().endsWith(".obj")) {
mScene->loadModel(url);
event->acceptProposedAction();
} else {
qDebug() << "Unsupported file type: " + url.fileName() + "\n";
event->ignore();
}
}
}
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();
if(mScene != Q_NULLPTR) {
mScene->update();
}
QWidget::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;
}
error += " (";
// Format based on source
#define CASE(c) \
case QOpenGLDebugMessage::c: \
error += #c; \
break
switch(msg.source()) {
CASE(APISource);
CASE(WindowSystemSource);
CASE(ShaderCompilerSource);
CASE(ThirdPartySource);
CASE(ApplicationSource);
CASE(OtherSource);
CASE(InvalidSource);
}
#undef CASE
error += " : ";
// Format based on type
#define CASE(c) \
case QOpenGLDebugMessage::c: \
error += #c; \
break
switch(msg.type()) {
CASE(InvalidType);
CASE(ErrorType);
CASE(DeprecatedBehaviorType);
CASE(UndefinedBehaviorType);
CASE(PortabilityType);
CASE(PerformanceType);
CASE(OtherType);
CASE(MarkerType);
CASE(GroupPushType);
CASE(GroupPopType);
}
#undef CASE
error += ")\n" + msg.message() + "\n";
qDebug() << qPrintable(error);
sendLog("(OpenGL) " + error.replace("\n", "\n(OpenGL) "), context);
}
/*******************************************************************************
* Private Methods
******************************************************************************/
void QtkWidget::teardownGL() { /* Nothing to teardown yet... */
}
void QtkWidget::updateCameraInput() {
Input::update();
// Camera Transformation
if(Input::buttonPressed(Qt::LeftButton)
|| Input::buttonPressed(Qt::RightButton)) {
static const float transSpeed = 0.1f;
static const float rotSpeed = 0.5f;
// Handle rotations
Scene::getCamera().getTransform().rotate(
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
Scene::getCamera().getTransform().rotate(
-rotSpeed * Input::mouseDelta().y(), Scene::getCamera().getRight());
// Handle translations
QVector3D translation;
if(Input::keyPressed(Qt::Key_W)) {
translation += Scene::getCamera().getForward();
}
if(Input::keyPressed(Qt::Key_S)) {
translation -= Scene::getCamera().getForward();
}
if(Input::keyPressed(Qt::Key_A)) {
translation -= Scene::getCamera().getRight();
}
if(Input::keyPressed(Qt::Key_D)) {
translation += Scene::getCamera().getRight();
}
if(Input::keyPressed(Qt::Key_Q)) {
translation -= Scene::getCamera().getUp() / 2.0f;
}
if(Input::keyPressed(Qt::Key_E)) {
translation += Scene::getCamera().getUp() / 2.0f;
}
Scene::getCamera().getTransform().translate(transSpeed * translation);
}
}
void QtkWidget::printContextInformation() {
QString glType;
QString glVersion;
QString glProfile;
QString glVendor;
QString glRenderer;
// Get Version Information
glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL";
glVersion = reinterpret_cast<const char *>(glGetString(GL_VERSION));
glVendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
glRenderer = reinterpret_cast<const char *>(glGetString(GL_RENDERER));
// Get Profile Information
#define CASE(c) \
case QSurfaceFormat::c: \
glProfile = #c; \
break
switch(format().profile()) {
CASE(NoProfile);
CASE(CoreProfile);
CASE(CompatibilityProfile);
}
#undef CASE
auto message = QString(glType) + glVersion + "(" + glProfile + ")"
+ "\nOpenGL Vendor: " + glVendor
+ "\nRendering Device: " + glRenderer;
qDebug() << qPrintable(message);
sendLog("(OpenGL) " + message.replace("\n", "\n(OpenGL) "), Status);
}

View File

@@ -1,214 +0,0 @@
/*##############################################################################
## Author: Shaun Reed ##
## 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 ##
##############################################################################*/
#ifndef QTK_QTKWIDGET_H
#define QTK_QTKWIDGET_H
#include <iostream>
#include <QDockWidget>
#include <QMatrix4x4>
#include <QOpenGLDebugLogger>
#include <QOpenGLFunctions>
#include <QOpenGLWidget>
#include <QPlainTextEdit>
#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 QtkWidget : public QOpenGLWidget, protected QOpenGLFunctions {
Q_OBJECT;
public:
/*************************************************************************
* Contructors / Destructors
************************************************************************/
/**
* Qt Designer will call this ctor when creating this widget as a child.
*
* @param parent Pointer to a parent widget for this QtkWidget or nullptr.
*/
explicit QtkWidget(QWidget * parent = nullptr);
/**
* Default construct a QtkWidget.
*
* @param parent Pointer to a parent widget or nullptr if no parent.
* @param name An objectName for the new QtkWidget.
*/
explicit QtkWidget(QWidget * parent, const QString & name);
/**
* 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();
/*************************************************************************
* Public 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.
*/
void initializeGL() override;
/**
* Called when the application window is resized.
*
* @param width The new width of the window.
* @param height The new height of the window.
*/
void resizeGL(int width, int height) override;
/**
* Called when OpenGL repaints the widget.
*/
void paintGL() override;
/*************************************************************************
* 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
************************************************************************/
/**
* @param scene The new scene to view.
*/
void setScene(Qtk::Scene * scene);
public slots:
/**
* Toggle visibility of the DebugConsole associated with this QtkWidget.
*/
void toggleConsole();
signals:
/**
* Log a message to the DebugConsole associated with this widget.
* @param message The message to log.
* @param context The context of the log message.
*/
void sendLog(const QString & message, DebugContext context = Status);
// TODO: Use this signal in treeview and toolbox to update object
// properties
void objectFocusChanged(const QString objectName);
protected:
/*************************************************************************
* Protected Methods
************************************************************************/
void dragEnterEvent(QDragEnterEvent * event) override;
void dropEvent(QDropEvent * event) override;
/**
* @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()
* https://doc.qt.io/qt-6/qopengldebuglogger.html#signals
*
* @param msg The message logged.
*/
void messageLogged(const QOpenGLDebugMessage & msg);
private:
/*************************************************************************
* Private Methods
************************************************************************/
/**
* Deconstruct any resources we have allocated for this widget.
*/
void teardownGL();
/**
* Callback function to update input for camera controls
*/
static void updateCameraInput();
/**
* Prints OpenGL context information at start of debug session.
*/
void printContextInformation();
/*************************************************************************
* Private Members
************************************************************************/
QOpenGLDebugLogger * mDebugLogger;
Qtk::Scene * mScene;
Qtk::DebugConsole * mConsole;
bool mConsoleActive = false;
};
} // namespace Qtk
#endif // QTK_QTKWIDGET_H

View File

@@ -1,149 +0,0 @@
/*##############################################################################
## 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 ##
################################################################################
*/
#include "toolbox.h"
#include "qtkmainwindow.h"
#include "ui_toolbox.h"
#include <QFormLayout>
#include <QLabel>
using namespace Qtk;
ToolBox::ToolBox(QWidget * parent) : QDockWidget(parent), ui(new Ui::ToolBox) {
ui->setupUi(this);
setMinimumWidth(350);
}
void ToolBox::updateFocus(const QString & name) {
auto object =
MainWindow::getMainWindow()->getQtkWidget()->getScene()->getObject(name);
if(object != Q_NULLPTR) {
removePages();
createPageProperties(object);
createPageShader(object);
}
}
ToolBox::~ToolBox() {
delete ui;
}
void ToolBox::removePages() {
// Remove all existing pages.
for(size_t i = 0; i < ui->toolBox->count(); i++) {
delete ui->toolBox->widget(i);
ui->toolBox->removeItem(i);
}
}
void ToolBox::createPageProperties(const Object * object) {
auto transform = object->getTransform();
auto type = object->getType();
auto * widget = new QWidget;
ui->toolBox->addItem(widget, "Properties");
ui->toolBox->setCurrentWidget(widget);
auto * layout = new QFormLayout;
layout->addRow(
new QLabel(tr("Name:")), new QLabel(object->getName().c_str()));
layout->addRow(
new QLabel(tr("Type:")),
new QLabel(type == Object::Type::QTK_MESH ? "Mesh" : "Model"));
auto rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel(tr("Translation:")));
int minWidth = 75;
for(size_t i = 0; i < 3; i++) {
auto spinBox = new QDoubleSpinBox;
spinBox->setMinimum(std::numeric_limits<double>::lowest());
spinBox->setSingleStep(0.1);
spinBox->setValue(transform.getTranslation()[i]);
spinBox->setFixedWidth(minWidth);
rowLayout->addWidget(spinBox);
if(i == 0) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object,
&Object::setTranslationX);
} else if(i == 1) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object,
&Object::setTranslationY);
} else if(i == 2) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object,
&Object::setTranslationZ);
}
}
layout->addRow(rowLayout);
rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel(tr("Scale:")));
for(size_t i = 0; i < 3; i++) {
auto spinBox = new QDoubleSpinBox;
spinBox->setMinimum(std::numeric_limits<double>::lowest());
spinBox->setSingleStep(0.1);
spinBox->setValue(transform.getScale()[i]);
spinBox->setFixedWidth(minWidth);
rowLayout->addWidget(spinBox);
if(i == 0) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleX);
} else if(i == 1) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleY);
} else if(i == 2) {
connect(
spinBox, &QDoubleSpinBox::valueChanged, object, &Object::setScaleZ);
}
}
layout->addRow(rowLayout);
widget->setLayout(layout);
}
void ToolBox::createPageShader(const Object * object) {
// Shaders page.
auto widget = new QWidget;
ui->toolBox->addItem(widget, "Shaders");
auto mainLayout = new QFormLayout;
auto rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel("Vertex Shader:"));
rowLayout->addWidget(new QLabel(object->getVertexShader().c_str()));
mainLayout->addRow(rowLayout);
auto shaderView = new QTextEdit;
shaderView->setReadOnly(true);
auto vertexFile = QFile(object->getVertexShader().c_str());
if(vertexFile.exists()) {
vertexFile.open(QIODeviceBase::ReadOnly);
shaderView->setText(vertexFile.readAll());
vertexFile.close();
mainLayout->addRow(shaderView);
}
rowLayout = new QHBoxLayout;
rowLayout->addWidget(new QLabel("Fragment Shader:"));
rowLayout->addWidget(new QLabel(object->getFragmentShader().c_str()));
mainLayout->addRow(rowLayout);
shaderView = new QTextEdit;
shaderView->setReadOnly(true);
auto fragmentfile = QFile(object->getFragmentShader().c_str());
if(fragmentfile.exists()) {
fragmentfile.open(QIODeviceBase::ReadOnly);
shaderView->setText(fragmentfile.readAll());
fragmentfile.close();
mainLayout->addRow(shaderView);
}
widget->setLayout(mainLayout);
}

View File

@@ -1,56 +0,0 @@
/*##############################################################################
## 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>
#include <QDoubleSpinBox>
#include <QGroupBox>
#include "qtk/scene.h"
namespace Ui {
class ToolBox;
}
namespace Qtk {
class ToolBox : public QDockWidget {
Q_OBJECT
public:
/*************************************************************************
* Contructors / Destructors
*************************************************************************/
explicit ToolBox(QWidget * parent = nullptr);
~ToolBox();
void removePages();
void createPageProperties(const Object * object);
void createPageShader(const Object * object);
void updateFocus(const QString & name);
private:
/*************************************************************************
* Private Members
************************************************************************/
Ui::ToolBox * ui;
};
} // namespace Qtk
#endif // TOOLBOX_H

View File

@@ -1,83 +0,0 @@
<?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="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>86</width>
<height>167</height>
</size>
</property>
<property name="windowTitle">
<string>Object Details</string>
</property>
<widget class="QWidget" name="dockWidgetContents">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page_properties">
<property name="enabled">
<bool>true</bool>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>201</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<attribute name="label">
<string>Properties</string>
</attribute>
</widget>
<widget class="QWidget" name="page_shaders">
<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>
</item>
</layout>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,72 +0,0 @@
/*##############################################################################
## 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);
Transform3D * objectTransform;
// If the object is a mesh or model, focus the camera on it.
if(object == Q_NULLPTR) {
qDebug() << "Attempt to get non-existing object with name '" << name
<< "'\n";
} else 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();
}
auto focusScale = objectTransform->getScale();
float width = focusScale.x() / 2.0f;
float height = focusScale.y() / 2.0f;
QVector3D pos = objectTransform->getTranslation();
// pos.setX(pos.x() + width);
pos.setY(pos.y() + height);
transform.setTranslation(pos);
transform.translate(0.0f, 0.0f, 3.0f);
// Emit signal from qtk widget for new object focus. Triggers GUI updates.
emit MainWindow::getMainWindow()->getQtkWidget()->objectFocusChanged(name);
}

View File

@@ -1,73 +0,0 @@
/*##############################################################################
## 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

View File

@@ -1,44 +0,0 @@
<?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>

View File

@@ -1,98 +0,0 @@
/*##############################################################################
## 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";
}

View File

@@ -1,124 +0,0 @@
/*##############################################################################
## 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

View File

@@ -1,43 +0,0 @@
/*##############################################################################
## 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;
}

View File

@@ -1,50 +0,0 @@
/*##############################################################################
## 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