drag-and-drop #14

Merged
shaunrd0 merged 45 commits from drag-and-drop into master 2023-12-27 19:36:48 +00:00
24 changed files with 139 additions and 100 deletions
Showing only changes of commit 0659df94bd - Show all commits

@ -74,7 +74,7 @@ We can install this library on a system path or a custom path and then set `CMAK
Below is an example of installing on a system path.
```bash
cmake -S qtk/ -B qtk/build/ -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64 -DQTK_INSTALL_GUI=OFF -DQTK_INSTALL_PLUGINS=OFF
cmake -S qtk/ -B qtk/build/ -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64 -DQTK_INSTALL_GUI=OFF -DQTK_INSTALL_PLUGINS=OFF -DQTK_DEBUG=OFF
cmake --build qtk/build/ -j $(nproc --ignore=2)
sudo cmake --install . --prefix=/usr/local
-- Install configuration: "Release"

@ -2,7 +2,7 @@
include("${CMAKE_CURRENT_LIST_DIR}/QtkTargets.cmake")
set_and_check(QTK_EXECUTABLE "${PACKAGE_PREFIX_DIR}/bin/qtk_main")
set_and_check(QTK_EXECUTABLE "${PACKAGE_PREFIX_DIR}/bin/qtk_app")
set_and_check(QTK_INCLUDE_DIR "${PACKAGE_PREFIX_DIR}/include")
set_and_check(QTK_LIBRARIES "${PACKAGE_PREFIX_DIR}/lib")

@ -65,6 +65,6 @@ set(
examplewidget.cpp examplewidget.h
)
add_executable(example ${EXAMPLE_SOURCES})
target_link_libraries(example PUBLIC Qt6::Widgets Qt6::OpenGLWidgets Qt6::Core)
target_link_libraries(example PUBLIC Qtk::qtk_library)
add_executable(example_app ${EXAMPLE_SOURCES})
target_link_libraries(example_app PUBLIC Qt6::Widgets Qt6::OpenGLWidgets Qt6::Core)
target_link_libraries(example_app PUBLIC Qtk::qtk_library)

@ -1,7 +1,10 @@
This is an example application that is using the Qtk API to create custom Qt
OpenGL widgets. This is very similar to `QtkWidget` in the Qtk desktop
application, but could be modified for different uses if needed.
application source code, but could be modified for different uses if needed.
There are no camera controls supported in this example. The camera is fixed.
If these controls are desired, they can be implemented by the client.
You can import your own models within `examplescene.cpp`, inside the
`ExampleScene::init()` function. Rotations and translations

