diff --git a/data/models.json b/data/models.json index 3324492..63073c3 100644 --- a/data/models.json +++ b/data/models.json @@ -64,6 +64,34 @@ "shaderProgram": "lightProgram" } ], + "directionalLight": { + "intensity": 0.25, + "direction": [ + -0.2, + -1.0, + -0.3 + ], + "color": [ + 1.0, + 1.0, + 1.0 + ] + }, + "pointLights": [ + { + "intensity": 7.5, + "position": [ + 0.0, + 1.0, + 0.0 + ], + "color": [ + 1.0, + 1.0, + 1.0 + ] + } + ], "textures": [ { "unique_name": "fallback_normal", diff --git a/src/Controller.cpp b/src/Controller.cpp index 681cf22..8bee1c9 100644 --- a/src/Controller.cpp +++ b/src/Controller.cpp @@ -37,7 +37,11 @@ Controller::Controller() : m_gameWindow(std::unique_ptr(new Window)) m_camera = new Camera(90.0f, m_gameWindow->getWindowAspectRatio()); JsonParser shaderParser("data/shaderPrograms.json"); - m_shaderPrograms = shaderParser.getShaderPrograms(); + auto shaderProgramPrototypes = shaderParser.getShaderProgramPrototypes(); + + for (auto &prototype : shaderProgramPrototypes) { + m_shaderPrograms.push_back(new ShaderProgram(prototype)); + } m_postProcessFrameBuffer = new FrameBuffer(m_gameWindow->getWindowWidth(), m_gameWindow->getWindowHeight(), getShaderProgramByName("postProcessingProgram")); diff --git a/src/Entity.cpp b/src/Entity.cpp index 2be56cd..b29e0aa 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -10,7 +10,7 @@ uint32_t Entity::s_idCounter = 0; Entity::Entity(Prototype prototype, Model *model, ShaderProgram *shaderProgram) - : m_uniqueName(prototype.name), m_model(model), m_shaderProgram(shaderProgram), m_id(s_idCounter++) + : m_id(s_idCounter++), m_uniqueName(prototype.name), m_model(model), m_shaderProgram(shaderProgram) { setPosition(prototype.position); setRotation(prototype.rotation); @@ -146,11 +146,19 @@ bool Entity::getIsLightSource() return m_isLightSource; } -Skybox::Skybox(Model *cubeModel, ShaderProgram *shaderProgram, const char *texturePseudoPath) - : m_cubeModel(cubeModel), m_shaderProgram(shaderProgram), m_cubeMap(texturePseudoPath), +Skybox::Skybox(Prototype prototype, Model *cubeModel, ShaderProgram *shaderProgram) + : m_cubeModel(cubeModel), m_shaderProgram(shaderProgram), m_cubeMap(new CubeMap(prototype.texturePath.c_str())), m_vertexArray(cubeModel->getMesh(0)->getVertexArray()) +{} + +Skybox::~Skybox() { - // Empty + delete m_cubeMap; +} + +void Skybox::initializeOnGPU() +{ + m_cubeMap->initializeOnGPU(); } void Skybox::draw(glm::mat4 viewMatrix, glm::mat4 projectionMatrix) @@ -168,9 +176,9 @@ void Skybox::draw(glm::mat4 viewMatrix, glm::mat4 projectionMatrix) m_shaderProgram->setUniform("u_viewProjectionMatrix", viewProjectionMatrix); - m_cubeMap.bind(m_shaderProgram); + m_cubeMap->bind(m_shaderProgram); m_cubeModel->getMesh(0)->drawWithoutTextures(); - m_cubeMap.unbind(); + m_cubeMap->unbind(); m_shaderProgram->unbind(); glDepthMask(GL_TRUE); diff --git a/src/Entity.h b/src/Entity.h index 9035540..3c1b98e 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -68,16 +68,25 @@ private: class Skybox { public: - Skybox(Model *cubeModel, ShaderProgram *shaderProgram, const char *texturePseudoPath); - ~Skybox() = default; + struct Prototype + { + std::string texturePath; + }; + + Skybox(Prototype prototype, Model *cubeModel, ShaderProgram *shaderProgram); + ~Skybox(); + + void initializeOnGPU(); void draw(glm::mat4 viewMatrix, glm::mat4 projectionMatrix); private: + bool m_isInitialized = false; + Model *m_cubeModel; ShaderProgram *m_shaderProgram; - CubeMap m_cubeMap; + CubeMap *m_cubeMap; VertexArray *m_vertexArray; }; diff --git a/src/JsonParser.cpp b/src/JsonParser.cpp index 1dfdbbf..46f5ca5 100644 --- a/src/JsonParser.cpp +++ b/src/JsonParser.cpp @@ -10,12 +10,12 @@ #include #include -JsonParser::JsonParser(const std::string &path) +JsonParser::JsonParser(const std::string &jsonFilepath) { - std::ifstream file(path.c_str(), std::ifstream::binary); + std::ifstream file(jsonFilepath.c_str(), std::ifstream::binary); if (!file) { - std::cout << "Error reading file \"" << path << "\"." << std::endl; + std::cout << "Error reading file \"" << jsonFilepath << "\"." << std::endl; return; } @@ -87,9 +87,9 @@ std::vector JsonParser::getEntityPrototypes() const return entityPrototypes; } -std::vector JsonParser::getShaderPrograms() +std::vector JsonParser::getShaderProgramPrototypes() { - std::vector temp_shaderPrograms; + std::vector prototypes; const Json::Value shaderProgramsJson = m_root["shaderPrograms"]; @@ -99,28 +99,23 @@ std::vector JsonParser::getShaderPrograms() std::string shaderProgram_fragmentPath = shaderProgramsJson[index]["fragmentPath"].asString(); std::string shaderProgram_geometryPath = shaderProgramsJson[index]["geometryPath"].asString(); - ShaderProgram *current_shaderProgram; - if (shaderProgram_geometryPath.empty()) { - current_shaderProgram = - new ShaderProgram(shaderProgram_name, shaderProgram_vertexPath, shaderProgram_fragmentPath); - } else { - current_shaderProgram = new ShaderProgram(shaderProgram_name, shaderProgram_vertexPath, - shaderProgram_geometryPath, shaderProgram_fragmentPath); - } - temp_shaderPrograms.push_back(current_shaderProgram); - std::cout << "Loaded ShaderProgram \"" << shaderProgram_name << "\"" << std::endl; + ShaderProgram::Prototype prototype{shaderProgram_name, shaderProgram_vertexPath, shaderProgram_fragmentPath, + shaderProgram_geometryPath}; + + prototypes.push_back(prototype); + // std::cout << "Loaded ShaderProgram \"" << shaderProgram_name << "\"" << std::endl; } - return temp_shaderPrograms; + return prototypes; } -std::vector JsonParser::getLights(ShaderProgram *shaderProgram) +std::vector> JsonParser::getLightPrototypes() const { - std::vector temp_lights; - glm::vec3 light_direction = {1.0f, 0.0f, 0.0f}; - glm::vec3 light_position = {}; - glm::vec3 light_color = {1.0f, 1.0f, 1.0f}; - float light_intensity = 10.0f; + std::vector> prototypes; + glm::vec3 direction = {1.0f, 0.0f, 0.0f}; + glm::vec3 position = {}; + glm::vec3 color = {1.0f, 1.0f, 1.0f}; + float intensity = 10.0f; const Json::Value directionalLightsJson = m_root["directionalLight"]; @@ -129,52 +124,55 @@ std::vector JsonParser::getLights(ShaderProgram *shaderProgram) Json::Value intensityJson = directionalLightsJson["intensity"]; if (!intensityJson.empty()) { - light_intensity = intensityJson.asFloat(); + intensity = intensityJson.asFloat(); } if (!directionJson.empty()) { - light_direction.x = directionJson[0].asFloat(); - light_direction.y = directionJson[1].asFloat(); - light_direction.z = directionJson[2].asFloat(); + direction.x = directionJson[0].asFloat(); + direction.y = directionJson[1].asFloat(); + direction.z = directionJson[2].asFloat(); } if (!colorJson.empty()) { - light_color.x = colorJson[0].asFloat(); - light_color.y = colorJson[1].asFloat(); - light_color.z = colorJson[2].asFloat(); + color.x = colorJson[0].asFloat(); + color.y = colorJson[1].asFloat(); + color.z = colorJson[2].asFloat(); } - DirectionalLight *current_directionalLight = - new DirectionalLight(light_direction, light_color, light_intensity, shaderProgram); - current_directionalLight->setActive(true); - temp_lights.push_back(current_directionalLight); + auto prototype = std::unique_ptr(new DirectionalLight::Prototype{direction, color, intensity}); + + // DirectionalLight *current_directionalLight = new DirectionalLight(*prototype, shaderProgram); + // current_directionalLight->setActive(true); + + prototypes.push_back(std::move(prototype)); // Pointlights const Json::Value pointLightsJson = m_root["pointLights"]; int index = 0; for (; index < (int)pointLightsJson.size(); index++) { - PointLight *current_pointLight; - const Json::Value positionJson = pointLightsJson[index]["position"]; colorJson = pointLightsJson[index]["color"]; intensityJson = pointLightsJson[index]["intensity"]; if (!intensityJson.empty()) { - light_intensity = intensityJson.asFloat(); + intensity = intensityJson.asFloat(); } if (!positionJson.empty()) { - light_position.x = positionJson[0].asFloat(); - light_position.y = positionJson[1].asFloat(); - light_position.z = positionJson[2].asFloat(); + position.x = positionJson[0].asFloat(); + position.y = positionJson[1].asFloat(); + position.z = positionJson[2].asFloat(); } if (!colorJson.empty()) { - light_color.x = colorJson[0].asFloat(); - light_color.y = colorJson[1].asFloat(); - light_color.z = colorJson[2].asFloat(); + color.x = colorJson[0].asFloat(); + color.y = colorJson[1].asFloat(); + color.z = colorJson[2].asFloat(); } - current_pointLight = new PointLight(light_position, light_color, light_intensity, shaderProgram); - current_pointLight->setActive(true); - temp_lights.push_back(current_pointLight); + auto prototype = std::unique_ptr(new PointLight::Prototype{position, color, intensity}); + + // current_pointLight = new PointLight(*prototype, shaderProgram); + // current_pointLight->setActive(true); + + prototypes.push_back(std::move(prototype)); } // In case there aren't enough PointLights defined in the Json file @@ -182,13 +180,16 @@ std::vector JsonParser::getLights(ShaderProgram *shaderProgram) const glm::vec3 default_position(0.0f); const glm::vec3 default_color(1.0f); const float default_intensity = 10.0f; - PointLight *current_pointLight = - new PointLight(default_position, default_color, default_intensity, shaderProgram); - current_pointLight->setActive(false); - temp_lights.push_back(current_pointLight); + auto prototype = std::unique_ptr( + new PointLight::Prototype{default_position, default_color, default_intensity}); + + // PointLight *current_pointLight = new PointLight(*prototype, shaderProgram); + // current_pointLight->setActive(false); + + prototypes.push_back(std::move(prototype)); } - return temp_lights; + return prototypes; } std::vector JsonParser::getScreenPrototypes() const @@ -234,15 +235,12 @@ std::vector JsonParser::getWidgetPrototypesFromScreen(const J return widgetPrototypes; } -Skybox *JsonParser::getSkybox(Model *cubeModel, ShaderProgram *skyboxProgram) +Skybox::Prototype JsonParser::getSkyboxPrototype() const { - Skybox *temp_skybox; - const Json::Value shaderProgramsJson = m_root["skybox"]; - std::string skybox_texturePath = shaderProgramsJson["texturePath"].asString(); - temp_skybox = new Skybox(cubeModel, skyboxProgram, skybox_texturePath.c_str()); - std::cout << "Loaded Skybox \"" << skybox_texturePath << "\"" << std::endl; + std::string texturePath = shaderProgramsJson["texturePath"].asString(); + Skybox::Prototype prototype{texturePath}; - return temp_skybox; + return prototype; } diff --git a/src/JsonParser.h b/src/JsonParser.h index e08c058..56634f9 100644 --- a/src/JsonParser.h +++ b/src/JsonParser.h @@ -1,34 +1,34 @@ #pragma once #include +#include #include #include #include "Entity.h" +#include "Light.h" #include "Model.h" #include "Screen.h" +#include "ShaderProgram.h" #include "Widget.h" -class Light; class Screen; -class Skybox; class ShaderProgram; class FrameBuffer; -class Widget; class JsonParser { public: - JsonParser(const std::string &path); + JsonParser(const std::string &jsonFilepath); ~JsonParser(); std::vector getModelPrototypes() const; std::vector getEntityPrototypes() const; - std::vector getLights(ShaderProgram *shaderProgram); // should be under entities too + std::vector> getLightPrototypes() const; std::vector getScreenPrototypes() const; - Skybox *getSkybox(Model *cubeModel, ShaderProgram *skyboxProgram); + Skybox::Prototype getSkyboxPrototype() const; - std::vector getShaderPrograms(); + std::vector getShaderProgramPrototypes(); private: std::vector getWidgetPrototypesFromScreen(const Json::Value &screenJson) const; diff --git a/src/Light.cpp b/src/Light.cpp index ac544e5..82f9cb3 100644 --- a/src/Light.cpp +++ b/src/Light.cpp @@ -5,8 +5,6 @@ uint32_t Light::s_idCounter = 0; -// Light - Light::Light(glm::vec3 color, float intensity, ShaderProgram *shaderProgram) : m_shaderProgram(shaderProgram), m_intensity(intensity) { @@ -14,6 +12,9 @@ Light::Light(glm::vec3 color, float intensity, ShaderProgram *shaderProgram) m_lightColor = color * intensity; } +Light::~Light() +{} + glm::vec3 Light::getColor() { return m_lightColor; @@ -42,13 +43,9 @@ void Light::setActive(bool active) update(); } -// PointLight - -PointLight::PointLight(glm::vec3 position, glm::vec3 color, float intensity, ShaderProgram *shaderProgram) - : Light(color, intensity, shaderProgram), m_position(position) -{ - // Empty -} +PointLight::PointLight(Prototype prototype, ShaderProgram *shaderProgram) + : Light(prototype.color, prototype.intensity, shaderProgram), m_position(prototype.position) +{} void PointLight::update() { @@ -79,13 +76,9 @@ void PointLight::setPosition(glm::vec3 position) update(); } -// DirectionalLight - -DirectionalLight::DirectionalLight(glm::vec3 direction, glm::vec3 color, float intensity, ShaderProgram *shaderProgram) - : Light(color, intensity, shaderProgram), m_direction(direction) -{ - // Empty -} +DirectionalLight::DirectionalLight(Prototype prototype, ShaderProgram *shaderProgram) + : Light(prototype.color, prototype.intensity, shaderProgram), m_direction(prototype.direction) +{} void DirectionalLight::update() { diff --git a/src/Light.h b/src/Light.h index 80d0e0b..dd2650c 100644 --- a/src/Light.h +++ b/src/Light.h @@ -10,8 +10,13 @@ class ShaderProgram; class Light { public: - virtual ~Light() - {} + struct Prototype + { + virtual ~Prototype() = default; + }; + + Light(glm::vec3 color, float intensity, ShaderProgram *shaderProgram); + virtual ~Light() = 0; virtual void update() = 0; @@ -23,8 +28,6 @@ public: glm::vec3 getColor(); protected: - Light(glm::vec3 color, float intensity, ShaderProgram *shaderProgram); - ShaderProgram *m_shaderProgram; uint32_t m_id; @@ -42,7 +45,17 @@ protected: class PointLight : public Light { public: - PointLight(glm::vec3 position, glm::vec3 color, float intensity, ShaderProgram *shaderProgram); + struct Prototype : public Light::Prototype + { + Prototype(glm::vec3 position, glm::vec3 color, float intensity) + : position(position), color(color), intensity(intensity) + {} + glm::vec3 position; + glm::vec3 color; + float intensity; + }; + + PointLight(Prototype prototype, ShaderProgram *shaderProgram); ~PointLight() override = default; void setPosition(glm::vec3 position); @@ -59,7 +72,18 @@ private: class DirectionalLight : public Light { public: - DirectionalLight(glm::vec3 direction, glm::vec3 color, float intensity, ShaderProgram *shaderProgram); + struct Prototype : public Light::Prototype + { + Prototype(glm::vec3 direction, glm::vec3 color, float intensity) + : direction(direction), color(color), intensity(intensity) + {} + glm::vec3 direction; + glm::vec3 color; + float intensity; + }; + + DirectionalLight(Prototype prototype, ShaderProgram *shaderProgram); + ~DirectionalLight() override = default; void setDirection(glm::vec3 direction); diff --git a/src/Mesh.cpp b/src/Mesh.cpp index eb21de5..e16a32d 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -4,7 +4,7 @@ #include "VertexArray.h" Mesh::Mesh(std::vector vertices, std::vector indices, std::vector textures) - : m_numElements(indices.size()), m_textures(textures), m_preInitializationVertexData{vertices, indices} + : m_preInitializationVertexData{vertices, indices}, m_numElements(indices.size()), m_textures(textures) {} void Mesh::initializeOnGPU() diff --git a/src/Model.cpp b/src/Model.cpp index 3dffbc6..848b72b 100644 --- a/src/Model.cpp +++ b/src/Model.cpp @@ -10,7 +10,7 @@ uint32_t Model::s_idCounter = 0; -Model::Model(const Prototype &prototype) : m_uniqueName(prototype.modelName), m_id(s_idCounter++) +Model::Model(const Prototype &prototype) : m_id(s_idCounter++), m_uniqueName(prototype.modelName) { m_workingPath = prototype.modelPath.substr(0, prototype.modelPath.find_last_of('/')); diff --git a/src/Screen.cpp b/src/Screen.cpp index e3ee9fd..716c04f 100644 --- a/src/Screen.cpp +++ b/src/Screen.cpp @@ -9,7 +9,7 @@ uint32_t Screen::s_idCounter = 0; Screen::Screen(Prototype prototype, FrameBuffer *framebuffer, ShaderProgram *shaderProgram) - : m_uniqueName(prototype.name), m_frameBuffer(framebuffer), m_shaderProgram(shaderProgram), m_id(s_idCounter++) + : m_id(s_idCounter++), m_uniqueName(prototype.name), m_frameBuffer(framebuffer), m_shaderProgram(shaderProgram) { for (auto &prototype : prototype.widgetPrototypes) { Texture *currentTexture = new Texture(prototype.texturePrototype); diff --git a/src/ShaderProgram.cpp b/src/ShaderProgram.cpp index 407e749..2f5a39f 100644 --- a/src/ShaderProgram.cpp +++ b/src/ShaderProgram.cpp @@ -6,26 +6,32 @@ #include #include -ShaderProgram::ShaderProgram(const std::string &name, const std::string &vertexShaderPath, - const std::string &fragmentShaderPath) - : m_uniqueName(name) +ShaderProgram::ShaderProgram(Prototype prototype) : m_uniqueName(prototype.name) { - std::string vertexShaderSource = parse(vertexShaderPath.c_str()); - std::string fragmentShaderSource = parse(fragmentShaderPath.c_str()); + std::string vertexShaderSource = parse(prototype.vertexPath.c_str()); + std::string fragmentShaderSource = parse(prototype.fragmentPath.c_str()); m_shaderProgramId = glCreateProgram(); GLuint vs = compile(vertexShaderSource, GL_VERTEX_SHADER); + GLuint gs; GLuint fs = compile(fragmentShaderSource, GL_FRAGMENT_SHADER); glAttachShader(m_shaderProgramId, vs); glAttachShader(m_shaderProgramId, fs); + if (!prototype.geometryPath.empty()) { + std::string geometryShaderSource = parse(prototype.geometryPath.c_str()); + gs = compile(geometryShaderSource, GL_GEOMETRY_SHADER); + glAttachShader(m_shaderProgramId, gs); + } + glLinkProgram(m_shaderProgramId); GLint isLinked = 0; glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked); if (!isLinked) { - std::cout << "Failed to link shaderProgram: " << vertexShaderPath << ", " << fragmentShaderPath << std::endl; + std::cout << "Failed to link shaderProgram: " << prototype.vertexPath << ", " << prototype.geometryPath << ", " + << prototype.fragmentPath << std::endl; } #ifdef _RELEASE @@ -34,43 +40,11 @@ ShaderProgram::ShaderProgram(const std::string &name, const std::string &vertexS glDeleteShader(vs); glDeleteShader(fs); -#endif -} -ShaderProgram::ShaderProgram(const std::string &name, const std::string &vertexShaderPath, - const std::string &geometryShaderPath, const std::string &fragmentShaderPath) - : m_uniqueName(name) -{ - std::string vertexShaderSource = parse(vertexShaderPath.c_str()); - std::string geometryShaderSource = parse(geometryShaderPath.c_str()); - std::string fragmentShaderSource = parse(fragmentShaderPath.c_str()); - - m_shaderProgramId = glCreateProgram(); - GLuint vs = compile(vertexShaderSource, GL_VERTEX_SHADER); - GLuint gs = compile(geometryShaderSource, GL_GEOMETRY_SHADER); - GLuint fs = compile(fragmentShaderSource, GL_FRAGMENT_SHADER); - - glAttachShader(m_shaderProgramId, vs); - glAttachShader(m_shaderProgramId, gs); - glAttachShader(m_shaderProgramId, fs); - - glLinkProgram(m_shaderProgramId); - - GLint isLinked = 0; - glGetProgramiv(m_shaderProgramId, GL_LINK_STATUS, &isLinked); - if (!isLinked) { - std::cout << "Failed to link shaderProgram: " << vertexShaderPath << ", " << geometryShaderPath << ", " - << fragmentShaderPath << std::endl; + if (!prototype.geometryPath.empty()) { + glDetachShader(program, gs); + glDeleteShader(gs); } - -#ifdef _RELEASE - glDetachShader(program, vs); - glDetachShader(program, gs); - glDetachShader(program, fs); - - glDeleteShader(vs); - glDeleteShader(gs); - glDeleteShader(fs); #endif } diff --git a/src/ShaderProgram.h b/src/ShaderProgram.h index 7dbee1d..fb86f7b 100644 --- a/src/ShaderProgram.h +++ b/src/ShaderProgram.h @@ -8,9 +8,16 @@ class ShaderProgram { public: - ShaderProgram(const std::string &name, const std::string &vertexShaderPath, const std::string &fragmentShaderPath); - ShaderProgram(const std::string &name, const std::string &vertexShaderPath, const std::string &geometryShaderPath, - const std::string &fragmentShaderPath); + struct Prototype + { + std::string name; + std::string vertexPath; + std::string fragmentPath; + std::string geometryPath; + }; + + ShaderProgram(Prototype prototype); + ~ShaderProgram(); void bind(); diff --git a/src/Texture.cpp b/src/Texture.cpp index 5afe3fd..10088d4 100644 --- a/src/Texture.cpp +++ b/src/Texture.cpp @@ -28,15 +28,20 @@ void Texture::initializeOnGPU() GLenum internalFormat; GLenum dataFormat; - if (m_numComponents == 1) { + + switch (m_numComponents) { + case 1: internalFormat = GL_RED; dataFormat = GL_RED; - } else if (m_numComponents == 3) { + break; + case 3: internalFormat = (m_textureType == TextureType::Diffuse) ? GL_SRGB8 : GL_RGB8; dataFormat = GL_RGB; - } else if (m_numComponents == 4) { + break; + case 4: internalFormat = (m_textureType == TextureType::Diffuse) ? GL_SRGB8_ALPHA8 : GL_RGBA8; dataFormat = GL_RGBA; + break; } // Push texture to grahics card @@ -80,6 +85,8 @@ void Texture::bind(uint8_t textureUnit, ShaderProgram *shaderProgram, uint8_t te case TextureType::Gloss: uniformName += "gloss" + std::to_string(textureTypeNum); break; + default: + break; } // Add u_material as we store textures in a struct @@ -114,6 +121,9 @@ CubeMap::CubeMap(const char *texturePseudoPath) { // Reserve space in vector so that elements can be accessed explicitly. m_texturePaths.resize(CUBEMAP_FACES_NUM_ITEMS); + m_textureBuffers.resize(CUBEMAP_FACES_NUM_ITEMS); + m_numComponents.resize(CUBEMAP_FACES_NUM_ITEMS); + fillTexturePathVector(texturePseudoPath); stbi_set_flip_vertically_on_load(0); @@ -127,34 +137,20 @@ CubeMap::CubeMap(const char *texturePseudoPath) glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - for (unsigned int i = 0; i < CUBEMAP_FACES_NUM_ITEMS; i++) { + int i = 0; + for (auto &path : m_texturePaths) { int32_t numComponents; - auto *textureBuffer = - stbi_load(m_texturePaths[i].c_str(), &m_textureWidth, &m_textureHeight, &numComponents, 0); - - GLenum internalFormat; - GLenum dataFormat; - if (numComponents == 1) { - internalFormat = GL_RED; - dataFormat = GL_RED; - } else if (numComponents == 3) { - internalFormat = GL_SRGB8; - dataFormat = GL_RGB; - } else if (numComponents == 4) { - internalFormat = GL_SRGB8_ALPHA8; - dataFormat = GL_RGBA; - } + auto textureBuffer = stbi_load(path.c_str(), &m_textureWidth, &m_textureHeight, &numComponents, 0); if (!textureBuffer) { - std::cout << "[Warning] CubeMap Texture " << m_texturePaths[i].c_str() << " not found!" << std::endl; + std::cout << "[Warning] CubeMap Texture " << path.c_str() << " not found!" << std::endl; return; } - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat, m_textureWidth, m_textureHeight, 0, - dataFormat, GL_UNSIGNED_BYTE, textureBuffer); - - stbi_image_free(textureBuffer); + m_textureBuffers[i] = textureBuffer; + m_numComponents[i] = numComponents; + i++; } glBindTexture(GL_TEXTURE_CUBE_MAP, 0); @@ -186,6 +182,52 @@ CubeMap::~CubeMap() // glDeleteTextures(1, &m_textureId); } +void CubeMap::initializeOnGPU() +{ + if (m_isInitialized) + return; + + m_isInitialized = true; + + glGenTextures(1, &m_textureId); + glBindTexture(GL_TEXTURE_CUBE_MAP, m_textureId); + + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + int i = 0; + for (auto &textureBuffer : m_textureBuffers) { + GLenum internalFormat; + GLenum dataFormat; + + switch (m_numComponents[i]) { + case 1: + internalFormat = GL_RED; + dataFormat = GL_RED; + break; + case 3: + internalFormat = GL_SRGB8; + dataFormat = GL_RGB; + break; + case 4: + internalFormat = GL_SRGB8_ALPHA8; + dataFormat = GL_RGBA; + break; + } + + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalFormat, m_textureWidth, m_textureHeight, 0, + dataFormat, GL_UNSIGNED_BYTE, textureBuffer); + + stbi_image_free(textureBuffer); + i++; + } + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} + void CubeMap::bind(ShaderProgram *shaderProgram) { std::string uniformName = "u_skybox"; diff --git a/src/Texture.h b/src/Texture.h index 8c2b909..4d66451 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -65,6 +65,8 @@ public: CubeMap(const char *texturePseudoPath); CubeMap(int RESOLUTION); + void initializeOnGPU(); + ~CubeMap(); void bind(ShaderProgram *shaderProgram); @@ -75,7 +77,11 @@ public: private: void fillTexturePathVector(const char *texturePseudoPath); + bool m_isInitialized = false; + std::vector m_texturePaths; + std::vector m_textureBuffers; + std::vector m_numComponents; GLuint m_textureId; diff --git a/src/World.cpp b/src/World.cpp index 313440a..3ad1b26 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -13,8 +13,8 @@ #include World::World(std::vector shaderPrograms) - : m_depthMapDirectionalFBO(DepthMapType::Normal, SHADOW_RES), - m_shaderProgram(Controller::getShaderProgramByName("defaultProgram", shaderPrograms)) + : m_shaderProgram(Controller::getShaderProgramByName("defaultProgram", shaderPrograms)), + m_depthMapDirectionalFBO(DepthMapType::Normal, SHADOW_RES) { // Create 4 depthMaps for (int i = 0; i < 4; i++) { @@ -28,6 +28,7 @@ World::World(std::vector shaderPrograms) m_shaderProgram->unbind(); JsonParser modelParser("data/models.json"); + std::vector modelPrototypes = modelParser.getModelPrototypes(); { @@ -53,6 +54,15 @@ World::World(std::vector shaderPrograms) for (auto &model : m_models) model->initializeOnGPU(); + // TODO: use geometry shader instead of model and load skybox before models. + Skybox::Prototype skyboxPrototype = modelParser.getSkyboxPrototype(); + std::thread skyboxThread([=]() { + m_skybox = new Skybox(skyboxPrototype, getModelByName("cube"), + Controller::getShaderProgramByName("skyboxProgram", shaderPrograms)); + + std::cout << "Loaded Skybox \"" << skyboxPrototype.texturePath << "\"" << std::endl; + }); + std::vector entityPrototypes = modelParser.getEntityPrototypes(); std::vector entities; @@ -84,13 +94,30 @@ World::World(std::vector shaderPrograms) entities.push_back(currentEntity); } } - m_entities = entities; - m_skybox = modelParser.getSkybox(getModelByName("cube"), - Controller::getShaderProgramByName("skyboxProgram", shaderPrograms)); JsonParser lightParser("data/lights.json"); - m_lights = lightParser.getLights(m_shaderProgram); + auto lightPrototypes = lightParser.getLightPrototypes(); + + std::vector lights; + { + for (auto &prototype : lightPrototypes) { + Light *currentLight; + auto directionalPrototype = dynamic_cast(prototype.get()); + if (directionalPrototype) { + currentLight = new DirectionalLight(*directionalPrototype, m_shaderProgram); + } + auto pointPrototype = dynamic_cast(prototype.get()); + if (pointPrototype) { + currentLight = new PointLight(*pointPrototype, m_shaderProgram); + } + lights.push_back(currentLight); + } + } + m_lights = lights; + + skyboxThread.join(); + m_skybox->initializeOnGPU(); } World::~World() diff --git a/src/imgui/Handler.cpp b/src/imgui/Handler.cpp index 12babc8..64c8704 100644 --- a/src/imgui/Handler.cpp +++ b/src/imgui/Handler.cpp @@ -14,6 +14,7 @@ Imgui::Handler::Handler(GLFWwindow *window) : m_GLFWwindow(window) ImGui::CreateContext(); ImGuiIO &io = ImGui::GetIO(); + (void)io; // io.IniFilename = nullptr; // Setup Platform/Renderer bindings