diff --git a/data/lights.json b/data/lights.json index 846b679..cf5b8d7 100644 --- a/data/lights.json +++ b/data/lights.json @@ -6,7 +6,7 @@ }, "pointLights": [ { - "intensity": 10.0, + "intensity": 7.5, "position": [0.0, 1.0, 0.0], "color": [1.0, 1.0, 1.0] } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7150d19..26350aa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,6 +29,7 @@ target_link_libraries( ${OPENGL_LIBRARIES} ${FREETYPE_LIBRARIES} imgui + pthread ) target_compile_options(Fall-Fever PRIVATE -Wall -Wextra -pedantic) diff --git a/src/Controller.cpp b/src/Controller.cpp index ad61d9b..e986f24 100644 --- a/src/Controller.cpp +++ b/src/Controller.cpp @@ -111,7 +111,7 @@ void Controller::run() world->getEntityById(0)->rotate(glm::vec3(0.0f, 1.0f, 0.0f), -0.2f * deltaTime); } static glm::vec3 lightColor = glm::vec3(1.f); - static float intensity = 20.f; + static float intensity = 7.5f; world->updatePointLight(0, true, world->getEntityByName("light")->getPosition(), lightColor, intensity); world->updateDirectionalLight(true, world->getDirectionalLight()->getDirection(), lightColor); getShaderProgramByName("lightProgram")->bind(); diff --git a/src/JsonParser.cpp b/src/JsonParser.cpp index 56c098d..801a1d0 100644 --- a/src/JsonParser.cpp +++ b/src/JsonParser.cpp @@ -2,8 +2,9 @@ #include #include +#include -JsonParser::JsonParser(std::string path) +JsonParser::JsonParser(const std::string& path) { std::ifstream file(path.c_str(), std::ifstream::binary); @@ -33,16 +34,37 @@ std::vector JsonParser::getModels() const Json::Value modelsJson = root["models"]; + struct ModelSkeleton { + std::string model_name; + std::string model_path; + }; + + std::vector model_skeletons; + for (unsigned int index = 0; index < modelsJson.size(); index++) { std::string model_name = modelsJson[index]["unique_name"].asString(); std::string model_path = modelsJson[index]["path"].asString(); - Model *current_model = new Model(model_name, model_path); - if(current_model) { - temp_models.push_back(current_model); - std::cout << "Loaded Model \"" << model_name << "\" from \"" << model_path << "\"" << std::endl; - } + ModelSkeleton model_skeleton = {model_name, model_path}; + model_skeletons.push_back(model_skeleton); } + std::vector> futures; + std::mutex mutex; + + auto* temp_models_ptr = &temp_models; + for (const auto& model_skeleton : model_skeletons) { + auto loadModel = [&]() { + Model *current_model = new Model(model_skeleton.model_name, model_skeleton.model_path); + if(current_model) { + std::lock_guard lock(mutex); + 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)); + } + 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 8fa0014..cbc2651 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -5,7 +5,7 @@ uint32_t Model::id_counter = 0; -Model::Model(std::string &modelName, std::string &modelPath) : +Model::Model(const std::string &modelName, const std::string &modelPath) : unique_name(modelName) { directory = modelPath.substr(0, modelPath.find_last_of('/')); @@ -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,13 +37,18 @@ 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(); } } -void Model::loadModel(std::string &pathToModel) +void Model::loadModel(const std::string &pathToModel) { std::ifstream input(pathToModel, std::ios::in | std::ios::binary); @@ -71,10 +81,15 @@ void Model::loadModel(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); } // When there is no normal map bound, please use fallback texture @@ -85,8 +100,12 @@ void Model::loadModel(std::string &pathToModel) } if (!hasNormalMap) { - Texture *newTex = new Texture("data/res/models/tex/fallback_normal.png", textureType::texture_normal); - loadedTextures.push_back(newTex); + TexturePrototype texture_prototype; + + texture_prototype.texturePath = "data/res/models/tex/fallback_normal.png"; + texture_prototype.textureType = textureType::texture_normal; + + modelTexturePrototypes.push_back(texture_prototype); } // Here starts the first mesh @@ -95,6 +114,8 @@ void Model::loadModel(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)); @@ -109,30 +130,53 @@ void Model::loadModel(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); } if (!hasNormalMap) { // This will be the last texture - meshTextures.push_back(loadedTextures[numTextures]); + mesh_prototype.textureIds.push_back(numTextures); } - 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 03e35f4..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(std::string &modelName, std::string &pathToModel); + Model(const std::string& modelName, const std::string& pathToModel); ~Model(); + void prepareModel(); + void draw(ShaderProgram *shaderProgram); void drawWithoutTextures(); @@ -18,14 +31,19 @@ public: std::string getUniqueName(); private: - void loadModel(std::string &pathToModel); + void loadModel(const std::string &pathToModel); 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"));