diff --git a/.gitignore b/.gitignore index 51d9ca3..cd2265b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ build .directory lib/assimp/libassimp.so.5.0.0 res/models +res/textures diff --git a/imgui.ini b/imgui.ini index dc8954e..ebf8c46 100644 --- a/imgui.ini +++ b/imgui.ini @@ -9,7 +9,7 @@ Size=894,195 Collapsed=0 [Window][Debug Utils] -Pos=14,16 +Pos=39,30 Size=908,204 Collapsed=0 diff --git a/res/shaders/skybox.frag b/res/shaders/skybox.frag new file mode 100644 index 0000000..ba0bbdd --- /dev/null +++ b/res/shaders/skybox.frag @@ -0,0 +1,13 @@ +#version 330 core + +layout(location = 0) out vec4 f_color; + +in vec3 v_texCoord; + +uniform samplerCube u_skybox; + +void main() { + + f_color = texture(u_skybox, v_texCoord); + +} \ No newline at end of file diff --git a/res/shaders/skybox.vert b/res/shaders/skybox.vert new file mode 100644 index 0000000..3f98932 --- /dev/null +++ b/res/shaders/skybox.vert @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 a_position; + +out vec3 v_texCoord; + +uniform mat4 projection; +uniform mat4 view; +uniform mat4 u_viewProjectionMatrix; + +void main() { + + gl_Position = u_viewProjectionMatrix * vec4(a_position, 1.0); + + v_texCoord = a_position; + +} \ No newline at end of file diff --git a/src/Camera.h b/src/Camera.h index 063c668..52ab4b0 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -20,6 +20,8 @@ public: void lookAtTarget(glm::vec3 target); void lookForward(); + glm::mat4 getView() { return viewMatrix; } + glm::mat4 getProj() { return projectionMatrix; } glm::mat4 getViewProj() { return viewProjectionMatrix; } glm::vec3 getPosition() { return position; } glm::vec3 getDirection() { return frontVec; } diff --git a/src/Controller.cpp b/src/Controller.cpp index 1e09551..6fff68e 100644 --- a/src/Controller.cpp +++ b/src/Controller.cpp @@ -78,6 +78,7 @@ void Controller::run() { ShaderProgram shaderProgram("res/shaders/basic.vert", "res/shaders/basic.frag"); ShaderProgram lightProgram("res/shaders/light.vert", "res/shaders/light.frag"); + ShaderProgram skyboxProgram("res/shaders/skybox.vert", "res/shaders/skybox.frag"); //Model model_backpack("res/models/backpack.ffo"); //Model model_plant("res/models/plant.ffo"); @@ -104,6 +105,8 @@ void Controller::run() { lightSource.setRotation(glm::vec3(0.f)); lightSource.setPosition(glm::vec3(-2.f, 1.5f, 2.f)); + Skybox skybox(&model_cube, &skyboxProgram, "res/textures/skybox/"); + World world(&shaderProgram); world.addEntity(dragon); world.addEntity(lightSource); @@ -137,6 +140,8 @@ void Controller::run() { camera->lookForward(); camera->updateVPM(); + skybox.draw(camera->getView(), camera->getProj()); + world.draw(camera->getViewProj(), camera->getPosition()); #ifdef _DEBUG diff --git a/src/Entity.cpp b/src/Entity.cpp index 0b9dec9..4a8806c 100644 --- a/src/Entity.cpp +++ b/src/Entity.cpp @@ -79,4 +79,45 @@ void Entity::updateModelMatrix() { modelMatrix = translationMatrix * rotationMatrix * scaleMatrix; -} \ No newline at end of file +} + + + +Skybox::Skybox(Model *cubeModel, ShaderProgram *shaderProgram, const char *texturePseudoPath) + : cubeModel(cubeModel), + shaderProgram(shaderProgram), + cubeMap(texturePseudoPath), + vertexArray(cubeModel->getMesh(0)->getVertexArray()) { + + // Empty + +} + +void Skybox::draw(glm::mat4 viewMatrix, glm::mat4 projectionMatrix) { + + // To disable face culling first get current state + GLboolean active; + glGetBooleanv(GL_CULL_FACE_MODE, &active); + glDisable(GL_CULL_FACE); + + glDepthMask(GL_FALSE); + shaderProgram->bind(); + + glm::mat4 viewProjectionMatrix = projectionMatrix * glm::mat4(glm::mat3(viewMatrix)); + + shaderProgram->setUniform("u_viewProjectionMatrix", viewProjectionMatrix); + + cubeMap.bind(shaderProgram); + cubeModel->getMesh(0)->drawWithoutTextures(shaderProgram); + cubeMap.unbind(); + + shaderProgram->unbind(); + glDepthMask(GL_TRUE); + + // Restore face culling + if(active) + glEnable(GL_CULL_FACE); + else + glDisable(GL_CULL_FACE); + +} diff --git a/src/Entity.h b/src/Entity.h index 4ff85c9..635789e 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -1,6 +1,7 @@ #pragma once #include "Model.h" +#include "Texture.h" #include "ShaderProgram.h" #include @@ -46,6 +47,26 @@ private: glm::mat4 modelMatrix = glm::mat4(1.0f); - ShaderProgram* shaderProgram; + ShaderProgram *shaderProgram; -}; \ No newline at end of file +}; + +class Skybox { + +public: + + Skybox(Model *cubeModel, ShaderProgram *shaderProgram, const char *texturePseudoPath); + ~Skybox() = default; + + void draw(glm::mat4 viewMatrix, glm::mat4 projectionMatrix); + +private: + + Model *cubeModel; + ShaderProgram *shaderProgram; + + CubeMap cubeMap; + + VertexArray *vertexArray; + +}; diff --git a/src/Mesh.cpp b/src/Mesh.cpp index 8b273a3..a98104e 100644 --- a/src/Mesh.cpp +++ b/src/Mesh.cpp @@ -34,5 +34,12 @@ void Mesh::draw(ShaderProgram *shaderProgram) { (*it)->unbind(); } +} + +void Mesh::drawWithoutTextures(ShaderProgram *shaderProgram) { + + vertexArray.bind(); + glDrawElements(GL_TRIANGLES, numElements, GL_UNSIGNED_INT, 0); + vertexArray.unbind(); } diff --git a/src/Mesh.h b/src/Mesh.h index 761a4a7..321a2e8 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -15,6 +15,9 @@ public: ~Mesh() = default; void draw(ShaderProgram *shaderProgram); + void drawWithoutTextures(ShaderProgram *shaderProgram); + + VertexArray * getVertexArray() { return &vertexArray; } private: diff --git a/src/Model.h b/src/Model.h index ff37efd..b3c1791 100644 --- a/src/Model.h +++ b/src/Model.h @@ -14,6 +14,8 @@ public: void draw(ShaderProgram *shaderProgram); + Mesh * getMesh(unsigned int index) { return meshes[index]; } + private: diff --git a/src/Texture.cpp b/src/Texture.cpp index 91dd151..13624da 100644 --- a/src/Texture.cpp +++ b/src/Texture.cpp @@ -23,17 +23,14 @@ Texture::Texture(const char* texturePath, uint8_t textureType) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - if(textureBuffer) { - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer); - //glGenerateMipmap(GL_TEXTURE_2D); - - } else { - + if(!textureBuffer) { std::cout << "[Warning] Texture " << texturePath << " not found!" << std::endl; - + return; } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer); + //glGenerateMipmap(GL_TEXTURE_2D); + stbi_image_free(textureBuffer); glBindTexture(GL_TEXTURE_2D, 0); @@ -76,3 +73,72 @@ void Texture::bind(uint8_t textureUnit, ShaderProgram* shaderProgram, uint8_t te void Texture::unbind() { glBindTexture(GL_TEXTURE_2D, 0); } + + + +CubeMap::CubeMap(const char* texturePseudoPath) { + + // Reserve space in vector so that elements can be accessed explicitly. + texturePaths.resize(CUBEMAP_FACES_NUM_ITEMS); + fillTexturePathVector(texturePseudoPath); + + stbi_set_flip_vertically_on_load(0); + + glGenTextures(1, &textureId); + glBindTexture(GL_TEXTURE_CUBE_MAP, 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); + + for(unsigned int i = 0; i < CUBEMAP_FACES_NUM_ITEMS; i++) { + + auto *textureBuffer = stbi_load(texturePaths[i].c_str(), &textureWidth, &textureHeight, &bitsPerPixel, STBI_rgb_alpha); + + if(!textureBuffer) { + std::cout << "[Warning] CubeMap Texture " << texturePaths[i].c_str() << " not found!" << std::endl; + return; + } + + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA8, textureWidth, textureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureBuffer); + + stbi_image_free(textureBuffer); + + } + + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); + +} + +CubeMap::~CubeMap() { + glDeleteTextures(1, &textureId); +} + +void CubeMap::bind(ShaderProgram *shaderProgram) { + std::string uniformName = "u_skybox"; + + shaderProgram->setUniform(uniformName.c_str(), 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, textureId); +} + +void CubeMap::unbind() { + glBindTexture(GL_TEXTURE_CUBE_MAP, 0); +} + +void CubeMap::fillTexturePathVector(const char* texturePseudoPath) { + + for(unsigned int i = 0; i < CUBEMAP_FACES_NUM_ITEMS; i++) { + + texturePaths[cm_front] = std::string(texturePseudoPath) + "front.png"; + texturePaths[cm_back] = std::string(texturePseudoPath) + "back.png"; + texturePaths[cm_top] = std::string(texturePseudoPath) + "top.png"; + texturePaths[cm_bottom] = std::string(texturePseudoPath) + "bottom.png"; + texturePaths[cm_left] = std::string(texturePseudoPath) + "left.png"; + texturePaths[cm_right] = std::string(texturePseudoPath) + "right.png"; + + } + +} diff --git a/src/Texture.h b/src/Texture.h index b370811..6e78f55 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -3,9 +3,14 @@ #include "ShaderProgram.h" #include "defines.h" + #include #include #include +#include + +// Order is important! +enum cubeMapFaces{cm_right, cm_left, cm_top, cm_bottom, cm_back, cm_front, CUBEMAP_FACES_NUM_ITEMS}; class Texture { @@ -32,4 +37,28 @@ private: uint8_t textureType; +}; + +class CubeMap { + +public: + + CubeMap(const char* texturePseudoPath); + ~CubeMap(); + + void bind(ShaderProgram *shaderProgram); + void unbind(); + +private: + + void fillTexturePathVector(const char* texturePseudoPath); + + std::vector texturePaths; + + GLuint textureId; + + int32_t textureWidth; + int32_t textureHeight; + int32_t bitsPerPixel; + }; \ No newline at end of file diff --git a/src/Window.cpp b/src/Window.cpp index 0211f06..feef9d1 100644 --- a/src/Window.cpp +++ b/src/Window.cpp @@ -9,7 +9,7 @@ Window::Window() { width = INIT_WINDOW_WIDTH; height = INIT_WINDOW_HEIGHT; - window = glfwCreateWindow(width, height, "Fall-Fever", NULL, NULL); + window = glfwCreateWindow(width, height, "OpenGL", NULL, NULL); if(!window) { std::cout << "Failed to create window" << std::endl; }