@ -10,7 +10,7 @@
using namespace Qtk;
ExampleScene::ExampleScene() {
ExampleScene::ExampleScene(Qtk::Scene * scene) : Qtk::SceneInterface(scene) {
setSceneName("Example Scene");
getCamera().getTransform().setTranslation(-8.0f, 0.0f, 10.0f);
getCamera().getTransform().setRotation(-5.0f, 0.0f, 1.0f, 0.0f);

@ -11,9 +11,9 @@
#include <qtk/scene.h>
class ExampleScene : public Qtk::Scene {
class ExampleScene : public Qtk::SceneInterface {
public:
ExampleScene();
ExampleScene(Qtk::Scene * scene);
~ExampleScene();

@ -11,7 +11,12 @@
#include "examplewidget.h"
ExampleWidget::ExampleWidget(QWidget * parent) :
QOpenGLWidget(parent), mScene(new ExampleScene) {
QOpenGLWidget(parent), mScene(new ExampleScene(new Qtk::SceneEmpty)) {
// NOTE: The decorator pattern is used to save / load scenes in Qtk currently.
// The initializer above sets mScene to the concrete decorator ExampleScene.
// Qtk::SceneEmpty provides an empty scene as the concrete component.
// ExampleScene is defined in client source, deriving Qtk::SceneInterface.
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setProfile(QSurfaceFormat::CoreProfile);

@ -32,7 +32,7 @@ class ExampleWidget : public QOpenGLWidget, protected QOpenGLFunctions {
void update();
private:
ExampleScene * mScene;
Qtk::Scene * mScene;
};
#endif // QTKCLIENT_EXAMPLEWIDGET_H

@ -32,7 +32,7 @@ if (QTK_INSTALL_GUI OR QTK_INSTALL_PLUGINS)
if(QTK_INSTALL_GUI)
install(
TARGETS qtk_main qtk_library
TARGETS qtk_app qtk_library
COMPONENT qtk
BUNDLE DESTINATION .
LIBRARY DESTINATION lib
@ -41,7 +41,7 @@ if (QTK_INSTALL_GUI OR QTK_INSTALL_PLUGINS)
)
qt_generate_deploy_app_script(
TARGET qtk_main
TARGET qtk_app
OUTPUT_SCRIPT QTK_DEPLOY_SCRIPT
NO_UNSUPPORTED_PLATFORM_ERROR
)
@ -58,7 +58,7 @@ if (QTK_INSTALL_GUI OR QTK_INSTALL_PLUGINS)
)
file(TO_NATIVE_PATH "${QT6_INSTALL_PREFIX}/bin" QT6_INSTALL_PREFIX)
set(VSUSER_FILE "${CMAKE_CURRENT_BINARY_DIR}/qtk_main.vcxproj.user")
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")
@ -137,11 +137,11 @@ 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_main.exe'"
"CreateShortCut '$SMPROGRAMS\\\\$STARTMENU_FOLDER\\\\Qtk.lnk' '$INSTDIR\\\\bin\\\\qtk_app.exe'"
)
set(
CPACK_NSIS_DELETE_ICONS_EXTRA
"Delete '$SMPROGRAMS\\$START_MENU\\Qtk.lnk'"
"Delete '$SMPROGRAMS\\\\$START_MENU\\\\Qtk.lnk'"
)
# TODO: Icons for NSIS installer.
#set(CPACK_NSIS_MUI_ICON "${CMAKE_SOURCE_DIR}/resources/icon.png")
@ -154,9 +154,8 @@ set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
#set(CPACK_PACKAGING_INSTALL_PREFIX /usr/local/)
# OSX
# TODO: Fix OSX appbundle error.
set(CPACK_BUNDLE_NAME ${PROJECT_NAME})
set(CPACK_BUNDLE_PLIST $<TARGET_BUNDLE_CONTENT_DIR:qtk_main>/Info.plist)
set(CPACK_BUNDLE_PLIST $<TARGET_BUNDLE_CONTENT_DIR:qtk_app>/Info.plist)
set(CPACK_BUNDLE_ICON ${QTK_OSX_ICONS})
# Platform defaults for source bundles.

@ -50,7 +50,7 @@ target_link_libraries(qtk_collection PUBLIC qtk_plugin_library)
set(
QTK_APP_SOURCES
examplescene.cpp examplescene.h
qtkscene.cpp qtkscene.h
main.cpp
)
@ -61,11 +61,11 @@ configure_file(
@ONLY
)
qt_add_executable(qtk_main ${QTK_APP_SOURCES})
target_link_libraries(qtk_main PRIVATE qtk_plugin_library)
qt_add_executable(qtk_app ${QTK_APP_SOURCES})
target_link_libraries(qtk_app PRIVATE qtk_plugin_library)
set_target_properties(
qtk_main PROPERTIES
qtk_app PROPERTIES
WIN32_EXECUTABLE TRUE
MACOSX_BUNDLE TRUE
MACOSX_BUNDLE_BUNDLE_NAME Qtk

@ -9,6 +9,7 @@
#include <QApplication>
#include "qtkmainwindow.h"
#include "qtkscene.h"
int main(int argc, char * argv[]) {
Q_INIT_RESOURCE(resources);
@ -16,7 +17,12 @@ int main(int argc, char * argv[]) {
QApplication a(argc, argv);
auto window = MainWindow::getMainWindow();
window->show();
// 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();
}

@ -7,7 +7,7 @@
##############################################################################*/
#include "qtkmainwindow.h"
#include "examplescene.h"
#include "qtkscene.h"
#include "ui_qtkmainwindow.h"
MainWindow * MainWindow::mainWindow_ = Q_NULLPTR;
@ -27,7 +27,7 @@ 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 ExampleScene);
qtkWidget->setScene(new Qtk::SceneEmpty);
views_.emplace(qtkWidget->getScene()->getSceneName(), qtkWidget);
ui_->menuView->addAction(qtkWidget->getActionToggleConsole());
connect(
@ -60,6 +60,13 @@ MainWindow * MainWindow::getMainWindow() {
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;

@ -53,6 +53,8 @@ class MainWindow : public QMainWindow {
*/
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.

@ -6,7 +6,7 @@
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
##############################################################################*/
#include "examplescene.h"
#include "qtkscene.h"
#include "resources.h"
using namespace Qtk;
@ -15,13 +15,14 @@ using namespace Qtk;
* Constructors, Destructors
******************************************************************************/
ExampleScene::ExampleScene() {
setSceneName("Example Scene");
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);
}
ExampleScene::~ExampleScene() {
QtkScene::~QtkScene() {
delete mTestPhong;
delete mTestSpecular;
delete mTestDiffuse;
@ -32,7 +33,7 @@ ExampleScene::~ExampleScene() {
* Public Member Functions
******************************************************************************/
void ExampleScene::init() {
void QtkScene::init() {
// Add a skybox to the scene using default cube map images and settings.
setSkybox(new Qtk::Skybox("Skybox"));
@ -97,7 +98,7 @@ void ExampleScene::init() {
model->getTransform().scale(0.15f);
model =
addObject(new Qtk::Model("scythe", ":/models/models/scythe/scythe.obj"));
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);
@ -387,19 +388,11 @@ void ExampleScene::init() {
mesh->reallocateTexCoords(mesh->getTexCoords());
}
void ExampleScene::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();
for(const auto & model : getModels()) {
model->draw();
}
for(const auto & mesh : getMeshes()) {
mesh->draw();
}
mTestPhong->bindShaders();
mTestPhong->setUniform(
"uModelInverseTransposed",
@ -409,14 +402,14 @@ void ExampleScene::draw() {
MeshRenderer::getInstance("phongLight")->getTransform().getTranslation());
mTestPhong->setUniform(
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
QtkScene::getCamera().getTransform().getTranslation());
mTestPhong->releaseShaders();
mTestPhong->draw();
mTestAmbient->bindShaders();
mTestAmbient->setUniform(
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
QtkScene::getCamera().getTransform().getTranslation());
mTestAmbient->releaseShaders();
mTestAmbient->draw();
@ -430,7 +423,7 @@ void ExampleScene::draw() {
.getTranslation());
mTestDiffuse->setUniform(
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
QtkScene::getCamera().getTransform().getTranslation());
mTestDiffuse->releaseShaders();
mTestDiffuse->draw();
@ -444,12 +437,12 @@ void ExampleScene::draw() {
.getTranslation());
mTestSpecular->setUniform(
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
QtkScene::getCamera().getTransform().getTranslation());
mTestSpecular->releaseShaders();
mTestSpecular->draw();
}
void ExampleScene::update() {
void QtkScene::update() {
auto mySpartan = Model::getInstance("My spartan");
mySpartan->getTransform().rotate(0.75f, 0.0f, 1.0f, 0.0f);
@ -463,12 +456,12 @@ void ExampleScene::update() {
alien->setUniform("uLight.position", position);
alien->setUniform(
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
QtkScene::getCamera().getTransform().getTranslation());
auto posMatrix = alien->getTransform().toMatrix();
alien->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
alien->setUniform("uMVP.model", posMatrix);
alien->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
alien->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
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")
@ -478,12 +471,12 @@ void ExampleScene::update() {
spartan->setUniform("uLight.position", position);
spartan->setUniform(
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
QtkScene::getCamera().getTransform().getTranslation());
posMatrix = spartan->getTransform().toMatrix();
spartan->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
spartan->setUniform("uMVP.model", posMatrix);
spartan->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
spartan->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
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");
@ -494,12 +487,12 @@ void ExampleScene::update() {
phong->setUniform("uLight.position", position);
phong->setUniform(
"uCameraPosition",
ExampleScene::getCamera().getTransform().getTranslation());
QtkScene::getCamera().getTransform().getTranslation());
posMatrix = phong->getTransform().toMatrix();
phong->setUniform("uMVP.normalMatrix", posMatrix.normalMatrix());
phong->setUniform("uMVP.model", posMatrix);
phong->setUniform("uMVP.view", ExampleScene::getCamera().toMatrix());
phong->setUniform("uMVP.projection", ExampleScene::getProjectionMatrix());
phong->setUniform("uMVP.view", QtkScene::getCamera().toMatrix());
phong->setUniform("uMVP.projection", QtkScene::getProjectionMatrix());
phong->releaseShaders();
// Rotate lighting example cubes

@ -29,15 +29,15 @@
*
* To create your own Scene from scratch see Qtk::Scene.
*/
class ExampleScene : public Qtk::Scene {
class QtkScene : public Qtk::SceneInterface {
public:
/***************************************************************************
* Contructors / Destructors
**************************************************************************/
ExampleScene();
QtkScene(Qtk::Scene * scene);
~ExampleScene();
~QtkScene();
/***************************************************************************
* Inherited Public Overrides

@ -100,6 +100,13 @@ namespace Qtk {
*/
inline Qtk::Scene * getScene() { return mScene; }
/**
* @return Pointer to the QOpenGLDebugLogger attached to this widget.
*/
inline QOpenGLDebugLogger * getOpenGLDebugLogger() {
return mDebugLogger;
}
/*************************************************************************
* Setters
************************************************************************/

@ -37,7 +37,7 @@ void Qtk::TreeView::updateView(const Qtk::Scene * scene) {
mSceneName = scene->getSceneName();
auto objects = scene->getObjects();
for(const auto & object : objects) {
auto item = new QTreeWidgetItem(QStringList(QString(object->getName())));
auto item = new QTreeWidgetItem(QStringList(QString(object->getName().c_str())));
ui->treeWidget->insertTopLevelItem(0, item);
}
}
@ -48,6 +48,10 @@ void Qtk::TreeView::itemFocus(QTreeWidgetItem * item, int column) {
MainWindow::getMainWindow()->getQtkWidget(mSceneName)->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();

@ -38,7 +38,7 @@ MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
}
MeshRenderer::~MeshRenderer() {
sInstances.remove(mName);
sInstances.remove(mName.c_str());
}
/*******************************************************************************

@ -96,7 +96,7 @@ void Model::loadModel(const std::string & path) {
sortModelMeshes();
// Object finished loading, insert it into ModelManager
mManager.insert(getName(), this);
mManager.insert(getName().c_str(), this);
}
void Model::processNode(aiNode * node, const aiScene * scene) {
@ -200,7 +200,7 @@ 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(

@ -58,7 +58,7 @@ namespace Qtk {
loadModel(mModelPath);
}
inline ~Model() override { mManager.remove(getName()); }
inline ~Model() override { mManager.remove(getName().c_str()); }
/*************************************************************************
* Public Methods
@ -197,7 +197,7 @@ namespace Qtk {
/** 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;
std::string mVertexShader, mFragmentShader, mModelPath;
};
} // namespace Qtk

@ -73,7 +73,7 @@ void ModelMesh::initMesh(const char * vert, const char * frag) {
initializeOpenGLFunctions();
// Create VAO, VBO, EBO
mVAO->create();
bool status = mVAO->create();
mVBO->create();
mEBO->create();

@ -92,7 +92,7 @@ namespace Qtk {
return mShape.mVertices;
}
[[nodiscard]] inline const char * getName() const { return mName; }
[[nodiscard]] inline std::string getName() const { return mName; }
[[nodiscard]] inline const Type & getType() const { return mType; }
@ -160,7 +160,7 @@ namespace Qtk {
Transform3D mTransform;
Shape mShape;
Texture mTexture;
const char * mName;
std::string mName;
bool mBound;
Type mType = QTK_OBJECT;
};

@ -37,6 +37,23 @@ Scene::~Scene() {
* 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());
@ -51,7 +68,7 @@ std::vector<Object *> Scene::getObjects() const {
Object * Scene::getObject(const QString & name) {
for(auto object : getObjects()) {
if(object->getName() == name) {
if(object->getName() == name.toStdString()) {
return object;
}
}
@ -74,24 +91,3 @@ template <> Model * Scene::addObject(Model * object) {
sceneUpdated(mSceneName);
return object;
}
/*******************************************************************************
* Private Methods
******************************************************************************/
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();
}
}

@ -10,6 +10,7 @@
#define QTK_SCENE_H
#include <QMatrix4x4>
#include <utility>
#include "camera3d.h"
@ -65,7 +66,7 @@ namespace Qtk {
*
* This function is only called when the widget is redrawn.
*/
virtual void draw() { privateDraw(); };
virtual void draw();
/**
* Function called to update the QOpenGLWidget. Does not trigger a redraw.
@ -165,6 +166,7 @@ namespace Qtk {
*/
inline void setSceneName(QString name) { mSceneName = std::move(name); }
std::vector<Model *> mModels {};
signals:
/**
* Signal thrown when the scene is modified by adding or removing objects.
@ -175,16 +177,6 @@ namespace Qtk {
void sceneUpdated(QString sceneName);
private:
/*************************************************************************
* Private Methods
************************************************************************/
/**
* Handles drawing members encapsulated by this base class.
* Child classes do not need to draw these objects manually.
*/
void privateDraw();
/*************************************************************************
* Private Members
************************************************************************/
@ -199,8 +191,33 @@ namespace Qtk {
/* 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