diff --git a/CMakeLists.txt b/CMakeLists.txt index 3eaf0a2..97ef03b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,12 +20,16 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) # For CLion builds, point CMAKE_PREFIX_PATH to Qt6 install directory -list(APPEND CMAKE_PREFIX_PATH $ENV{HOME}/Code/Clones/Qt6.2/6.2.3/gcc_64/) -find_package(Qt6 COMPONENTS OpenGLWidgets REQUIRED) +list(APPEND CMAKE_PREFIX_PATH $ENV{HOME}/Code/Clones/Qt/6.3.1/gcc_64/) +find_package(Qt6 COMPONENTS OpenGLWidgets) +if (NOT Qt6_FOUND) + message(SEND_ERROR "Unable to find Qt6 at CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}") + message(FATAL_ERROR "Specify path to Qt6 with `cmake -DCMAKE_PREFIX_PATH=/path/to/Qt/6.x.x/gcc_64 -S /path/to/qtk -B /path/to/qtk/build && cmake --build /path/to/qtk/build -j $(nprocs)`") +endif() # Add our Qt resources.qrc file to our application set(SOURCES app/main.cpp) -qt6_add_resources(SOURCES resources.qrc) +qt6_add_big_resources(SOURCES resources.qrc) add_executable( qtk # Executable name @@ -59,6 +63,7 @@ add_library(main-widget SHARED src/transform3D.cpp src/transform3D.h src/model.cpp src/model.h src/scene.cpp src/scene.h + src/resourcemanager.cpp src/resourcemanager.h ) target_include_directories(main-widget PUBLIC src/) diff --git a/README.md b/README.md index 5194965..e0ba2de 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,9 @@ Be sure to take note of the Qt6 installation directory, as we will need it to co Once Qt6 is installed, to build and run `qtk` on Ubuntu - ```bash sudo apt update -y && sudo apt install freeglut3-dev libassimp-dev cmake build-essential git -git clone https://gitlab.com/shaunrd0/qtk && cd qtk -mkdir build && cd build -cmake .. -DCMAKE_PREFIX_PATH=$HOME/Qt6/6.2.3/gcc_64 && cmake --build . -./qtk +git clone https://gitlab.com/shaunrd0/qtk +cmake -DCMAKE_PREFIX_PATH=$HOME/Qt/6.3.1/gcc_64 -S qtk/ -B qtk/build/ && cmake --build qtk/build/ -j $(nprocs) +./qtk/build/qtk ``` You can fly around the scene if you hold the right mouse button and use WASD. diff --git a/src/meshrenderer.h b/src/meshrenderer.h index a295fa2..609492b 100644 --- a/src/meshrenderer.h +++ b/src/meshrenderer.h @@ -37,7 +37,8 @@ public: // Shader settings inline void setShaderVertex(const std::string & vert) { mVertexShader = vert;} - inline void setShaderFragment(const std::string & frag) { mFragmentShader = frag;} + inline void setShaderFragment(const std::string & frag) + { mFragmentShader = frag;} void setShaders(const std::string & vert, const std::string & frag); template diff --git a/src/model.cpp b/src/model.cpp index 2151fc5..2cb3458 100644 --- a/src/model.cpp +++ b/src/model.cpp @@ -11,6 +11,7 @@ #include #include +#include #include @@ -188,6 +189,21 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY) * Model Private Member Functions ******************************************************************************/ +/** + * Loads a model in .obj, .fbx, .gltf, and other formats + * For a full list of formats see assimp documentation: + * https://github.com/assimp/assimp/blob/master/doc/Fileformats.md + * + * Models should not be loaded into Qt resource system + * Instead pass an *absolute* path to this function + * Relative paths will break if Qtk is executed from different locations + * + * Models can also be laoded from the `qtk/resource` directory using qrc format + * loadModel(":/models/backpack/backpack.obj") + * See resourcemanager.h for more information + * + * @param path Absolute path to a model .obj or other format accepted by assimp + */ void Model::loadModel(const std::string & path) { Assimp::Importer import; @@ -195,13 +211,14 @@ void Model::loadModel(const std::string & path) // JIC a relative path was used, get the absolute file path QFileInfo info(path.c_str()); info.makeAbsolute(); - std::string temp = info.absoluteFilePath().toStdString(); + mDirectory = path[0] == ':' ? RM::getPath(path) + : info.absoluteFilePath().toStdString(); // Import the model, converting non-triangular geometry to triangles // + And flipping texture UVs, etc.. // Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html const aiScene * scene = - import.ReadFile(temp, aiProcess_Triangulate + import.ReadFile(mDirectory, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_GenSmoothNormals | aiProcess_CalcTangentSpace @@ -216,7 +233,7 @@ void Model::loadModel(const std::string & path) return; } // If there were no errors, find the directory that contains this model - mDirectory = path.substr(0, path.find_last_of('/')); + mDirectory = mDirectory.substr(0, mDirectory.find_last_of('/')); // Pass the pointers to the root node and the scene to recursive function // + Base case breaks when no nodes left to process on model diff --git a/src/resourcemanager.cpp b/src/resourcemanager.cpp new file mode 100644 index 0000000..71ffbf6 --- /dev/null +++ b/src/resourcemanager.cpp @@ -0,0 +1,13 @@ +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## About: Manage files and resources used by qtk ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +##############################################################################*/ + +#include "resourcemanager.h" + +std::string RM::resourcesDir = + std::string(__FILE__).substr(0, std::string(__FILE__).find("src/")) + + "resources/"; diff --git a/src/resourcemanager.h b/src/resourcemanager.h new file mode 100644 index 0000000..7189677 --- /dev/null +++ b/src/resourcemanager.h @@ -0,0 +1,35 @@ +/*############################################################################## +## Author: Shaun Reed ## +## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ## +## About: Manage files and resources used by qtk ## +## ## +## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ## +##############################################################################*/ + +#include + +#ifndef QTK_RESOURCEMANAGER_H +#define QTK_RESOURCEMANAGER_H + +typedef class ResourceManager { +public: + + /** + * Takes a path using qrc format and constructs full system path to qtk assets + * Qrc format prefix ':/' is trimmed from the path for the caller + * Assets used with RM may (or may not) appear in qtk/resources.qrc + * + * @param path Path relative to qtk/resources/; ie) ':/models/backpack/backpack.obj' + * An asset at location qtk/resources/path/to/asset.obj + * Should be given in qrc format: ':/path/to/asset.obj' + * @return Absoulte system path to a qtk asset + */ + static std::string getPath(const std::string & path) { + // Only construct qtk resource path if in qrc format; else return it as-is + return path[0] == ':' ? resourcesDir + path.substr(2) : path; + } + + static std::string resourcesDir; +} RM; + +#endif //QTK_RESOURCEMANAGER_H diff --git a/src/scene.cpp b/src/scene.cpp index 70bf76f..17929f4 100644 --- a/src/scene.cpp +++ b/src/scene.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include @@ -151,42 +152,31 @@ void Scene::init() // // Model loading - mModels.push_back(new Model("backpack", - "../resources/models/backpack/backpack.obj")); + mModels.push_back(new Model("backpack", ":/models/backpack/backpack.obj")); // Sometimes model textures need flipped in certain directions mModels.back()->flipTexture("diffuse.jpg", false, true); mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f); - mModels.push_back( - new Model("bird", - "../resources/models/bird/bird.obj")); + mModels.push_back(new Model("bird", ":/models/bird/bird.obj")); mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f); // Sometimes the models are very large mModels.back()->mTransform.scale(0.0025f); mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f); - mModels.push_back(new Model("lion", - "../resources/models/lion/lion.obj")); + mModels.push_back(new Model("lion", ":/models/lion/lion.obj")); mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f); mModels.back()->mTransform.scale(0.15f); - mModels.push_back( - new Model("alien", - "../resources/models/alien-hominid/alien.obj")); + mModels.push_back(new Model("alien", ":/models/alien-hominid/alien.obj")); mModels.back()->mTransform.setTranslation(2.0f, -1.0f, -5.0f); mModels.back()->mTransform.scale(0.15f); - mModels.push_back( - new Model("scythe", - "../resources/models/scythe/scythe.obj") - ); + mModels.push_back(new Model("scythe", ":/models/scythe/scythe.obj")); mModels.back()->mTransform.setTranslation(-6.0f, 0.0f, -10.0f); mModels.back()->mTransform.rotate(-90.0f, 1.0f, 0.0f, 0.0f); mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f); - mModels.push_back( - new Model("masterChief", - "../resources/models/spartan/spartan.obj")); + mModels.push_back(new Model("masterChief", ":/models/spartan/spartan.obj")); mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f); @@ -204,9 +194,9 @@ void Scene::init() mMeshes.back()->init(); mModels.push_back( - new Model("alienTest", - "../resources/models/alien-hominid/alien.obj", - ":/model-specular.vert", ":/model-specular.frag")); + new Model("alienTest", ":/models/alien-hominid/alien.obj", + ":/model-specular.vert", ":/model-specular.frag") + ); mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f); mModels.back()->mTransform.scale(0.15f); mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f)); @@ -224,7 +214,8 @@ void Scene::init() // Test spartan Model with phong lighting, specular and normal mapping mMeshes.push_back( - new MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS))); + new MeshRenderer("spartanTestLight", Triangle(QTK_DRAW_ELEMENTS)) + ); mMeshes.back()->mTransform.setTranslation(1.0f, 1.5f, 10.0f); mMeshes.back()->mTransform.scale(0.25f); // This function changes values we have allocated in a buffer, so init() after @@ -232,9 +223,9 @@ void Scene::init() mMeshes.back()->init(); mModels.push_back( - new Model("spartanTest", - "../resources/models/spartan/spartan.obj", - ":/model-normals.vert", ":/model-normals.frag")); + new Model("spartanTest", ":/models/spartan/spartan.obj", + ":/model-normals.vert", ":/model-normals.frag") + ); mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f); mModels.back()->mTransform.scale(2.0f); mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));