From d3c755713d293863b58a57c1e4e78a6ea6d3fea0 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Tue, 13 Apr 2021 20:29:29 +0200 Subject: [PATCH] Working Multithreading --- src/JsonParser.cpp | 26 +++++++--------------- src/JsonParser.h | 2 +- src/Model.cpp | 54 ++++++++++++++++++++++++++++++++++++++++------ src/Model.h | 18 ++++++++++++++++ src/Texture.cpp | 8 +++---- src/Texture.h | 2 +- src/World.cpp | 5 +++++ 7 files changed, 83 insertions(+), 32 deletions(-) diff --git a/src/JsonParser.cpp b/src/JsonParser.cpp index eca4ca7..6036d0a 100644 --- a/src/JsonParser.cpp +++ b/src/JsonParser.cpp @@ -4,7 +4,7 @@ #include #include -JsonParser::JsonParser(std::string path) +JsonParser::JsonParser(const std::string& path) { std::ifstream file(path.c_str(), std::ifstream::binary); @@ -28,17 +28,6 @@ JsonParser::~JsonParser() } -static std::mutex s_ModelsMutex; - -static void loadModel(const std::string modelName, const std::string modelPath, std::vector* model_vec) { - Model *current_model = new Model(modelName, modelPath); - if(current_model) { - std::lock_guard lock(s_ModelsMutex); - model_vec->push_back(current_model); - std::cout << "Loaded Model \"" << modelName << "\" from \"" << modelPath << "\"" << std::endl; - } -} - std::vector JsonParser::getModels() { std::vector temp_models; @@ -60,19 +49,20 @@ std::vector JsonParser::getModels() } std::vector> futures; + std::mutex mutex; auto* temp_models_ptr = &temp_models; for (const auto& model_skeleton : model_skeletons) { - /*auto loadModel = [](const std::string& modelName, const std::string& modelPath, std::mutex& mutex, std::vector* model_vec) { - Model *current_model = new Model(modelName, modelPath); + auto loadModel = [&]() { + Model *current_model = new Model(model_skeleton.model_name, model_skeleton.model_path); if(current_model) { std::lock_guard lock(mutex); - model_vec->push_back(current_model); - std::cout << "Loaded Model \"" << modelName << "\" from \"" << modelPath << "\"" << std::endl; + temp_models_ptr->push_back(current_model); + std::cout << "Loaded Model \"" << model_skeleton.model_name << "\" from \"" << model_skeleton.model_path << "\"" << std::endl; } - };*/ + }; - futures.push_back(std::async(std::launch::async, loadModel, model_skeleton.model_name, model_skeleton.model_path, temp_models_ptr)); + futures.push_back(std::async(std::launch::async, loadModel)); } return temp_models; diff --git a/src/JsonParser.h b/src/JsonParser.h index db15ed6..f0a3959 100644 --- a/src/JsonParser.h +++ b/src/JsonParser.h @@ -13,7 +13,7 @@ class JsonParser { public: - JsonParser(std::string path); + JsonParser(const std::string& path); ~JsonParser(); std::vector getModels(); diff --git a/src/Model.cpp b/src/Model.cpp index 21265d3..2c73d97 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -24,6 +24,11 @@ Model::~Model() void Model::draw(ShaderProgram *shaderProgram) { + if (!model_prepared) { + std::cout << "WARNING: Model not prepared! Unable to draw!" << std::endl; + return; + } + // Iterate through every mesh and call the draw function for (auto it = meshes.begin(); it != meshes.end(); it++) { (*it)->draw(shaderProgram); @@ -32,6 +37,11 @@ void Model::draw(ShaderProgram *shaderProgram) void Model::drawWithoutTextures() { + if (!model_prepared) { + std::cout << "WARNING: Model not prepared! Unable to draw!" << std::endl; + return; + } + // Iterate through every mesh and call the draw function for (auto it = meshes.begin(); it != meshes.end(); it++) { (*it)->drawWithoutTextures(); @@ -71,10 +81,15 @@ void Model::loadModel(const std::string &pathToModel) textureSources.push_back(currentTextureSource); } + for (unsigned int i = 0; i < numTextures; i++) { - std::string textureSource = directory + '/' + textureSources[i].c_str(); - Texture *newTex = new Texture(textureSource.c_str(), textureTypes[i]); - loadedTextures.push_back(newTex); + TexturePrototype texture_prototype; + std::string texturePath = directory + '/' + textureSources[i].c_str(); + + texture_prototype.texturePath = std::move(texturePath); + texture_prototype.textureType = textureTypes[i]; + + modelTexturePrototypes.push_back(texture_prototype); } // Here starts the first mesh @@ -83,6 +98,8 @@ void Model::loadModel(const std::string &pathToModel) for (unsigned int j = 0; j < numMeshes; j++) { + MeshPrototype mesh_prototype; + uint32_t numMeshVertices, numMeshIndices, numMeshTextureIds; input.read((char *) &numMeshVertices, sizeof(uint32_t)); @@ -97,25 +114,48 @@ void Model::loadModel(const std::string &pathToModel) std::vector meshVertices; meshVertices.resize(numMeshVertices); input.read((char *) meshVertices.data(), vertexBlockSize); + mesh_prototype.meshVertices = std::move(meshVertices); std::vector meshIndices; meshIndices.resize(numMeshIndices); input.read((char *) meshIndices.data(), indexBlockSize); + mesh_prototype.meshIndices = std::move(meshIndices); - std::vector meshTextures; for (unsigned int i = 0; i < numMeshTextureIds; i++) { uint32_t currentTextureId; input.read((char *) ¤tTextureId, sizeof(uint32_t)); - meshTextures.push_back(loadedTextures[currentTextureId]); + mesh_prototype.textureIds.push_back(currentTextureId); } - Mesh *currentMesh = new Mesh(meshVertices, meshIndices, meshTextures); - meshes.push_back(currentMesh); + modelMeshPrototypes.push_back(std::move(mesh_prototype)); } input.close(); } +void Model::prepareModel() +{ + model_prepared = true; + + // Create textures on GPU + for (auto& it : modelTexturePrototypes) { + Texture *newTex = new Texture(it.texturePath.c_str(), it.textureType); + loadedTextures.push_back(newTex); + } + + // Create meshes on GPU + for (const auto& it : modelMeshPrototypes) { + std::vector meshTextures; + for (const auto it2 : it.textureIds) { + meshTextures.push_back(loadedTextures[it2]); + } + + Mesh *currentMesh = new Mesh(std::move(it.meshVertices), std::move(it.meshIndices), meshTextures); + meshes.push_back(currentMesh); + } +} + + Mesh* Model::getMesh(unsigned int index) { return meshes[index]; diff --git a/src/Model.h b/src/Model.h index 4df2697..b94ffc9 100644 --- a/src/Model.h +++ b/src/Model.h @@ -5,12 +5,25 @@ #include "Mesh.h" +struct TexturePrototype { + uint32_t textureType; + std::string texturePath; +}; + +struct MeshPrototype { + std::vector textureIds; + std::vector meshVertices; + std::vector meshIndices; +}; + class Model { public: Model(const std::string& modelName, const std::string& pathToModel); ~Model(); + void prepareModel(); + void draw(ShaderProgram *shaderProgram); void drawWithoutTextures(); @@ -24,8 +37,13 @@ private: std::vector meshes; std::vector loadedTextures; + std::vector modelTexturePrototypes; + std::vector modelMeshPrototypes; + std::string directory; + bool model_prepared = false; + static uint32_t id_counter; uint32_t id; std::string unique_name; diff --git a/src/Texture.cpp b/src/Texture.cpp index 87fd51a..cbe5a0f 100644 --- a/src/Texture.cpp +++ b/src/Texture.cpp @@ -3,13 +3,11 @@ #include #include -Texture::Texture(const char *texturePath, uint8_t textureType) +Texture::Texture(const std::string& texturePath, uint8_t textureType) : + texturePath(texturePath), textureType(textureType) { - this->texturePath = texturePath; - this->textureType = textureType; - stbi_set_flip_vertically_on_load(1); - auto *textureBuffer = stbi_load(texturePath, &textureWidth, &textureHeight, &numComponents, 0); + auto *textureBuffer = stbi_load(texturePath.c_str(), &textureWidth, &textureHeight, &numComponents, 0); GLenum internalFormat; GLenum dataFormat; diff --git a/src/Texture.h b/src/Texture.h index d15b23c..871fbcb 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -15,7 +15,7 @@ enum cubeMapFaces {cm_right, cm_left, cm_top, cm_bottom, cm_back, cm_front, CUBE class Texture { public: - Texture(const char *texturePath, uint8_t textureType); + Texture(const std::string& texturePath, uint8_t textureType); ~Texture(); void bind(uint8_t textureUnit, ShaderProgram *shaderProgram, uint8_t textureTypeNum); diff --git a/src/World.cpp b/src/World.cpp index 157b1f5..f2fc013 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -21,6 +21,11 @@ World::World(std::vector shaderPrograms) : JsonParser modelParser("data/models.json"); models = modelParser.getModels(); + + for (const auto& it : models) { + it->prepareModel(); + } + entities = modelParser.getEntities(models, shaderPrograms); skybox = modelParser.getSkybox(getModelByName("cube"), Controller::getShaderProgramByName(shaderPrograms, "skyboxProgram"));