drag-and-drop #14
|
@ -84,12 +84,13 @@ endif ()
|
|||
set(QTK_RESOURCES "${CMAKE_SOURCE_DIR}/resources")
|
||||
set(QTK_OSX_ICONS ${CMAKE_SOURCE_DIR}/resources/icons/osx/kilroy.icns)
|
||||
|
||||
################################################################################
|
||||
# External Dependencies
|
||||
################################################################################
|
||||
# Point CMAKE_PREFIX_PATH to Qt6 install directory
|
||||
# If Qtk is built within Qt Creator this is not required.
|
||||
list(APPEND CMAKE_PREFIX_PATH "${QT_INSTALL_DIR}")
|
||||
if (QTK_PREFIX_QTCREATOR)
|
||||
# TODO: This might be a bit strange and needs more testing.
|
||||
set(CMAKE_INSTALL_PREFIX "${QT_INSTALL_DIR}")
|
||||
endif()
|
||||
|
||||
set(
|
||||
QT_CREATOR_DIR
|
||||
|
@ -97,8 +98,9 @@ set(
|
|||
CACHE PATH "Qt Creator path used to install Qtk plugins for Qt Designer."
|
||||
)
|
||||
|
||||
|
||||
# Print all QTK options and their values at the end of configuration.
|
||||
# We initialize this list here so that we can append to it as needed.
|
||||
# All variables in this list will be printed at the end of configuration.
|
||||
get_cmake_property(VAR_NAMES VARIABLES)
|
||||
list(FILTER VAR_NAMES INCLUDE REGEX "^[qQ][tT][kK]_.*$")
|
||||
list(SORT VAR_NAMES)
|
||||
|
@ -143,6 +145,7 @@ set(
|
|||
CMAKE_PREFIX_PATH CMAKE_INSTALL_PREFIX QTK_PLUGIN_INSTALL_DIR QT6_INSTALL_PREFIX
|
||||
QT_INSTALL_DIR
|
||||
)
|
||||
# Add QT6_INSTALL_PLUGINS to VAR_NAMES so it is printed at end of configuration.
|
||||
list(APPEND VAR_NAMES QT6_INSTALL_PLUGINS)
|
||||
|
||||
# Find Assimp.
|
||||
|
@ -184,6 +187,8 @@ if(QTK_EXAMPLE)
|
|||
add_subdirectory(example-app EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
|
||||
# Print all QTK options and their values at the end of configuration. This also
|
||||
# prints any additional variables that we have added to VAR_NAMES and VAR_PATHS.
|
||||
foreach(VAR_NAME IN LISTS VAR_NAMES VAR_PATHS)
|
||||
if(VAR_NAME IN_LIST VAR_PATHS)
|
||||
# Print absolute if variable is path
|
||||
|
|
16
README.md
16
README.md
|
@ -40,16 +40,16 @@ and [Qt Creator](https://github.com/qt-creator/qt-creator).
|
|||
Simply open the root `CMakeLists.txt` with either of these editors and
|
||||
configurations will be loaded.
|
||||
|
||||
This project has been ported to **Qt 6.5.0**, which is not yet available in
|
||||
This project has been ported to **Qt 6.6.0**, which is not yet available in
|
||||
Ubuntu apt repositories.
|
||||
To run this project, you will *need* to
|
||||
install [Qt6 Open Source Binaries](https://www.qt.io/download-qt-installer) for
|
||||
your system, **version 6.5.0** or later.
|
||||
your system, **version 6.6.0** or later.
|
||||
Be sure to take note of the Qt6 installation directory, as we will need it to
|
||||
correctly set our `CMAKE_PREFIX_PATH` in the next steps.
|
||||
|
||||
If you are building on **Windows / Mac**, consider setting
|
||||
the `-DASSIMP_NEW_INTERFACE` build flag.
|
||||
the `-DQTK_ASSIMP_NEW_INTERFACE` cmake build option.
|
||||
|
||||
If the build is configured with all options enabled, we can subsequently install
|
||||
individual components as needed with cmake.
|
||||
|
@ -59,7 +59,7 @@ sudo apt update -y && sudo apt install libassimp-dev cmake build-essential git c
|
|||
git clone https://github.com/shaunrd0/qtk
|
||||
cd qtk
|
||||
# Configure the build with all components enabled
|
||||
cmake -B build-all -DQTK_GUI=ON -DQTK_PLUGINS=ON -DQTK_EXAMPLE=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64
|
||||
cmake -B build-all -DQTK_GUI=ON -DQTK_PLUGINS=ON -DQTK_EXAMPLE=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.6.0/gcc_64
|
||||
# Build all targets
|
||||
cmake --build build-all/
|
||||
````
|
||||
|
@ -75,7 +75,7 @@ Windows / Mac / Linux) and may be easier
|
|||
to configure.
|
||||
|
||||
```bash
|
||||
cmake -B build-all -DQTK_GUI=ON -DQTK_PLUGINS=ON -DQTK_EXAMPLE=ON -DQTK_SUBMODULES=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.5.0/gcc_64
|
||||
cmake -B build-all -DQTK_GUI=ON -DQTK_PLUGINS=ON -DQTK_EXAMPLE=ON -DQTK_SUBMODULES=ON -DCMAKE_PREFIX_PATH=$HOME/Qt/6.6.0/gcc_64
|
||||
```
|
||||
|
||||
#### Qtk GUI
|
||||
|
@ -149,9 +149,9 @@ cmake --build build-all/ --target qtk_plugins -- -j $(nproc)
|
|||
# The path here should be initialized during build configuration, so no need for --prefix
|
||||
cmake --install build-all/ --component qtk_plugins
|
||||
-- Install configuration: "Release"
|
||||
-- Up-to-date: /home/shaun/Qt/6.5.0/gcc_64/../../Tools/QtCreator/lib/Qt/lib/libqtk_library.a
|
||||
-- Up-to-date: /home/shaun/Qt/6.5.0/gcc_64/../../Tools/QtCreator/lib/Qt/lib/libqtk_plugin_library.a
|
||||
-- Up-to-date: /home/shaun/Qt/6.5.0/gcc_64/../../Tools/QtCreator/lib/Qt/plugins/designer/libqtk_collection.so
|
||||
-- Up-to-date: /home/shaun/Qt/6.6.0/gcc_64/../../Tools/QtCreator/lib/Qt/lib/libqtk_library.a
|
||||
-- Up-to-date: /home/shaun/Qt/6.6.0/gcc_64/../../Tools/QtCreator/lib/Qt/lib/libqtk_plugin_library.a
|
||||
-- Up-to-date: /home/shaun/Qt/6.6.0/gcc_64/../../Tools/QtCreator/lib/Qt/plugins/designer/libqtk_collection.so
|
||||
```
|
||||
|
||||
To uninstall after a previous installation, we can run the following command
|
||||
|
|
|
@ -24,7 +24,7 @@ void ExampleScene::init() {
|
|||
setSkybox(skybox);
|
||||
|
||||
std::string spartanPath = QTK_EXAMPLE_SOURCE_DIR;
|
||||
spartanPath += "/../resources/models/spartan/spartan.obj";
|
||||
spartanPath += "/resources/models/spartan/spartan.obj";
|
||||
auto spartan = new Model("spartan", spartanPath.c_str());
|
||||
addObject(spartan);
|
||||
spartan->getTransform().setTranslation(-4.0f, 0.0f, 0.0f);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#ifndef QTK_RESOURCES_H_IN_H
|
||||
#define QTK_RESOURCES_H_IN_H
|
||||
|
||||
#define QTK_EXAMPLE_SOURCE_DIR "@CMAKE_CURRENT_SOURCE_DIR@"
|
||||
#define QTK_EXAMPLE_SOURCE_DIR "@CMAKE_SOURCE_DIR@"
|
||||
|
||||
#endif // QTK_RESOURCES_H_IN_H
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.8 MiB |
|
@ -1,5 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/textures">
|
||||
<file alias="plaster.png">images/plaster.png</file>
|
||||
<file alias="crate.png">images/crate.png</file>
|
||||
<file alias="stone.png">images/stone.png</file>
|
||||
<file alias="wood.png">images/wood.png</file>
|
||||
|
|
|
@ -41,6 +41,11 @@ MainWindow::MainWindow(QWidget * parent) : QMainWindow(parent) {
|
|||
&Qtk::ToolBox::updateFocus);
|
||||
}
|
||||
|
||||
// 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
|
||||
// designer. At the moment if you edit the UI in designer the dock widget
|
||||
// areas below will override the designer settings.
|
||||
|
||||
// Dock the toolbox widget to the main window.
|
||||
addDockWidget(Qt::LeftDockWidgetArea, ui_->qtk__ToolBox);
|
||||
// Add an option to toggle active widgets in the GUI's toolbar 'view' menu.
|
||||
|
@ -82,7 +87,7 @@ Qtk::QtkWidget * MainWindow::getQtkWidget(const QString & name) {
|
|||
return views_[name];
|
||||
}
|
||||
|
||||
void MainWindow::refreshScene(QString sceneName) {
|
||||
void MainWindow::refreshScene(const QString & sceneName) {
|
||||
// TODO: Select TreeView using sceneName
|
||||
ui_->qtk__TreeView->updateView(getQtkWidget()->getScene());
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ class MainWindow : public QMainWindow {
|
|||
* Trigger a refresh for widgets related to a scene that has been updated.
|
||||
* @param sceneName The name of the scene that has been modified.
|
||||
*/
|
||||
void refreshScene(QString sceneName);
|
||||
void refreshScene(const QString & sceneName);
|
||||
|
||||
private:
|
||||
/***************************************************************************
|
||||
|
|
|
@ -37,10 +37,10 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>A custom widget tool tip.</string>
|
||||
<string>Object details and configuration panel.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Custom widget what's this?</string>
|
||||
<string>When an object is double-clicked in the TreeView for a scene, this panel will display relevant details and options.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -66,10 +66,10 @@
|
|||
<item>
|
||||
<widget class="Qtk::QtkWidget" name="qtk::QtkWidget">
|
||||
<property name="toolTip">
|
||||
<string>A custom widget tool tip.</string>
|
||||
<string/>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Custom widget what's this?</string>
|
||||
<string>Qtk scene view rendered using OpenGL.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -91,10 +91,10 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>A custom widget tool tip.</string>
|
||||
<string>TreeView of objects within the current scene.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Custom widget what's this?</string>
|
||||
<string>TreeView of objects within the current scene. Double-click to select an object and snap to it's position.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -77,6 +77,7 @@ void QtkWidget::initializeGL() {
|
|||
// 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()) {
|
||||
|
@ -154,8 +155,8 @@ void QtkWidget::dragEnterEvent(QDragEnterEvent * event) {
|
|||
|
||||
void QtkWidget::dropEvent(QDropEvent * event) {
|
||||
mConsole->sendLog(event->mimeData()->text());
|
||||
if(event->mimeData()->hasUrls()) {
|
||||
auto urls = event->mimeData()->urls();
|
||||
auto urls = event->mimeData()->urls();
|
||||
if(!urls.isEmpty()) {
|
||||
if(urls.size() > 1) {
|
||||
qDebug() << "Cannot accept drop of multiple files.";
|
||||
event->ignore();
|
||||
|
@ -168,7 +169,7 @@ void QtkWidget::dropEvent(QDropEvent * event) {
|
|||
mScene->loadModel(url);
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
qDebug() << "Unsupported file type.";
|
||||
qDebug() << "Unsupported file type: " + url.fileName() + "\n";
|
||||
event->ignore();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) {
|
|||
texture.mTexture->destroy();
|
||||
texture.mTexture->create();
|
||||
texture.mTexture->setData(
|
||||
*OpenGLTextureFactory::initImage(fullPath.c_str(), flipX, flipY));
|
||||
OpenGLTextureFactory::initImage(fullPath.c_str(), flipX, flipY));
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ ModelMesh::Textures Model::loadMaterialTextures(
|
|||
// Add the texture to the textures container
|
||||
textures.push_back(texture);
|
||||
// Add the texture to the loaded textures to avoid loading it twice
|
||||
mTexturesLoaded.push_back(texture);
|
||||
mTexturesLoaded.push_back(textures.back());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,10 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader) {
|
|||
shader.setUniformValue((name + number).c_str(), i);
|
||||
}
|
||||
|
||||
// Always reset active texture to GL_TEXTURE0 before we draw.
|
||||
// This is important for models with no textures.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
// Draw the mesh
|
||||
glDrawElements(
|
||||
GL_TRIANGLES, mIndices.size(), GL_UNSIGNED_INT, mIndices.data());
|
||||
|
@ -62,7 +66,6 @@ void ModelMesh::draw(QOpenGLShaderProgram & shader) {
|
|||
}
|
||||
shader.release();
|
||||
mVAO->release();
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
|
|
|
@ -30,6 +30,21 @@ namespace Qtk {
|
|||
* Struct to store model textures. 3D Models may have multiple.
|
||||
*/
|
||||
struct QTKAPI ModelTexture {
|
||||
ModelTexture() = default;
|
||||
|
||||
/**
|
||||
* Construct a ModelTexture.
|
||||
*
|
||||
* @param id Texture ID for this texture.
|
||||
* @param type Type of texture in string format.
|
||||
* @param path Path to the texture on disk.
|
||||
*/
|
||||
ModelTexture(const std::string & type, const std::string & path) :
|
||||
mType(type), mPath(path) {
|
||||
mTexture = OpenGLTextureFactory::initTexture(path.c_str());
|
||||
mID = mTexture->textureId();
|
||||
}
|
||||
|
||||
/** Texture ID for for this texture. */
|
||||
GLuint mID {};
|
||||
QOpenGLTexture * mTexture {};
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace Qtk {
|
|||
void loadModel(const std::string & name, const std::string & path) {
|
||||
// Add the dropped model to the load queue.
|
||||
// This is consumed during rendering of the scene if not empty.
|
||||
mModelLoadQueue.push({name, path});
|
||||
mModelLoadQueue.emplace(name, path);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
|
|
|
@ -9,19 +9,18 @@
|
|||
#include <QDebug>
|
||||
#include <QImageReader>
|
||||
|
||||
#include "app/qtkmainwindow.h"
|
||||
#include "texture.h"
|
||||
|
||||
using namespace Qtk;
|
||||
|
||||
QImage * OpenGLTextureFactory::initImage(
|
||||
QImage OpenGLTextureFactory::initImage(
|
||||
const char * image, bool flipX, bool flipY) {
|
||||
// Qt6 limits loaded images to 256MB by default
|
||||
QImageReader::setAllocationLimit(512);
|
||||
auto loadedImage = new QImage(QImage(image).mirrored(flipX, flipY));
|
||||
if(loadedImage->isNull()) {
|
||||
qDebug() << "[Qtk::OpenGLTextureFactory] Error loading image: " << image
|
||||
<< "\nSupported types: " << QImageReader::supportedImageFormats();
|
||||
return Q_NULLPTR;
|
||||
QImageReader::setAllocationLimit(1024);
|
||||
auto loadedImage = QImage(image).mirrored(flipX, flipY);
|
||||
if(loadedImage.isNull()) {
|
||||
return defaultTexture();
|
||||
}
|
||||
|
||||
return loadedImage;
|
||||
|
@ -29,13 +28,12 @@ QImage * OpenGLTextureFactory::initImage(
|
|||
|
||||
QOpenGLTexture * OpenGLTextureFactory::initTexture(
|
||||
const char * texture, bool flipX, bool flipY) {
|
||||
QImage * image = initImage(texture, flipX, flipY);
|
||||
QImage image = initImage(texture, flipX, flipY);
|
||||
auto newTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
||||
newTexture->setData(*image);
|
||||
newTexture->setData(image);
|
||||
newTexture->setWrapMode(QOpenGLTexture::Repeat);
|
||||
newTexture->setMinMagFilters(
|
||||
QOpenGLTexture::LinearMipMapLinear, QOpenGLTexture::Linear);
|
||||
delete image;
|
||||
return newTexture;
|
||||
}
|
||||
|
||||
|
@ -71,6 +69,7 @@ QOpenGLTexture * OpenGLTextureFactory::initCubeMap(
|
|||
QImage faceImage(faceTextures[i]);
|
||||
if(faceImage.isNull()) {
|
||||
qDebug() << "Error loading cube map image\n";
|
||||
faceImage = defaultTexture();
|
||||
}
|
||||
faceImage = faceImage.convertToFormat(QImage::Format_RGBA8888);
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ namespace Qtk {
|
|||
* Can be absolute or Qt resource path.
|
||||
* @param flipX If true the image will be flipped on X axis.
|
||||
* @param flipY If true the image will be flipped on Y axis.
|
||||
* @return Pointer to an initialized QImage object.
|
||||
* @return QImage object.
|
||||
*/
|
||||
static QImage * initImage(
|
||||
static QImage initImage(
|
||||
const char * image, bool flipX = false, bool flipY = false);
|
||||
|
||||
/**
|
||||
|
@ -132,6 +132,14 @@ namespace Qtk {
|
|||
const char * right, const char * top, const char * front,
|
||||
const char * left, const char * bottom, const char * back);
|
||||
|
||||
/// The texture used in place of a missing texture.
|
||||
static QImage defaultTexture() {
|
||||
// Use plaster for default texture if image fails to load.
|
||||
// This prevents segfaults when loading a texture that doesn't exist.
|
||||
// TODO: Replace with a '?' texture to indicate missing texture.
|
||||
return QImage(":/textures/plaster.png");
|
||||
}
|
||||
|
||||
private:
|
||||
// Private ctor to prevent creating instances of this class
|
||||
OpenGLTextureFactory() = default;
|
||||
|
|
Loading…
Reference in New Issue