Add ResourceManager for assets outside of QRC

+ Use qt6_add_big_resources to improve build time
+ RM::getPath(sting) to build absolute path to assets
+ Allows easy access to models or other large assets not loaded into QRC
This commit is contained in:
Shaun Reed 2022-07-31 18:50:02 -04:00
parent 82b06c247d
commit d3c11d4645
7 changed files with 93 additions and 35 deletions

View File

@ -20,12 +20,16 @@ set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
# For CLion builds, point CMAKE_PREFIX_PATH to Qt6 install directory # 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/) list(APPEND CMAKE_PREFIX_PATH $ENV{HOME}/Code/Clones/Qt/6.3.1/gcc_64/)
find_package(Qt6 COMPONENTS OpenGLWidgets REQUIRED) 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 # Add our Qt resources.qrc file to our application
set(SOURCES app/main.cpp) set(SOURCES app/main.cpp)
qt6_add_resources(SOURCES resources.qrc) qt6_add_big_resources(SOURCES resources.qrc)
add_executable( add_executable(
qtk # Executable name qtk # Executable name
@ -59,6 +63,7 @@ add_library(main-widget SHARED
src/transform3D.cpp src/transform3D.h src/transform3D.cpp src/transform3D.h
src/model.cpp src/model.h src/model.cpp src/model.h
src/scene.cpp src/scene.h src/scene.cpp src/scene.h
src/resourcemanager.cpp src/resourcemanager.h
) )
target_include_directories(main-widget PUBLIC src/) target_include_directories(main-widget PUBLIC src/)

View File

@ -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 - Once Qt6 is installed, to build and run `qtk` on Ubuntu -
```bash ```bash
sudo apt update -y && sudo apt install freeglut3-dev libassimp-dev cmake build-essential git sudo apt update -y && sudo apt install freeglut3-dev libassimp-dev cmake build-essential git
git clone https://gitlab.com/shaunrd0/qtk && cd qtk git clone https://gitlab.com/shaunrd0/qtk
mkdir build && cd build cmake -DCMAKE_PREFIX_PATH=$HOME/Qt/6.3.1/gcc_64 -S qtk/ -B qtk/build/ && cmake --build qtk/build/ -j $(nprocs)
cmake .. -DCMAKE_PREFIX_PATH=$HOME/Qt6/6.2.3/gcc_64 && cmake --build . ./qtk/build/qtk
./qtk
``` ```
You can fly around the scene if you hold the right mouse button and use WASD. You can fly around the scene if you hold the right mouse button and use WASD.

View File

@ -37,7 +37,8 @@ public:
// Shader settings // Shader settings
inline void setShaderVertex(const std::string & vert) { mVertexShader = vert;} 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); void setShaders(const std::string & vert, const std::string & frag);
template <typename T> template <typename T>

View File

