Fix drag and drop model loading
This commit is contained in:
parent
5118726cde
commit
2476d125f7
|
@ -1,6 +1,9 @@
|
|||
# CLion
|
||||
**/.idea/**
|
||||
|
||||
# VS Code
|
||||
**/.vscode/**
|
||||
|
||||
# CMake build files
|
||||
**/cmake-build-debug/**
|
||||
**/build/**
|
||||
|
|
|
@ -101,31 +101,12 @@ set(
|
|||
"${QT_INSTALL_DIR}/../../Tools/QtCreator"
|
||||
CACHE PATH "Qt Creator path used to install Qtk plugins for Qt Designer."
|
||||
)
|
||||
# Qt Designer will look in different locations if WIN / Unix.
|
||||
# These paths are for using Qt Designer integrated within Qt Creator.
|
||||
# Standalone Qt Designer may use different paths.
|
||||
if (WIN32)
|
||||
# These paths may be different on windows. I have not tested this.
|
||||
set(QT_PLUGIN_INSTALL_DIR "${QT_CREATOR_DIR}/bin/plugins/designer")
|
||||
set(QT_PLUGIN_LIBRARY_DIR "${QT_CREATOR_DIR}/lib/Qt/lib")
|
||||
else()
|
||||
set(QT_PLUGIN_INSTALL_DIR "${QT_CREATOR_DIR}/lib/Qt/plugins/designer")
|
||||
set(QT_PLUGIN_LIBRARY_DIR "${QT_CREATOR_DIR}/lib/Qt/lib")
|
||||
endif()
|
||||
set(QTK_PLUGIN_LIBRARY_DIR "${QT_PLUGIN_LIBRARY_DIR}")
|
||||
set(QTK_PLUGIN_INSTALL_DIR "${QT_PLUGIN_INSTALL_DIR}")
|
||||
|
||||
message(STATUS "[Qtk] CMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX}")
|
||||
set(QTK_RESOURCES "${CMAKE_SOURCE_DIR}/resources")
|
||||
set(QTK_OSX_ICONS ${CMAKE_SOURCE_DIR}/resources/icons/osx/kilroy.icns)
|
||||
|
||||
# Print all QTK options and their values.
|
||||
get_cmake_property(VAR_NAMES VARIABLES)
|
||||
list(FILTER VAR_NAMES INCLUDE REGEX "^Q[tT][kK]_.*$")
|
||||
list(SORT VAR_NAMES)
|
||||
foreach(VAR_NAME ${VAR_NAMES})
|
||||
message(STATUS "[Qtk] ${VAR_NAME}=${${VAR_NAME}}")
|
||||
endforeach()
|
||||
|
||||
################################################################################
|
||||
# External Dependencies
|
||||
|
|
|
@ -38,11 +38,12 @@ void QtkScene::init() {
|
|||
/* Create a red cube with a mini master chief on top. */
|
||||
auto myCube = new MeshRenderer("My cube", Cube(Qtk::QTK_DRAW_ELEMENTS));
|
||||
myCube->setColor(RED);
|
||||
myCube->getTransform().setTranslation(5.0f, 0.0f, 0.0f);
|
||||
addObject(myCube);
|
||||
|
||||
auto mySpartan =
|
||||
new Model("My spartan", ":/models/models/spartan/spartan.obj");
|
||||
mySpartan->getTransform().setTranslation(0.0f, 0.5f, 0.0f);
|
||||
mySpartan->getTransform().setTranslation(5.0f, 0.5f, 0.0f);
|
||||
mySpartan->getTransform().setScale(0.5f);
|
||||
addObject(mySpartan);
|
||||
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
##############################################################################*/
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QVBoxLayout>
|
||||
#include <QMimeData>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#include <qtk/input.h>
|
||||
#include <qtk/scene.h>
|
||||
|
@ -34,8 +34,22 @@ QtkWidget::QtkWidget(QWidget * parent) : QtkWidget(parent, "QtkWidget") {}
|
|||
QtkWidget::QtkWidget(QWidget * parent, const QString & name) :
|
||||
QtkWidget(parent, name, Q_NULLPTR) {}
|
||||
|
||||
QtkWidget::QtkWidget(const QSurfaceFormat & format) :
|
||||
mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR) {
|
||||
QtkWidget::QtkWidget(QWidget * parent, const QString & name, Scene * scene) :
|
||||
QOpenGLWidget(parent), mDebugLogger(Q_NULLPTR),
|
||||
mConsole(new DebugConsole(this, name)), mScene(Q_NULLPTR) {
|
||||
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);
|
||||
}
|
||||
|
@ -71,8 +85,8 @@ void QtkWidget::initializeGL() {
|
|||
mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)), this,
|
||||
SLOT(messageLogged(QOpenGLDebugMessage)));
|
||||
// connect(
|
||||
// mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)), mConsole,
|
||||
// SLOT(sendLog(QOpenGLDebugMessage)));
|
||||
// mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)),
|
||||
// mConsole, SLOT(sendLog(QOpenGLDebugMessage)));
|
||||
mDebugLogger->startLogging();
|
||||
}
|
||||
|
||||
|
@ -146,47 +160,22 @@ void QtkWidget::dropEvent(QDropEvent * event) {
|
|||
mConsole->sendLog(event->mimeData()->text());
|
||||
if(event->mimeData()->hasUrls()) {
|
||||
auto urls = event->mimeData()->urls();
|
||||
// if (urls.size() > 1) {
|
||||
// qDebug() << "Cannot accept drop of multiple files.\n";
|
||||
// event->ignore();
|
||||
// }
|
||||
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")) {
|
||||
auto fileName = url.fileName().replace(".obj", "").toStdString();
|
||||
auto filePath = url.toLocalFile().toStdString();
|
||||
mScene->blockSignals(true);
|
||||
mScene->addObject(new Qtk::Model(url.fileName().replace(".obj", "").toStdString().c_str(), ":/models/models/scythe/scythe.obj"));
|
||||
mScene->blockSignals(false);
|
||||
mScene->sceneUpdated(mScene->getSceneName());
|
||||
// mScene->mModels.push_back(new Qtk::Model(url.fileName().replace(".obj", "").toStdString().c_str(), url.path().toStdString().c_str()));
|
||||
// event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::keyPressEvent(QKeyEvent * event) {
|
||||
if(event->isAutoRepeat()) {
|
||||
// Do not repeat input while a key is held down
|
||||
event->ignore();
|
||||
mScene->loadModel(url);
|
||||
event->acceptProposedAction();
|
||||
} else {
|
||||
Input::registerKeyPress(event->key());
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::keyReleaseEvent(QKeyEvent * event) {
|
||||
if(event->isAutoRepeat()) {
|
||||
qDebug() << "Unsupported file type.";
|
||||
event->ignore();
|
||||
} else {
|
||||
Input::registerKeyRelease(event->key());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void QtkWidget::mousePressEvent(QMouseEvent * event) {
|
||||
Input::registerMousePress(event->button());
|
||||
}
|
||||
|
||||
void QtkWidget::mouseReleaseEvent(QMouseEvent * event) {
|
||||
Input::registerMouseRelease(event->button());
|
||||
}
|
||||
|
||||
void QtkWidget::keyPressEvent(QKeyEvent * event) {
|
||||
|
@ -299,44 +288,6 @@ void QtkWidget::messageLogged(const QOpenGLDebugMessage & msg) {
|
|||
void QtkWidget::teardownGL() { /* Nothing to teardown yet... */
|
||||
}
|
||||
|
||||
void QtkWidget::updateCameraInput() {
|
||||
Input::update();
|
||||
// Camera Transformation
|
||||
if(Input::buttonPressed(Qt::RightButton)) {
|
||||
static const float transSpeed = 0.1f;
|
||||
static const float rotSpeed = 0.5f;
|
||||
|
||||
// Handle rotations
|
||||
Scene::getCamera().getTransform().rotate(
|
||||
-rotSpeed * Input::mouseDelta().x(), Camera3D::LocalUp);
|
||||
Scene::getCamera().getTransform().rotate(
|
||||
-rotSpeed * Input::mouseDelta().y(), Scene::getCamera().getRight());
|
||||
|
||||
// Handle translations
|
||||
QVector3D translation;
|
||||
if(Input::keyPressed(Qt::Key_W)) {
|
||||
translation += Scene::getCamera().getForward();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_S)) {
|
||||
translation -= Scene::getCamera().getForward();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_A)) {
|
||||
translation -= Scene::getCamera().getRight();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_D)) {
|
||||
translation += Scene::getCamera().getRight();
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_Q)) {
|
||||
translation -= Scene::getCamera().getUp() / 2.0f;
|
||||
}
|
||||
if(Input::keyPressed(Qt::Key_E)) {
|
||||
translation += Scene::getCamera().getUp() / 2.0f;
|
||||
}
|
||||
Scene::getCamera().getTransform().translate(transSpeed * translation);
|
||||
}
|
||||
void QtkWidget::teardownGL() { /* Nothing to teardown yet... */
|
||||
}
|
||||
|
||||
void QtkWidget::updateCameraInput() {
|
||||
Input::update();
|
||||
// Camera Transformation
|
||||
|
|
|
@ -170,6 +170,7 @@ namespace Qtk {
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
@ -179,10 +180,6 @@ namespace Qtk {
|
|||
/*************************************************************************
|
||||
* Private Methods
|
||||
************************************************************************/
|
||||
inline void loadModel(const QString & path) {
|
||||
auto * model = new Model("loadedModel", path.toStdString().c_str());
|
||||
mScene->mModels.push_back(model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deconstruct any resources we have allocated for this widget.
|
||||
|
|
|
@ -100,6 +100,10 @@ namespace Qtk {
|
|||
* Setters
|
||||
************************************************************************/
|
||||
|
||||
virtual inline void setName(const std::string & name) {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
virtual inline void setColors(const Colors & value) {
|
||||
mShape.mColors = value;
|
||||
}
|
||||
|
|
|
@ -37,16 +37,42 @@ Scene::~Scene() {
|
|||
* Public Methods
|
||||
******************************************************************************/
|
||||
|
||||
template <> MeshRenderer * Scene::addObject(MeshRenderer * object) {
|
||||
initSceneObjectName(object);
|
||||
mMeshes.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
}
|
||||
|
||||
template <> Model * Scene::addObject(Model * object) {
|
||||
initSceneObjectName(object);
|
||||
mModels.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
}
|
||||
|
||||
void Scene::draw() {
|
||||
if(!mInit) {
|
||||
initializeOpenGLFunctions();
|
||||
init();
|
||||
mInit = true;
|
||||
}
|
||||
|
||||
while (!mModelLoadQueue.empty()) {
|
||||
auto modelSpec = mModelLoadQueue.front();
|
||||
// Load the model and add it to the scene.
|
||||
addObject(new Model(modelSpec.first.c_str(), modelSpec.second.c_str()));
|
||||
mModelLoadQueue.pop();
|
||||
}
|
||||
|
||||
if (mPause) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(mSkybox != Q_NULLPTR) {
|
||||
mSkybox->draw();
|
||||
}
|
||||
for(auto & model : mModels) {
|
||||
for(const auto & model : mModels) {
|
||||
model->draw();
|
||||
}
|
||||
for(const auto & mesh : mMeshes) {
|
||||
|
@ -80,14 +106,14 @@ void Scene::setSkybox(Skybox * skybox) {
|
|||
mSkybox = skybox;
|
||||
}
|
||||
|
||||
template <> MeshRenderer * Scene::addObject(MeshRenderer * object) {
|
||||
mMeshes.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
void Qtk::Scene::initSceneObjectName(Qtk::Object * object) {
|
||||
if(!mObjectCount.count(object->getName())) {
|
||||
mObjectCount[object->getName()] = 1;
|
||||
} else {
|
||||
mObjectCount[object->getName()]++;
|
||||
}
|
||||
auto count = mObjectCount[object->getName()];
|
||||
if (count > 1) {
|
||||
object->setName(object->getName() + " (" + std::to_string(count) + ")");
|
||||
}
|
||||
|
||||
template <> Model * Scene::addObject(Model * object) {
|
||||
mModels.push_back(object);
|
||||
sceneUpdated(mSceneName);
|
||||
return object;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#define QTK_SCENE_H
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <QUrl>
|
||||
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
#include "camera3d.h"
|
||||
|
@ -75,6 +77,18 @@ namespace Qtk {
|
|||
*/
|
||||
virtual void update() {}
|
||||
|
||||
void loadModel(const QUrl & url) {
|
||||
auto fileName = url.fileName().replace(".obj", "").toStdString();
|
||||
auto filePath = url.toLocalFile().toStdString();
|
||||
loadModel(fileName, filePath);
|
||||
}
|
||||
|
||||
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});
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* Accessors
|
||||
************************************************************************/
|
||||
|
@ -93,6 +107,12 @@ namespace Qtk {
|
|||
*/
|
||||
[[nodiscard]] Object * getObject(const QString & name);
|
||||
|
||||
[[nodiscard]] uint64_t getObjectCount(const QString & name) {
|
||||
return mObjectCount.count(name.toStdString())
|
||||
? mObjectCount[name.toStdString()]
|
||||
: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Camera attached to this scene.
|
||||
*/
|
||||
|
@ -166,6 +186,8 @@ namespace Qtk {
|
|||
*/
|
||||
inline void setSceneName(QString name) { mSceneName = std::move(name); }
|
||||
|
||||
inline void setPause(bool pause) { mPause = pause; }
|
||||
|
||||
signals:
|
||||
/**
|
||||
* Signal thrown when the scene is modified by adding or removing objects.
|
||||
|
@ -175,7 +197,26 @@ namespace Qtk {
|
|||
*/
|
||||
void sceneUpdated(QString sceneName);
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* Public Members
|
||||
************************************************************************/
|
||||
public:
|
||||
/* Models used for storing 3D models in the scene. */
|
||||
std::vector<Model *> mModels {};
|
||||
|
||||
/* Queue of models requested to load at runtime. */
|
||||
std::queue<std::pair<std::string, std::string>> mModelLoadQueue;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize an object name relative to other objects already loaded.
|
||||
* Protects against having two objects with the same name.
|
||||
*
|
||||
* @param object Qtk Object to name within this scene.
|
||||
*/
|
||||
void initSceneObjectName(Qtk::Object * object);
|
||||
|
||||
/*************************************************************************
|
||||
* Private Members
|
||||
************************************************************************/
|
||||
|
@ -183,14 +224,16 @@ namespace Qtk {
|
|||
static Camera3D mCamera;
|
||||
static QMatrix4x4 mProjection;
|
||||
bool mInit = false;
|
||||
/* Pause rendering of the scene. */
|
||||
bool mPause = false;
|
||||
|
||||
QString mSceneName;
|
||||
/* The skybox for this scene. */
|
||||
Skybox * mSkybox {};
|
||||
/* MeshRenderers used simple geometry. */
|
||||
std::vector<MeshRenderer *> mMeshes {};
|
||||
/* Models used for storing 3D models in the scene. */
|
||||
std::vector<Model *> mModels {};
|
||||
/* Track count of objects with same initial name. */
|
||||
std::unordered_map<std::string, uint64_t> mObjectCount;
|
||||
};
|
||||
|
||||
class SceneEmpty : public Scene {
|
||||
|
|
Loading…
Reference in New Issue