Compare commits
43 Commits
main
...
58013ad571
| Author | SHA1 | Date | |
|---|---|---|---|
| 58013ad571 | |||
| fb9c320633 | |||
| c5e21bd731 | |||
| 310f337f57 | |||
| a3e7dc47d8 | |||
| f7b807d3a5 | |||
| d6dbb5c2ff | |||
| dab3fdc9bd | |||
| 8d7bbb75fb | |||
| c9004027b9 | |||
| 0a71bdc1c0 | |||
| ac87635ff7 | |||
| 4a1050e02f | |||
| 8d60355ccf | |||
| 0551b4f91f | |||
| ecae09f82d | |||
| e68d384340 | |||
| e2c7f5ba75 | |||
| f1d9a07940 | |||
| f5a38892b1 | |||
| d230662924 | |||
| 97bf086a87 | |||
| e97ccd8195 | |||
| 728710ece2 | |||
| 40119856de | |||
| de9ef4c948 | |||
| b252922b0a | |||
| 12883e8c20 | |||
| bdd178d0f2 | |||
| 9bd09b2bb0 | |||
| 0d2a73a35f | |||
| ea25ba312a | |||
| 78639cf1c2 | |||
| 941f2d228c | |||
| 16baf6cdaf | |||
| c86a7744b3 | |||
| 7fac6bafb4 | |||
| 1bed9545c9 | |||
| 32641acd8d | |||
| 68bfff7bcd | |||
| 92e5937cc7 | |||
| 1e1c328a5a | |||
| dcbeb26738 |
15
.github/workflows/build.yml
vendored
15
.github/workflows/build.yml
vendored
@@ -43,16 +43,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: ${{ env.QT_VERSION }}
|
version: ${{ env.QT_VERSION }}
|
||||||
|
|
||||||
- name: Install pkgconfiglite
|
# Windows
|
||||||
|
|
||||||
|
- name: Chocolatey Action
|
||||||
if: matrix.os == 'windows-latest'
|
if: matrix.os == 'windows-latest'
|
||||||
uses: crazy-max/ghaction-chocolatey@v2
|
uses: crazy-max/ghaction-chocolatey@v2
|
||||||
with:
|
with:
|
||||||
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
||||||
- name: Install nsis
|
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
uses: crazy-max/ghaction-chocolatey@v2
|
|
||||||
with:
|
|
||||||
args: install nsis
|
|
||||||
|
|
||||||
- name: Install Debian packaging dependencies
|
- name: Install Debian packaging dependencies
|
||||||
if: matrix.os == 'ubuntu-latest'
|
if: matrix.os == 'ubuntu-latest'
|
||||||
@@ -194,11 +191,6 @@ jobs:
|
|||||||
uses: crazy-max/ghaction-chocolatey@v2
|
uses: crazy-max/ghaction-chocolatey@v2
|
||||||
with:
|
with:
|
||||||
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
args: install pkgconfiglite --checksum e87b5ea3c9142256af60f2d5b917aa63b571e6a0 --checksum-type sha1
|
||||||
- name: Install nsis
|
|
||||||
if: matrix.os == 'windows-latest'
|
|
||||||
uses: crazy-max/ghaction-chocolatey@v2
|
|
||||||
with:
|
|
||||||
args: install nsis
|
|
||||||
|
|
||||||
- name: Configure Qtk Library
|
- name: Configure Qtk Library
|
||||||
shell: bash
|
shell: bash
|
||||||
@@ -377,6 +369,7 @@ jobs:
|
|||||||
- name: Download Installer Artifact
|
- name: Download Installer Artifact
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
name: Qtk Packages
|
||||||
path: |
|
path: |
|
||||||
build/packages/*
|
build/packages/*
|
||||||
install/*
|
install/*
|
||||||
|
|||||||
14
.github/workflows/linting.yml
vendored
14
.github/workflows/linting.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
|||||||
# Check the entire repo for source files to tidy
|
# Check the entire repo for source files to tidy
|
||||||
files-changed-only: false
|
files-changed-only: false
|
||||||
# Ignore qtk build and external assimp directories
|
# Ignore qtk build and external assimp directories
|
||||||
ignore: '.github|build|extern'
|
ignore: '.github|build|extern/assimp/assimp'
|
||||||
# Point to compile_commands.json produced by build
|
# Point to compile_commands.json produced by build
|
||||||
database: 'build'
|
database: 'build'
|
||||||
# Use thread comments as feedback
|
# Use thread comments as feedback
|
||||||
@@ -61,12 +61,8 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- uses: cpp-linter/cpp-linter-action@v2
|
- name: clang-format Check
|
||||||
|
uses: jidicula/clang-format-action@v4.9.0
|
||||||
with:
|
with:
|
||||||
version: '18'
|
clang-format-version: '18'
|
||||||
style: 'file'
|
check-path: ${{ matrix.path }}
|
||||||
tidy-checks: ''
|
|
||||||
files-changed-only: false
|
|
||||||
ignore: '.github|build|extern'
|
|
||||||
extensions: 'cpp,h'
|
|
||||||
files: ${{ matrix.path }}
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ add_compile_options(-fPIC)
|
|||||||
################################################################################
|
################################################################################
|
||||||
project(
|
project(
|
||||||
#[[NAME]] Qtk
|
#[[NAME]] Qtk
|
||||||
VERSION 0.3
|
VERSION 0.2
|
||||||
DESCRIPTION "Qt OpenGL library and desktop application."
|
DESCRIPTION "Qt OpenGL library and desktop application."
|
||||||
LANGUAGES CXX C
|
LANGUAGES CXX C
|
||||||
)
|
)
|
||||||
@@ -157,15 +157,8 @@ list(APPEND VAR_NAMES QT6_INSTALL_PLUGINS)
|
|||||||
|
|
||||||
# Find Assimp.
|
# Find Assimp.
|
||||||
if(QTK_SUBMODULES)
|
if(QTK_SUBMODULES)
|
||||||
if(APPLE)
|
|
||||||
# Avoid zlib redefining fdopen, causing build failures in apple clang.
|
|
||||||
# https://github.com/assimp/assimp/issues/6118
|
|
||||||
add_compile_definitions(-Dfdopen=fdopen)
|
|
||||||
endif()
|
|
||||||
if(NOT WIN32)
|
|
||||||
# Required to statically link.
|
# Required to statically link.
|
||||||
add_compile_options(-fPIC)
|
add_compile_options(-fPIC)
|
||||||
endif()
|
|
||||||
set(BUILD_SHARED_LIBS OFF CACHE STRING "Build static assimp libs" FORCE)
|
set(BUILD_SHARED_LIBS OFF CACHE STRING "Build static assimp libs" FORCE)
|
||||||
set(ASSIMP_BUILD_ZLIB ON CACHE STRING "Build Zlib with assimp." FORCE)
|
set(ASSIMP_BUILD_ZLIB ON CACHE STRING "Build Zlib with assimp." FORCE)
|
||||||
set(
|
set(
|
||||||
@@ -182,14 +175,6 @@ if(QTK_SUBMODULES)
|
|||||||
"${CMAKE_CURRENT_SOURCE_DIR}/extern/assimp/assimp/"
|
"${CMAKE_CURRENT_SOURCE_DIR}/extern/assimp/assimp/"
|
||||||
EXCLUDE_FROM_ALL
|
EXCLUDE_FROM_ALL
|
||||||
)
|
)
|
||||||
install(
|
|
||||||
TARGETS assimp zlibstatic
|
|
||||||
EXPORT qtk_export
|
|
||||||
COMPONENT qtk
|
|
||||||
ARCHIVE DESTINATION lib
|
|
||||||
LIBRARY DESTINATION lib
|
|
||||||
RUNTIME DESTINATION bin
|
|
||||||
)
|
|
||||||
else()
|
else()
|
||||||
find_package(assimp REQUIRED)
|
find_package(assimp REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Qtk
|
# Qtk
|
||||||
|
|
||||||
[](https://github.com/shaunrd0/qtk/actions/workflows/build.yml)
|
[](https://github.com/shaunrd0/qtk/actions/workflows/build.yml)
|
||||||
[](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml)
|
[](https://github.com/shaunrd0/qtk/actions/workflows/linting.yml)
|
||||||
|
|
||||||
The Qtk desktop application provides a model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
The Qtk desktop application provides a model loader using [Assimp](https://assimp.org/) within a Qt widget application.
|
||||||
@@ -60,12 +60,12 @@ Key features that are planned:
|
|||||||
- [x] Runtime loading of `.obj` or similar 3D models.
|
- [x] Runtime loading of `.obj` or similar 3D models.
|
||||||
- [x] Drag-and-drop interaction for adding objects to the scene.
|
- [x] Drag-and-drop interaction for adding objects to the scene.
|
||||||
- [x] Shader / object properties panel to modify related settings.
|
- [x] Shader / object properties panel to modify related settings.
|
||||||
- [x] Reduce size of application resources and git references.
|
|
||||||
- [ ] Runtime reloading of modified GLSL shaders attached to objects within scenes.
|
- [ ] Runtime reloading of modified GLSL shaders attached to objects within scenes.
|
||||||
- [ ] Multiple views of a scene at one time.
|
- [ ] Multiple views of a scene at one time.
|
||||||
- [ ] Camera control modes such as panning, orbiting, or following objects.
|
- [ ] Camera control modes such as panning, orbiting, or following objects.
|
||||||
- [ ] Save / load scene data. The current model requires writing C++ code.
|
- [ ] Save / load scene data. The current model requires writing C++ code.
|
||||||
- [ ] Basic text editor for quickly modifying shaders attached to objects.
|
- [ ] Basic text editor for quickly modifying shaders attached to objects.
|
||||||
|
- [ ] Reduce size of application resources and git references.
|
||||||
|
|
||||||
For examples of using libqtk, see the [example-app](./example-app)
|
For examples of using libqtk, see the [example-app](./example-app)
|
||||||
project in the root of this repository.
|
project in the root of this repository.
|
||||||
@@ -90,7 +90,7 @@ The Ubuntu apt repositories contain all the packages we need to build all target
|
|||||||
To build Qtk desktop application with the scene in the screenshots below run the following commands.
|
To build Qtk desktop application with the scene in the screenshots below run the following commands.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo apt update && sudo apt install cmake build-essential git ccache libxkbcommon-dev libassimp-dev qt6-base-dev qt6-tools-dev zlib1g-dev
|
sudo apt update && sudo apt install cmake build-essential git ccache libxkbcommon-dev libassimp-dev qt6-base-dev qt6-tools-dev
|
||||||
cmake -DQTK_GUI_SCENE=ON -B build
|
cmake -DQTK_GUI_SCENE=ON -B build
|
||||||
cmake --build build
|
cmake --build build
|
||||||
./build/bin/qtk_gui
|
./build/bin/qtk_gui
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ endif()
|
|||||||
# Allow add_subdirectory on this project to use target ALIAS if available.
|
# Allow add_subdirectory on this project to use target ALIAS if available.
|
||||||
# If this example project is opened standalone we will use find_package.
|
# If this example project is opened standalone we will use find_package.
|
||||||
if(NOT TARGET Qtk::qtk)
|
if(NOT TARGET Qtk::qtk)
|
||||||
find_package(Qtk 0.3 REQUIRED)
|
find_package(Qtk 0.2 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Qt6 COMPONENTS Core Widgets OpenGLWidgets REQUIRED)
|
find_package(Qt6 COMPONENTS Core Widgets OpenGLWidgets REQUIRED)
|
||||||
|
|||||||
2
extern/assimp/assimp
vendored
2
extern/assimp/assimp
vendored
Submodule extern/assimp/assimp updated: e0b52347c6...5d5496f1ad
@@ -48,16 +48,6 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent)
|
|||||||
&Qtk::ToolBox::updateFocus);
|
&Qtk::ToolBox::updateFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(ui_->actionDelete_Object,
|
|
||||||
&QAction::triggered,
|
|
||||||
this,
|
|
||||||
&MainWindow::deleteObject);
|
|
||||||
|
|
||||||
connect(ui_->actionLoad_Model,
|
|
||||||
&QAction::triggered,
|
|
||||||
this,
|
|
||||||
&MainWindow::loadObject);
|
|
||||||
|
|
||||||
// TODO: Fix / use MainWindow in Qt Designer to add these dock widgets.
|
// TODO: Fix / use MainWindow in Qt Designer to add these dock widgets.
|
||||||
// For now we will add them manually, but we should be able to do this in the
|
// For now we will add them manually, but we should be able to do this in the
|
||||||
// designer. At the moment if you edit the UI in designer the dock widget
|
// designer. At the moment if you edit the UI in designer the dock widget
|
||||||
@@ -114,26 +104,6 @@ void MainWindow::refreshScene(const QString & sceneName)
|
|||||||
ui_->qtk__TreeView->updateView(getQtkWidget()->getScene());
|
ui_->qtk__TreeView->updateView(getQtkWidget()->getScene());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::deleteObject()
|
|
||||||
{
|
|
||||||
if (auto object = ui_->qtk__ToolBox->getObjectFocus(); object != Q_NULLPTR) {
|
|
||||||
auto scene = getQtkWidget()->getScene();
|
|
||||||
switch (object->getType()) {
|
|
||||||
case Qtk::Object::Type::QTK_MESH:
|
|
||||||
scene->removeObject(dynamic_cast<Qtk::MeshRenderer *>(object));
|
|
||||||
ui_->qtk__ToolBox->clearFocus();
|
|
||||||
break;
|
|
||||||
case Qtk::Object::Type::QTK_MODEL:
|
|
||||||
scene->removeObject(dynamic_cast<Qtk::Model *>(object));
|
|
||||||
ui_->qtk__ToolBox->clearFocus();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
qDebug() << "Failed to delete model with invalid type";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::setScene(Qtk::Scene * scene)
|
void MainWindow::setScene(Qtk::Scene * scene)
|
||||||
{
|
{
|
||||||
connect(scene,
|
connect(scene,
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <QFileDialog>
|
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
|
#include <QPlainTextEdit>
|
||||||
|
|
||||||
#include "designer-plugins/debugconsole.h"
|
#include "designer-plugins/debugconsole.h"
|
||||||
|
|
||||||
@@ -144,23 +144,6 @@ class MainWindow : public QMainWindow
|
|||||||
*/
|
*/
|
||||||
void refreshScene(const QString & sceneName);
|
void refreshScene(const QString & sceneName);
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens a QFileDialog for selecting an object file to load into the scene.
|
|
||||||
*/
|
|
||||||
void loadObject()
|
|
||||||
{
|
|
||||||
const QUrl file = QFileDialog::getOpenFileName(
|
|
||||||
this, tr("Load Model"), QDir::homePath(), tr("Object Files (*.obj)"));
|
|
||||||
getQtkWidget()->getScene()->loadModel(file.fileName().replace(".obj", ""),
|
|
||||||
file.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the currently selected object from the scene.
|
|
||||||
*/
|
|
||||||
void deleteObject();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Private Members
|
* Private Members
|
||||||
|
|||||||
@@ -222,9 +222,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionLoad_Model">
|
<action name="actionLoad_Model">
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</iconset>
|
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/solid/cube.svg</iconset>
|
||||||
@@ -237,9 +234,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDelete_Object">
|
<action name="actionDelete_Object">
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<property name="icon">
|
<property name="icon">
|
||||||
<iconset>
|
<iconset>
|
||||||
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</iconset>
|
<normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</normaloff>:/icons/fontawesome-free-6.2.1-desktop/svgs/regular/trash-can.svg</iconset>
|
||||||
|
|||||||
@@ -482,9 +482,21 @@ void QtkScene::update()
|
|||||||
myCube->getTransform().rotate(-0.75f, 0.0f, 1.0f, 0.0f);
|
myCube->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();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
QMatrix4x4 posMatrix;
|
QMatrix4x4 posMatrix;
|
||||||
if (auto alien = getModel("alienTest"); alien) {
|
if (auto alien = getModel("alienTest"); alien) {
|
||||||
alien->setLightPosition("alienTestLight");
|
setLightPosition("alienTestLight", alien);
|
||||||
|
|
||||||
alien->setUniform("uCameraPosition", cameraPosition);
|
alien->setUniform("uCameraPosition", cameraPosition);
|
||||||
posMatrix = alien->getTransform().toMatrix();
|
posMatrix = alien->getTransform().toMatrix();
|
||||||
@@ -496,7 +508,7 @@ void QtkScene::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto spartan = getModel("spartanTest"); spartan) {
|
if (auto spartan = getModel("spartanTest"); spartan) {
|
||||||
spartan->setLightPosition("spartanTestLight");
|
setLightPosition("spartanTestLight", spartan);
|
||||||
|
|
||||||
spartan->setUniform("uCameraPosition", cameraPosition);
|
spartan->setUniform("uCameraPosition", cameraPosition);
|
||||||
posMatrix = spartan->getTransform().toMatrix();
|
posMatrix = spartan->getTransform().toMatrix();
|
||||||
@@ -508,7 +520,7 @@ void QtkScene::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (auto phong = getModel("testPhong"); phong) {
|
if (auto phong = getModel("testPhong"); phong) {
|
||||||
phong->setLightPosition("testLight");
|
setLightPosition("testLight", phong);
|
||||||
|
|
||||||
phong->getTransform().rotate(0.75f, 1.0f, 0.5f, 0.0f);
|
phong->getTransform().rotate(0.75f, 1.0f, 0.5f, 0.0f);
|
||||||
phong->bindShaders();
|
phong->bindShaders();
|
||||||
|
|||||||
@@ -16,121 +16,20 @@
|
|||||||
|
|
||||||
using namespace Qtk;
|
using namespace Qtk;
|
||||||
|
|
||||||
ToolBox::ToolBox(QWidget * parent) :
|
ToolBox::ToolBox(QWidget * parent) : QDockWidget(parent), ui(new Ui::ToolBox)
|
||||||
QDockWidget(parent), objectDetails_(this), transformPanel_(this),
|
|
||||||
scalePanel_(this), vertex_(this, "Vertex Shader:"),
|
|
||||||
fragment_(this, "Fragment Shader:"), properiesForm_(new QFormLayout),
|
|
||||||
shaderForm_(new QFormLayout), ui(new Ui::ToolBox), objectFocus_(Q_NULLPTR)
|
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
setMinimumWidth(350);
|
setMinimumWidth(350);
|
||||||
|
|
||||||
// Object Properties.
|
|
||||||
ui->page_properties->setLayout(properiesForm_);
|
|
||||||
properiesForm_->addRow(objectDetails_.name.label, objectDetails_.name.value);
|
|
||||||
properiesForm_->addRow(objectDetails_.objectType.label,
|
|
||||||
objectDetails_.objectType.value);
|
|
||||||
properiesForm_->addRow(reinterpret_cast<QWidget *>(&transformPanel_));
|
|
||||||
properiesForm_->addRow(reinterpret_cast<QWidget *>(&scalePanel_));
|
|
||||||
ui->toolBox->setCurrentWidget(ui->page_properties);
|
|
||||||
|
|
||||||
// Shader views.
|
|
||||||
ui->page_shaders->setLayout(shaderForm_);
|
|
||||||
shaderForm_->addRow(reinterpret_cast<QWidget *>(&vertex_));
|
|
||||||
shaderForm_->addRow(reinterpret_cast<QWidget *>(&fragment_));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolBox::updateFocus(const QString & name)
|
void ToolBox::updateFocus(const QString & name)
|
||||||
{
|
{
|
||||||
auto object =
|
auto object =
|
||||||
QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name);
|
Qtk::QtkWidget::mWidgetManager.get_widget()->getScene()->getObject(name);
|
||||||
// If we can't find the object show a warning.
|
if (object != Q_NULLPTR) {
|
||||||
if (object == Q_NULLPTR) {
|
removePages();
|
||||||
qDebug() << "Failed to find selected object: " << name
|
createPageProperties(object);
|
||||||
<< "; Clearing object panels.";
|
createPageShader(object);
|
||||||
}
|
|
||||||
|
|
||||||
// We should still pass the nullptr here if we failed to find the object
|
|
||||||
// above.
|
|
||||||
objectFocus_ = object;
|
|
||||||
refreshProperties(object);
|
|
||||||
refreshShaders(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolBox::clearFocus()
|
|
||||||
{
|
|
||||||
objectFocus_ = Q_NULLPTR;
|
|
||||||
refreshProperties(objectFocus_);
|
|
||||||
refreshShaders(objectFocus_);
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolBox::SpinBox3D::SpinBox3D(QWidget * parent, const char * l) :
|
|
||||||
QWidget(parent), layout(new QHBoxLayout(this)), label(new QLabel(tr(l)))
|
|
||||||
{
|
|
||||||
// The layout owns the widget and will clean it up on destruction.
|
|
||||||
layout->addWidget(label);
|
|
||||||
for (const auto & f : fields) {
|
|
||||||
layout->addWidget(f->spinBox);
|
|
||||||
f->spinBox->setMinimum(std::numeric_limits<double>::lowest());
|
|
||||||
f->spinBox->setSingleStep(0.1);
|
|
||||||
f->spinBox->setFixedWidth(75);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolBox::SpinBox::disconnect() const
|
|
||||||
{
|
|
||||||
Object::disconnect(connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolBox::TransformPanel::setObject(const Qtk::Object * object)
|
|
||||||
{
|
|
||||||
// Zero the panel contents if there is no object selected.
|
|
||||||
if (object == Q_NULLPTR) {
|
|
||||||
spinBox3D.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Reconnect translation panel controls to the new object.
|
|
||||||
const std::vector binds = {&Object::setTranslationX,
|
|
||||||
&Object::setTranslationY,
|
|
||||||
&Object::setTranslationZ};
|
|
||||||
for (size_t i = 0; i < spinBox3D.fields.size(); i++) {
|
|
||||||
auto * f = spinBox3D.fields[i];
|
|
||||||
// Disconnect before changing spin box value.
|
|
||||||
f->disconnect();
|
|
||||||
|
|
||||||
// Set the values in the spin box to the object's current X,Y,Z
|
|
||||||
f->spinBox->setValue(object->getTransform().getTranslation()[i]);
|
|
||||||
|
|
||||||
// Reconnect to bind spin box value to the new object's position.
|
|
||||||
f->connection =
|
|
||||||
connect(f->spinBox, &QDoubleSpinBox::valueChanged, object, binds[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolBox::ScalePanel::setObject(const Qtk::Object * object)
|
|
||||||
{
|
|
||||||
// Zero the panel contents if there is no object selected.
|
|
||||||
if (object == Q_NULLPTR) {
|
|
||||||
spinBox3D.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reconnect scale panel controls to the new object.
|
|
||||||
const std::vector binds = {
|
|
||||||
&Object::setScaleX, &Object::setScaleY, &Object::setScaleZ};
|
|
||||||
for (size_t i = 0; i < spinBox3D.fields.size(); i++) {
|
|
||||||
auto * f = spinBox3D.fields[i];
|
|
||||||
// Disconnect before changing spin box value.
|
|
||||||
f->disconnect();
|
|
||||||
|
|
||||||
// Set the values in the spin box to the object's current X,Y,Z
|
|
||||||
f->spinBox->setValue(object->getTransform().getScale()[i]);
|
|
||||||
|
|
||||||
// Reconnect to bind spin box value to the new object's scale.
|
|
||||||
f->connection =
|
|
||||||
connect(f->spinBox, &QDoubleSpinBox::valueChanged, object, binds[i]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,32 +38,110 @@ ToolBox::~ToolBox()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolBox::refreshProperties(const Object * object)
|
void ToolBox::removePages()
|
||||||
{
|
{
|
||||||
// Refresh to show the new object's details.
|
// Remove all existing pages.
|
||||||
objectDetails_.setObject(object);
|
for (size_t i = 0; i < ui->toolBox->count(); i++) {
|
||||||
// Reconnect transform panel controls to the new object.
|
delete ui->toolBox->widget(i);
|
||||||
transformPanel_.setObject(object);
|
ui->toolBox->removeItem(i);
|
||||||
scalePanel_.setObject(object);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToolBox::refreshShaders(const Object * object)
|
void ToolBox::createPageProperties(const Object * object)
|
||||||
{
|
{
|
||||||
// Zero the panel contents if there is no object selected.
|
auto transform = object->getTransform();
|
||||||
if (object == Q_NULLPTR) {
|
auto type = object->getType();
|
||||||
vertex_.clear();
|
auto * widget = new QWidget;
|
||||||
fragment_.clear();
|
ui->toolBox->addItem(widget, "Properties");
|
||||||
return;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertex_.path.setValue(object->getVertexShader().c_str());
|
void ToolBox::createPageShader(const Object * object)
|
||||||
vertex_.editor->setText(object->getVertexShaderSourceCode().c_str());
|
|
||||||
fragment_.path.setValue(object->getFragmentShader().c_str());
|
|
||||||
fragment_.editor->setText(object->getFragmentShaderSourceCode().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToolBox::refresh(const Object * object)
|
|
||||||
{
|
{
|
||||||
refreshProperties(object);
|
// Shaders page.
|
||||||
refreshShaders(object);
|
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);
|
||||||
|
shaderView->setText(object->getVertexShaderSourceCode().c_str());
|
||||||
|
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);
|
||||||
|
shaderView->setText(object->getFragmentShaderSourceCode().c_str());
|
||||||
|
mainLayout->addRow(shaderView);
|
||||||
|
|
||||||
|
widget->setLayout(mainLayout);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,13 +13,10 @@
|
|||||||
#include <QDesignerExportWidget>
|
#include <QDesignerExportWidget>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QDoubleSpinBox>
|
#include <QDoubleSpinBox>
|
||||||
#include <QFormLayout>
|
#include <QGroupBox>
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QTextEdit>
|
|
||||||
|
|
||||||
#include "qtk/object.h"
|
|
||||||
|
|
||||||
|
#include "qtk/scene.h"
|
||||||
|
|
||||||
namespace Ui
|
namespace Ui
|
||||||
{
|
{
|
||||||
@@ -28,7 +25,7 @@ namespace Ui
|
|||||||
|
|
||||||
namespace Qtk
|
namespace Qtk
|
||||||
{
|
{
|
||||||
class ToolBox final : public QDockWidget
|
class ToolBox : public QDockWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -41,184 +38,20 @@ namespace Qtk
|
|||||||
|
|
||||||
~ToolBox();
|
~ToolBox();
|
||||||
|
|
||||||
void refreshProperties(const Object * object);
|
void removePages();
|
||||||
|
|
||||||
void refreshShaders(const Object * object);
|
void createPageProperties(const Object * object);
|
||||||
|
|
||||||
void refresh(const Object * object);
|
void createPageShader(const Object * object);
|
||||||
|
|
||||||
void updateFocus(const QString & name);
|
void updateFocus(const QString & name);
|
||||||
|
|
||||||
[[nodiscard]] Object * getObjectFocus() const { return objectFocus_; }
|
|
||||||
|
|
||||||
void clearFocus();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* Private Members
|
* Private Members
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
/// Displays details on the object.
|
|
||||||
struct ObjectDetails {
|
|
||||||
/// Single item containing a label and value.
|
|
||||||
struct Item {
|
|
||||||
explicit Item(QWidget * parent,
|
|
||||||
const char * l = "Item:",
|
|
||||||
const char * v = "") :
|
|
||||||
label(new QLabel(tr(l), parent)),
|
|
||||||
value(new QLabel(tr(v), parent))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void setValue(const char * v) const { value->setText(tr(v)); }
|
|
||||||
|
|
||||||
void setItem(const char * l, const char * v) const
|
|
||||||
{
|
|
||||||
label->setText(tr(l));
|
|
||||||
value->setText(tr(v));
|
|
||||||
}
|
|
||||||
|
|
||||||
QLabel * label;
|
|
||||||
QLabel * value;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// We pass the parent widget so that Qt handles releasing memory.
|
|
||||||
explicit ObjectDetails(QWidget * parent) :
|
|
||||||
name(parent, "Name:"), objectType(parent, "Object Type:")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Refresh to display the new object's details
|
|
||||||
void setObject(const Qtk::Object * object) const
|
|
||||||
{
|
|
||||||
// Zero contents if there is no object selected.
|
|
||||||
if (object == Q_NULLPTR) {
|
|
||||||
name.setValue("");
|
|
||||||
objectType.setValue("No object selected");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
name.setItem("Name:", object->getName().toStdString().c_str());
|
|
||||||
objectType.setItem(
|
|
||||||
"Type:",
|
|
||||||
object->getType() == Object::QTK_MESH ? "Mesh" : "Model");
|
|
||||||
}
|
|
||||||
|
|
||||||
Item name, objectType;
|
|
||||||
};
|
|
||||||
ObjectDetails objectDetails_;
|
|
||||||
|
|
||||||
/// Structure to associate a QSpinBox with a connection.
|
|
||||||
struct SpinBox {
|
|
||||||
/**
|
|
||||||
* Default constructor passes no parent to the QSpinBox.
|
|
||||||
* It must be added to a layout for Qt to clean up the resources.
|
|
||||||
*/
|
|
||||||
SpinBox() : spinBox(new QDoubleSpinBox) {}
|
|
||||||
|
|
||||||
/// Disconnect the associated connection.
|
|
||||||
void disconnect() const;
|
|
||||||
|
|
||||||
QDoubleSpinBox * spinBox;
|
|
||||||
QMetaObject::Connection connection;
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Spinbox with 3 fields and a single label.
|
|
||||||
class SpinBox3D final : QWidget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// We pass a parent to ensure Qt will clean up resources.
|
|
||||||
/// Assigning a QWidget to a QLayout also ensures Qt will clean up.
|
|
||||||
explicit SpinBox3D(QWidget * parent, const char * l = "SpinBox3D:");
|
|
||||||
|
|
||||||
/// Zero the SpinBox3D display.
|
|
||||||
void clear()
|
|
||||||
{
|
|
||||||
for (auto & field : fields) {
|
|
||||||
field->disconnect();
|
|
||||||
field->spinBox->setValue(0.0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The main layout for the SpinBox3D widget.
|
|
||||||
QHBoxLayout * layout;
|
|
||||||
|
|
||||||
/// Label for the SpinBox3D.
|
|
||||||
QLabel * label;
|
|
||||||
|
|
||||||
/// SpinBox and a connection for each field.
|
|
||||||
SpinBox x, y, z;
|
|
||||||
/// Array for iterating over fields.
|
|
||||||
std::array<SpinBox *, 3> fields {&x, &y, &z};
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Initialize the transform panel and configure QObject connections.
|
|
||||||
struct TransformPanel {
|
|
||||||
explicit TransformPanel(QWidget * parent) :
|
|
||||||
spinBox3D(parent, "Transform:")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reconnect QObject connections and spin box values in UI.
|
|
||||||
void setObject(const Qtk::Object * object);
|
|
||||||
|
|
||||||
SpinBox3D spinBox3D;
|
|
||||||
};
|
|
||||||
TransformPanel transformPanel_;
|
|
||||||
|
|
||||||
/// Initialize the scale panel and configure QObject connections.
|
|
||||||
struct ScalePanel {
|
|
||||||
explicit ScalePanel(QWidget * parent) : spinBox3D(parent, "Scale:") {}
|
|
||||||
|
|
||||||
/// Reconnect QObject connections and spin box values in UI.
|
|
||||||
void setObject(const Qtk::Object * object);
|
|
||||||
|
|
||||||
SpinBox3D spinBox3D;
|
|
||||||
};
|
|
||||||
ScalePanel scalePanel_;
|
|
||||||
|
|
||||||
/// Displays shader name, path, and read-only text view.
|
|
||||||
class ShaderView final : QWidget
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit ShaderView(QWidget * parent,
|
|
||||||
const char * l = "ShaderView:") :
|
|
||||||
layout(new QVBoxLayout(this)), path(parent, l),
|
|
||||||
editor(new QTextEdit(parent))
|
|
||||||
{
|
|
||||||
// Create a child horizontal layout for shader name and file path.
|
|
||||||
auto * pathLayout = new QHBoxLayout;
|
|
||||||
pathLayout->addWidget(path.label);
|
|
||||||
pathLayout->addWidget(path.value);
|
|
||||||
layout->addLayout(pathLayout);
|
|
||||||
|
|
||||||
// Add the read-only text editor widget to the main layout.
|
|
||||||
editor->setReadOnly(true);
|
|
||||||
layout->addWidget(editor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Zero the ShaderView display.
|
|
||||||
void clear() const
|
|
||||||
{
|
|
||||||
path.setValue("");
|
|
||||||
editor->setText("");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The main layout for the ShaderView widget.
|
|
||||||
QVBoxLayout * layout;
|
|
||||||
|
|
||||||
/// Shader name and path on disk.
|
|
||||||
ObjectDetails::Item path;
|
|
||||||
|
|
||||||
/// Read-only (for now) display of the shader source code.
|
|
||||||
QTextEdit * editor;
|
|
||||||
};
|
|
||||||
ShaderView vertex_, fragment_;
|
|
||||||
|
|
||||||
QFormLayout * properiesForm_;
|
|
||||||
QFormLayout * shaderForm_;
|
|
||||||
|
|
||||||
Object * objectFocus_ {};
|
|
||||||
|
|
||||||
Ui::ToolBox * ui;
|
Ui::ToolBox * ui;
|
||||||
};
|
};
|
||||||
} // namespace Qtk
|
} // namespace Qtk
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ void Qtk::TreeView::updateView(const Qtk::Scene * scene)
|
|||||||
mSceneName = scene->getSceneName();
|
mSceneName = scene->getSceneName();
|
||||||
auto objects = scene->getObjects();
|
auto objects = scene->getObjects();
|
||||||
for (const auto & object : objects) {
|
for (const auto & object : objects) {
|
||||||
QStringList list(QStringList(QString(object->getName())));
|
QStringList list(QStringList(QString(object->getName().c_str())));
|
||||||
ui->treeWidget->insertTopLevelItem(0, new QTreeWidgetItem(list));
|
ui->treeWidget->insertTopLevelItem(0, new QTreeWidgetItem(list));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
|
|||||||
|
|
||||||
MeshRenderer::~MeshRenderer()
|
MeshRenderer::~MeshRenderer()
|
||||||
{
|
{
|
||||||
sInstances.remove(mName);
|
sInstances.remove(mName.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
|
|||||||
@@ -56,19 +56,8 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setLightPosition(const QString & lightName, const char * uniform)
|
|
||||||
{
|
|
||||||
if (auto light = MeshRenderer::getInstance(lightName); light) {
|
|
||||||
QVector3D position = light->getTransform().getTranslation();
|
|
||||||
setUniform(uniform, position);
|
|
||||||
} else {
|
|
||||||
qDebug() << "[QtkScene] Failed to set " << mName
|
|
||||||
<< "light position: " << lightName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Static function to access ModelManager for getting Models by name
|
// Static function to access ModelManager for getting Models by name
|
||||||
Model * Model::getInstance(const char * name)
|
Model * Qtk::Model::getInstance(const char * name)
|
||||||
{
|
{
|
||||||
return mManager[name];
|
return mManager[name];
|
||||||
}
|
}
|
||||||
@@ -113,7 +102,7 @@ void Model::loadModel(const std::string & path)
|
|||||||
sortModelMeshes();
|
sortModelMeshes();
|
||||||
|
|
||||||
// Object finished loading, insert it into ModelManager
|
// 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)
|
void Model::processNode(aiNode * node, const aiScene * scene)
|
||||||
@@ -272,11 +261,13 @@ ModelMesh::Textures Model::loadMaterialTextures(aiMaterial * mat,
|
|||||||
|
|
||||||
void Model::sortModelMeshes()
|
void Model::sortModelMeshes()
|
||||||
{
|
{
|
||||||
auto cameraPos = Scene::getCamera().getTransform().getTranslation();
|
auto cameraPos = Scene::getCamera().getTransform();
|
||||||
auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) {
|
auto cameraDistance = [&cameraPos](const ModelMesh & a, const ModelMesh & b) {
|
||||||
// Sort by the first vertex position in the model
|
// Sort by the first vertex position in the model
|
||||||
return cameraPos.distanceToPoint(a.mVertices[0].mPosition)
|
return (cameraPos.getTranslation().distanceToPoint(
|
||||||
< cameraPos.distanceToPoint(b.mVertices[0].mPosition);
|
a.mVertices[0].mPosition))
|
||||||
|
< (cameraPos.getTranslation().distanceToPoint(
|
||||||
|
b.mVertices[0].mPosition));
|
||||||
};
|
};
|
||||||
std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance);
|
std::sort(mMeshes.begin(), mMeshes.end(), cameraDistance);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace Qtk
|
|||||||
loadModel(mModelPath);
|
loadModel(mModelPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ~Model() override { mManager.remove(getName()); }
|
inline ~Model() override { mManager.remove(getName().c_str()); }
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* Public Methods
|
* Public Methods
|
||||||
@@ -113,14 +113,6 @@ namespace Qtk
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the position of a light used in GLSL unfiroms.
|
|
||||||
*
|
|
||||||
* @param lightName Object name of the light
|
|
||||||
*/
|
|
||||||
void setLightPosition(const QString & lightName,
|
|
||||||
const char * uniform = "uLight.position");
|
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* Accessors
|
* Accessors
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ namespace Qtk
|
|||||||
return mShape.mVertices;
|
return mShape.mVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] inline QString getName() const { return mName; }
|
[[nodiscard]] inline std::string getName() const { return mName; }
|
||||||
|
|
||||||
[[nodiscard]] inline const Type & getType() const { return mType; }
|
[[nodiscard]] inline const Type & getType() const { return mType; }
|
||||||
|
|
||||||
@@ -143,7 +143,7 @@ namespace Qtk
|
|||||||
* Setters
|
* Setters
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
virtual inline void setName(const QString & name) { mName = name; }
|
virtual inline void setName(const std::string & name) { mName = name; }
|
||||||
|
|
||||||
virtual inline void setColors(const Colors & value)
|
virtual inline void setColors(const Colors & value)
|
||||||
{
|
{
|
||||||
@@ -244,23 +244,6 @@ namespace Qtk
|
|||||||
mProgram.release();
|
mProgram.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
|
||||||
* Public Static Methods
|
|
||||||
************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to disconnect a QObject connection, only if it's valid.
|
|
||||||
* If the connection is valid and we fail to disconnect log a message.
|
|
||||||
*
|
|
||||||
* @param con QObject connection handle to disconnect.
|
|
||||||
*/
|
|
||||||
static void disconnect(const QMetaObject::Connection & con)
|
|
||||||
{
|
|
||||||
if (con && !QObject::disconnect(con)) {
|
|
||||||
qDebug() << "[Qtk] Failed to disconnect valid connection: " << con;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
* Private Members
|
* Private Members
|
||||||
@@ -272,7 +255,7 @@ namespace Qtk
|
|||||||
Transform3D mTransform;
|
Transform3D mTransform;
|
||||||
Shape mShape;
|
Shape mShape;
|
||||||
Texture mTexture;
|
Texture mTexture;
|
||||||
QString mName;
|
std::string mName;
|
||||||
bool mBound;
|
bool mBound;
|
||||||
Type mType = QTK_OBJECT;
|
Type mType = QTK_OBJECT;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -55,34 +55,6 @@ template <> Model * Scene::addObject(Model * object)
|
|||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> void Scene::removeObject(MeshRenderer * object)
|
|
||||||
{
|
|
||||||
auto it = std::find(mMeshes.begin(), mMeshes.end(), object);
|
|
||||||
if (it == mMeshes.end()) {
|
|
||||||
qDebug() << "[Scene::removeObject]: Failed to remove object: "
|
|
||||||
<< object->getName() << " (" << object << ")";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
--mObjectCount[object->getName()];
|
|
||||||
mMeshes.erase(it);
|
|
||||||
emit sceneUpdated(mSceneName);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <> void Scene::removeObject(Model * object)
|
|
||||||
{
|
|
||||||
auto it = std::find(mModels.begin(), mModels.end(), object);
|
|
||||||
if (it == mModels.end()) {
|
|
||||||
qDebug() << "[Scene::removeObject]: Failed to remove object: "
|
|
||||||
<< object->getName() << " (" << object << ")";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
--mObjectCount[object->getName()];
|
|
||||||
mModels.erase(it);
|
|
||||||
emit sceneUpdated(mSceneName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Scene::draw()
|
void Scene::draw()
|
||||||
{
|
{
|
||||||
if (!mInit) {
|
if (!mInit) {
|
||||||
@@ -131,7 +103,7 @@ std::vector<Object *> Scene::getObjects() const
|
|||||||
Object * Scene::getObject(const QString & name) const
|
Object * Scene::getObject(const QString & name) const
|
||||||
{
|
{
|
||||||
for (const auto & object : getObjects()) {
|
for (const auto & object : getObjects()) {
|
||||||
if (object->getName() == name) {
|
if (object->getName() == name.toStdString()) {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -149,6 +121,6 @@ void Scene::initSceneObjectName(Object * object)
|
|||||||
// If the object name exists make it unique.
|
// If the object name exists make it unique.
|
||||||
auto count = ++mObjectCount[object->getName()];
|
auto count = ++mObjectCount[object->getName()];
|
||||||
if (count > 1) {
|
if (count > 1) {
|
||||||
object->setName(object->getName() + " (" + QString::number(count) + ")");
|
object->setName(object->getName() + " (" + std::to_string(count) + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,16 +85,16 @@ namespace Qtk
|
|||||||
|
|
||||||
void loadModel(const QUrl & url)
|
void loadModel(const QUrl & url)
|
||||||
{
|
{
|
||||||
auto fileName = url.fileName().replace(".obj", "");
|
auto fileName = url.fileName().replace(".obj", "").toStdString();
|
||||||
auto filePath = url.toLocalFile();
|
auto filePath = url.toLocalFile().toStdString();
|
||||||
loadModel(fileName, filePath);
|
loadModel(fileName, filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loadModel(const QString & name, const QString & path)
|
void loadModel(const std::string & name, const std::string & path)
|
||||||
{
|
{
|
||||||
// Add the dropped model to the load queue.
|
// Add the dropped model to the load queue.
|
||||||
// This is consumed during rendering of the scene if not empty.
|
// This is consumed during rendering of the scene if not empty.
|
||||||
mModelLoadQueue.emplace(name.toStdString(), path.toStdString());
|
mModelLoadQueue.emplace(name, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
@@ -120,7 +120,9 @@ namespace Qtk
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] uint64_t getObjectCount(const QString & name)
|
[[nodiscard]] uint64_t getObjectCount(const QString & name)
|
||||||
{
|
{
|
||||||
return mObjectCount.count(name) ? mObjectCount[name] : 0;
|
return mObjectCount.count(name.toStdString())
|
||||||
|
? mObjectCount[name.toStdString()]
|
||||||
|
: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -182,9 +184,8 @@ namespace Qtk
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds objects to the scene.
|
* Adds objects to the scene.
|
||||||
* This template provides explicit specializations for the valid types:
|
* This template provides explicit specializations for valid types.
|
||||||
* MeshRenderer, Model
|
* Adding any object other than these types will cause errors.
|
||||||
* Any other object type will cause errors.
|
|
||||||
* TODO: Refactor to use Object base class container for scene objects.
|
* TODO: Refactor to use Object base class container for scene objects.
|
||||||
*
|
*
|
||||||
* If creating a new object type for a scene, it must inherit Qtk::Object
|
* If creating a new object type for a scene, it must inherit Qtk::Object
|
||||||
@@ -195,17 +196,6 @@ namespace Qtk
|
|||||||
*/
|
*/
|
||||||
template <typename T> T * addObject(T * object);
|
template <typename T> T * addObject(T * object);
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes an object from the scene.
|
|
||||||
* This template provides explicit specializations for the valid types:
|
|
||||||
* MeshRenderer, Model
|
|
||||||
* Any other object type will cause errors.
|
|
||||||
* TODO: Refactor to use Object base class container for scene objects.
|
|
||||||
*
|
|
||||||
* @param object Pointer to the object to remove from the scene.
|
|
||||||
*/
|
|
||||||
template <typename T> void removeObject(T * object);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param name The name to use for this scene.
|
* @param name The name to use for this scene.
|
||||||
*/
|
*/
|
||||||
@@ -258,7 +248,7 @@ namespace Qtk
|
|||||||
/* MeshRenderers used simple geometry. */
|
/* MeshRenderers used simple geometry. */
|
||||||
std::vector<MeshRenderer *> mMeshes {};
|
std::vector<MeshRenderer *> mMeshes {};
|
||||||
/* Track count of objects with same initial name. */
|
/* Track count of objects with same initial name. */
|
||||||
std::unordered_map<QString, uint64_t> mObjectCount;
|
std::unordered_map<std::string, uint64_t> mObjectCount;
|
||||||
};
|
};
|
||||||
} // namespace Qtk
|
} // namespace Qtk
|
||||||
|
|
||||||
|
|||||||
@@ -109,12 +109,11 @@ void main()
|
|||||||
#version 330
|
#version 330
|
||||||
uniform samplerCube uTexture;
|
uniform samplerCube uTexture;
|
||||||
|
|
||||||
in vec3 vTexCoord;
|
varying vec3 vTexCoord;
|
||||||
out vec4 FragColor;
|
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
FragColor = texture(uTexture, vTexCoord);
|
gl_FragColor = texture(uTexture, vTexCoord);
|
||||||
}
|
}
|
||||||
)"
|
)"
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user