@ -11,6 +11,7 @@
#include <scene.h> #include <scene.h>
#include <texture.h> #include <texture.h>
#include <resourcemanager.h>
#include <model.h> #include <model.h>
@ -188,6 +189,18 @@ void Model::flipTexture(const std::string & fileName, bool flipX, bool flipY)
* Model Private Member Functions * 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
* See resourcemanager.h for an example of how qtk handles this
*
* @param path Absolute path to a model .obj or other format accepted by assimp
*/
void Model::loadModel(const std::string & path) void Model::loadModel(const std::string & path)
{ {
Assimp::Importer import; Assimp::Importer import;
@ -195,13 +208,14 @@ void Model::loadModel(const std::string & path)
// JIC a relative path was used, get the absolute file path // JIC a relative path was used, get the absolute file path
QFileInfo info(path.c_str()); QFileInfo info(path.c_str());
info.makeAbsolute(); 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 // Import the model, converting non-triangular geometry to triangles
// + And flipping texture UVs, etc.. // + And flipping texture UVs, etc..
// Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html // Assimp options: http://assimp.sourceforge.net/lib_html/postprocess_8h.html
const aiScene * scene = const aiScene * scene =
import.ReadFile(temp, aiProcess_Triangulate import.ReadFile(mDirectory, aiProcess_Triangulate
| aiProcess_FlipUVs | aiProcess_FlipUVs
| aiProcess_GenSmoothNormals | aiProcess_GenSmoothNormals
| aiProcess_CalcTangentSpace | aiProcess_CalcTangentSpace
@ -216,7 +230,7 @@ void Model::loadModel(const std::string & path)
return; return;
} }
// If there were no errors, find the directory that contains this model // 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 // Pass the pointers to the root node and the scene to recursive function
// + Base case breaks when no nodes left to process on model // + Base case breaks when no nodes left to process on model

13
src/resourcemanager.cpp Normal file
View File

@ -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/";

35
src/resourcemanager.h Normal file
View File

@ -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 <string>
#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

View File

@ -10,6 +10,7 @@
#include <texture.h> #include <texture.h>
#include <meshrenderer.h> #include <meshrenderer.h>
#include <model.h> #include <model.h>
#include <resourcemanager.h>
#include <scene.h> #include <scene.h>
@ -151,42 +152,31 @@ void Scene::init()
// //
// Model loading // Model loading
mModels.push_back(new Model("backpack", mModels.push_back(new Model("backpack", ":/models/backpack/backpack.obj"));
"../resources/models/backpack/backpack.obj"));
// Sometimes model textures need flipped in certain directions // Sometimes model textures need flipped in certain directions
mModels.back()->flipTexture("diffuse.jpg", false, true); mModels.back()->flipTexture("diffuse.jpg", false, true);
mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f); mModels.back()->mTransform.setTranslation(0.0f, 0.0f, -10.0f);
mModels.push_back( mModels.push_back(new Model("bird", ":/models/bird/bird.obj"));
new Model("bird",
"../resources/models/bird/bird.obj"));
mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f); mModels.back()->mTransform.setTranslation(2.0f, 2.0f, -10.0f);
// Sometimes the models are very large // Sometimes the models are very large
mModels.back()->mTransform.scale(0.0025f); mModels.back()->mTransform.scale(0.0025f);
mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f); mModels.back()->mTransform.rotate(-110.0f, 0.0f, 1.0f, 0.0f);
mModels.push_back(new Model("lion", mModels.push_back(new Model("lion", ":/models/lion/lion.obj"));
"../resources/models/lion/lion.obj"));
mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f); mModels.back()->mTransform.setTranslation(-3.0f, -1.0f, -10.0f);
mModels.back()->mTransform.scale(0.15f); mModels.back()->mTransform.scale(0.15f);
mModels.push_back( mModels.push_back(new Model("alien", ":/models/alien-hominid/alien.obj"));
new Model("alien",
"../resources/models/alien-hominid/alien.obj"));
mModels.back()->mTransform.setTranslation(2.0f, -1.0f, -5.0f); mModels.back()->mTransform.setTranslation(2.0f, -1.0f, -5.0f);
mModels.back()->mTransform.scale(0.15f); mModels.back()->mTransform.scale(0.15f);
mModels.push_back( mModels.push_back(new Model("scythe", ":/models/scythe/scythe.obj"));
new Model("scythe",
"../resources/models/scythe/scythe.obj")
);
mModels.back()->mTransform.setTranslation(-6.0f, 0.0f, -10.0f); 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, 1.0f, 0.0f, 0.0f);
mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f); mModels.back()->mTransform.rotate(90.0f, 0.0f, 1.0f, 0.0f);
mModels.push_back( mModels.push_back(new Model("masterChief", ":/models/spartan/spartan.obj"));
new Model("masterChief",
"../resources/models/spartan/spartan.obj"));
mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f); mModels.back()->mTransform.setTranslation(-1.5f, 0.5f, -2.0f);
@ -204,9 +194,9 @@ void Scene::init()
mMeshes.back()->init(); mMeshes.back()->init();
mModels.push_back( mModels.push_back(
new Model("alienTest", new Model("alienTest", ":/models/alien-hominid/alien.obj",
"../resources/models/alien-hominid/alien.obj", ":/model-specular.vert", ":/model-specular.frag")
":/model-specular.vert", ":/model-specular.frag")); );
mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f); mModels.back()->mTransform.setTranslation(3.0f, -1.0f, 10.0f);
mModels.back()->mTransform.scale(0.15f); mModels.back()->mTransform.scale(0.15f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f)); 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 // Test spartan Model with phong lighting, specular and normal mapping
mMeshes.push_back( 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.setTranslation(1.0f, 1.5f, 10.0f);
mMeshes.back()->mTransform.scale(0.25f); mMeshes.back()->mTransform.scale(0.25f);
// This function changes values we have allocated in a buffer, so init() after // This function changes values we have allocated in a buffer, so init() after
@ -232,9 +223,9 @@ void Scene::init()
mMeshes.back()->init(); mMeshes.back()->init();
mModels.push_back( mModels.push_back(
new Model("spartanTest", new Model("spartanTest", ":/models/spartan/spartan.obj",
"../resources/models/spartan/spartan.obj", ":/model-normals.vert", ":/model-normals.frag")
":/model-normals.vert", ":/model-normals.frag")); );
mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f); mModels.back()->mTransform.setTranslation(0.0f, -1.0f, 10.0f);
mModels.back()->mTransform.scale(2.0f); mModels.back()->mTransform.scale(2.0f);
mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f)); mModels.back()->setUniform("uMaterial.ambient", QVector3D(1.0f, 1.0f, 1.0f));