diff --git a/GameObject.h b/GameObject.h new file mode 100644 index 0000000..7740030 --- /dev/null +++ b/GameObject.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +#include +#include +#include + +class GameObject +{ +public: + glm::vec3 Position; + + glm::vec3 Rotation; + + glm::vec3 Scale; + + GameObject(glm::vec3 Position, glm::vec3 Rotation, glm::vec3 Scale) + : Input(nullptr), + Graphics(nullptr), + Physics(nullptr), + Position(Position), + Rotation(Rotation), + Scale(Scale), + Front(0.0f, 0.0f, 1.0f), + Up(0.0f, 1.0f, 0.0f), + Right(1.0f, 0.0f, 0.0f), + WorldUp(0.0f, 1.0f, 0.0f) + { + } + + GameObject(InputComponent* Input, GraphicsComponent* Graphics, PhysicsComponent* Physics) + : Input(Input), + Graphics(Graphics), + Physics(Physics), + Position(0.0f, 0.0f, 0.0f), + Rotation(0.0f, 0.0f, 0.0f), + Scale(1.0f, 1.0f, 1.0f), + Front(0.0f, 0.0f, 1.0f), + Up(0.0f, 1.0f, 0.0f), + Right(1.0f, 0.0f, 0.0f), + WorldUp(0.0f, 1.0f, 0.0f) + {} + + void Update() + { + Input->Update(); + Graphics->Update(); + Physics->Update(); + } + +protected: + InputComponent* Input; + GraphicsComponent* Graphics; + PhysicsComponent* Physics; + + glm::vec3 Front; + glm::vec3 Up; + glm::vec3 Right; + glm::vec3 WorldUp; +}; \ No newline at end of file diff --git a/GraphicsComponent.h b/GraphicsComponent.h new file mode 100644 index 0000000..0ed2060 --- /dev/null +++ b/GraphicsComponent.h @@ -0,0 +1,8 @@ +#pragma once + +class GraphicsComponent +{ +public: + virtual ~GraphicsComponent() {}; + virtual void Update() = 0; +}; \ No newline at end of file diff --git a/InputComponent.h b/InputComponent.h new file mode 100644 index 0000000..94d061b --- /dev/null +++ b/InputComponent.h @@ -0,0 +1,8 @@ +#pragma once + +class InputComponent +{ +public: + virtual ~InputComponent() {}; + virtual void Update() = 0; +}; \ No newline at end of file diff --git a/LearningOpenGL.vcxproj b/LearningOpenGL.vcxproj index ac4c1ad..6f73b5e 100644 --- a/LearningOpenGL.vcxproj +++ b/LearningOpenGL.vcxproj @@ -134,7 +134,20 @@ + + + + + + + + + + + + + @@ -142,13 +155,36 @@ + + + + + + + - + - + + + + + + + + + + + + + + + + + diff --git a/LearningOpenGL.vcxproj.filters b/LearningOpenGL.vcxproj.filters index 8612da1..cd57acc 100644 --- a/LearningOpenGL.vcxproj.filters +++ b/LearningOpenGL.vcxproj.filters @@ -21,6 +21,45 @@ Source Files + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + @@ -29,19 +68,66 @@ + + + + + + + - - Header Files - Header Files - + Header Files Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + \ No newline at end of file diff --git a/LevelMap.cpp b/LevelMap.cpp new file mode 100644 index 0000000..f5b3b41 --- /dev/null +++ b/LevelMap.cpp @@ -0,0 +1,275 @@ +#include "LevelMap.h" + +#include + +LevelMap::LevelMap() +{ + +} + +LevelMap::~LevelMap() +{ + +} + +void LevelMap::Compile(std::string level_map_code) +{ + std::stringstream level_map_stream(level_map_code); + std::string line; + + bool in_sector = false, in_wall = false; + + unsigned int sector_index = 0; + unsigned int wall_index = 0; + + while (std::getline(level_map_stream, line)) + { + if (line.empty() || line[0] == '#') continue; + + if (line.find("[SECTOR]") != std::string::npos) + { + in_sector = true; + in_wall = false; + continue; + } + + if (line.find("[WALL]") != std::string::npos) + { + in_sector = false; + in_wall = true; + continue; + } + + if (in_sector) + { + Sector sector = ParseSector(line); + sectors.push_back(sector); + } + + if (in_wall && !sectors.empty()) + { + Wall wall = ParseWall(line); + + if (wall_index >= sectors[sector_index].number_of_walls) + { + sector_index++; + wall_index = 0; + } + + sectors[sector_index].walls.push_back(wall); + + wall_index++; + } + } + + wall_index = 0; + unsigned int floor_index = 0; + unsigned int ceiling_index = 0; + for (Sector& sector : sectors) + { + std::vector floor_vertices; + std::vector ceiling_vertices; + + for (Wall& wall : sector.walls) + { + glm::vec3 floor_vertex(wall.a.x, sector.floor_height, wall.a.y); + glm::vec3 ceiling_vertex(wall.a.x, sector.ceiling_height, wall.a.y); + + floor_vertices.push_back(floor_vertex); + ceiling_vertices.push_back(ceiling_vertex); + + AddWall(sector, wall, wall_index); + } + + AddFloor(sector, floor_vertices); + AddCeiling(sector, ceiling_vertices); + //AddFloorOrCeiling(sector, floor_vertices, true); + //AddFloorOrCeiling(sector, ceiling_vertices, false); + } +} + +void LevelMap::RenderSetup +( + Shader *wall_shader, + Shader *floor_shader, + Shader *ceiling_shader +) +{ + wall_renderer.Setup(wall_vertices, wall_normals, wall_colors, wall_indices, wall_shader); + floor_renderer.Setup(floor_vertices, floor_normals, floor_colors, floor_indices, floor_shader); + ceiling_renderer.Setup(ceiling_vertices, ceiling_normals, ceiling_colors, ceiling_indices, ceiling_shader); +} + +void LevelMap::Update(glm::mat4 projection, glm::mat4 view, glm::vec3 light_position, glm::vec3 light_color, glm::vec3 view_position) +{ + wall_renderer.Render(projection, view, light_position, light_color, view_position); + floor_renderer.Render(projection, view, light_position, light_color, view_position); + ceiling_renderer.Render(projection, view, light_position, light_color, view_position); +} + +std::vector LevelMap::GetMeshes() +{ + return { &wall_renderer, &floor_renderer, &ceiling_renderer }; +} + +Sector LevelMap::ParseSector(std::string& line) +{ + Sector sector; + std::stringstream ss(line); + ss >> sector.index >> sector.number_of_walls >> sector.floor_height >> sector.ceiling_height >> sector.outward_facing >> sector.color.x >> sector.color.y >> sector.color.z; + + /*static std::random_device rd; // Obtain a random number from hardware + static std::mt19937 eng(rd()); // Seed the generator + std::uniform_real_distribution distr(0.0f, 1.0f); // Define the range + + glm::vec3 randomColor(distr(eng), distr(eng), distr(eng));*/ + + //sector.color = glm::vec3(sector.index+1 / 5.0f, 0.0f, sector.index+1 / 7.0f); + + return sector; +} + +Wall LevelMap::ParseWall(std::string& line) +{ + Wall wall; + std::stringstream ss(line); + ss >> wall.a.x >> wall.a.y >> wall.b.x >> wall.b.y >> wall.portal; + return wall; +} + +void LevelMap::AddWall(Sector& sector, Wall& wall, unsigned int& wall_index) +{ + glm::vec3 v0(wall.a.x, sector.floor_height, wall.a.y); + glm::vec3 v1(wall.a.x, sector.ceiling_height, wall.a.y); + glm::vec3 v2(wall.b.x, sector.ceiling_height, wall.b.y); + glm::vec3 v3(wall.b.x, sector.floor_height, wall.b.y); + + glm::vec3 normal = glm::normalize(glm::cross(v1 - v0, v3 - v1)); + normal = sector.outward_facing ? -normal : normal; + + if (sector.outward_facing) + { + std::swap(v0, v3); + std::swap(v1, v2); + } + + if (wall.portal == 0) + { + AddVertices({ v0, v1, v2, v3 }, wall_vertices); + AddNormals({ normal, normal, normal, normal }, wall_normals); + AddColors({ sector.color, sector.color, sector.color, sector.color }, wall_colors); + AddIndices({ wall_index, wall_index + 1, wall_index + 2, wall_index, wall_index + 2, wall_index + 3 }, wall_indices); + wall_index += 4; + } + else + { + Sector& portal_sector = sectors[wall.portal - 1]; + + if (portal_sector.floor_height > sector.floor_height) + { + v1.y = portal_sector.floor_height; + v2.y = portal_sector.floor_height; + + AddVertices({ v0, v1, v2, v3 }, wall_vertices); + AddNormals({ normal, normal, normal, normal }, wall_normals); + AddColors({ sector.color, sector.color, sector.color, sector.color }, wall_colors); + AddIndices({ wall_index, wall_index + 1, wall_index + 2, wall_index, wall_index + 2, wall_index + 3 }, wall_indices); + wall_index += 4; + } + + if (portal_sector.ceiling_height < sector.ceiling_height) + { + v0.y = portal_sector.ceiling_height; + v1.y = sector.ceiling_height; + v2.y = sector.ceiling_height; + v3.y = portal_sector.ceiling_height;; + + AddVertices({ v0, v1, v2, v3 }, wall_vertices); + AddNormals({ normal, normal, normal, normal }, wall_normals); + AddColors({ sector.color, sector.color, sector.color, sector.color }, wall_colors); + AddIndices({ wall_index, wall_index + 1, wall_index + 2, wall_index, wall_index + 2, wall_index + 3 }, wall_indices); + wall_index += 4; + } + } +} + +void LevelMap::AddFloor(Sector& sector, std::vector vertices) +{ + unsigned int starting_index = sector.index; + unsigned int _index = starting_index + 1; + glm::vec3 normal = glm::vec3(0.0f, 1.0f, 0.0f); + + for (int i = vertices.size() - 1; i >= 0; i--) + { + AddVertices({ vertices[i] }, floor_vertices); + AddNormals({ normal }, floor_normals); + AddColors({ glm::vec3(1.0f) - sector.color }, floor_colors); + if (_index + 1 < sector.index + sector.number_of_walls) + { + unsigned int next_index = _index + 1; + AddIndices({ starting_index, _index, next_index }, floor_indices); + _index++; + } + } +} + +void LevelMap::AddCeiling(Sector& sector, std::vector vertices) +{ + unsigned int starting_index = sector.index; + unsigned int _index = starting_index + 1; + glm::vec3 normal = glm::vec3(0.0f, 1.0f, 0.0f); + normal = -normal; + + for (int i = 0; i < vertices.size(); i++) + { + AddVertices({ vertices[i] }, ceiling_vertices); + AddNormals({ normal }, ceiling_normals); + AddColors({ glm::vec3(1.0f) - sector.color }, ceiling_colors); + if ( _index + 1 < sector.index + sector.number_of_walls) + { + unsigned int next_index = _index + 1; + AddIndices({ starting_index, _index, next_index }, ceiling_indices); + _index++; + } + } +} + +void LevelMap::AddVertices(std::vector vertices, std::vector& target_vertices) +{ + for (unsigned int i = 0; i < vertices.size(); i += 1) + { + target_vertices.push_back(vertices[i].x); + target_vertices.push_back(vertices[i].y); + target_vertices.push_back(vertices[i].z); + } +} + +void LevelMap::AddNormals(std::vector normals, std::vector& target_normals) +{ + for (unsigned int i = 0; i < normals.size(); i += 1) + { + target_normals.push_back(normals[i].x); + target_normals.push_back(normals[i].y); + target_normals.push_back(normals[i].z); + } +} + +void LevelMap::AddColors(std::vector colors, std::vector& target_colors) +{ + for (unsigned int i = 0; i < colors.size(); i += 1) + { + target_colors.push_back(colors[i].x); + target_colors.push_back(colors[i].y); + target_colors.push_back(colors[i].z); + } +} + +void LevelMap::AddIndices(std::vector indices, std::vector& target_indices) +{ + for (unsigned int i = 0; i < indices.size(); i += 1) + { + target_indices.push_back(indices[i]); + } +} + + diff --git a/LevelMap.h b/LevelMap.h new file mode 100644 index 0000000..71325c0 --- /dev/null +++ b/LevelMap.h @@ -0,0 +1,94 @@ +#pragma once + +#include +#include +#include + +#include + +#include "MeshRenderer.h" + +struct Wall +{ + glm::vec2 a, b; + int portal; +}; + +struct Sector +{ + unsigned int index; + unsigned int number_of_walls; + + float floor_height; + float ceiling_height; + + bool outward_facing; + + glm::vec3 color; + + std::vector walls; +}; + +class LevelMap +{ +public: + LevelMap(); + ~LevelMap(); + + void Compile(std::string level_map_code); + + void RenderSetup + ( + Shader *wall_shader, + Shader *floor_shader, + Shader *ceiling_shader + ); + + void Update + ( + glm::mat4 projection, + glm::mat4 view, + glm::vec3 light_position, + glm::vec3 light_color, + glm::vec3 view_position + ); + + std::vector GetMeshes(); +private: + std::vector sectors; + + std::vector wall_vertices; + std::vector wall_normals; + std::vector wall_colors; + std::vector wall_indices; + MeshRenderer wall_renderer; + Shader wall_shader; + + std::vector floor_vertices; + std::vector floor_normals; + std::vector floor_colors; + std::vector floor_indices; + MeshRenderer floor_renderer; + Shader floor_shader; + + std::vector ceiling_vertices; + std::vector ceiling_normals; + std::vector ceiling_colors; + std::vector ceiling_indices; + MeshRenderer ceiling_renderer; + Shader ceiling_shader; + + Sector ParseSector(std::string& line); + Wall ParseWall(std::string& line); + + void AddWall(Sector& sector, Wall& wall, unsigned int& wall_index); + + void AddFloor(Sector& sector, std::vector vertices); + void AddCeiling(Sector& sector, std::vector vertices); + + void AddVertices(std::vector vertices, std::vector& target_vertices); + void AddNormals(std::vector normals, std::vector& target_normals); + void AddColors(std::vector colors, std::vector& target_colors); + void AddIndices(std::vector indices, std::vector& target_indices); +}; + diff --git a/Light.cpp b/Light.cpp new file mode 100644 index 0000000..5c44cc5 --- /dev/null +++ b/Light.cpp @@ -0,0 +1 @@ +#include "Light.h" diff --git a/Light.h b/Light.h new file mode 100644 index 0000000..e69de29 diff --git a/MeshRenderer.cpp b/MeshRenderer.cpp new file mode 100644 index 0000000..33128bf --- /dev/null +++ b/MeshRenderer.cpp @@ -0,0 +1,240 @@ +#include + +#include + +// when creating a meshrenderer the important question is "do all these vertices share the same shader?" + +MeshRenderer::MeshRenderer() +{ +} + +MeshRenderer::~MeshRenderer() +{ + glDeleteVertexArrays(1, &this->VAO); +} + +void MeshRenderer::Setup +( + std::vector vertices, + std::vector normals, + std::vector colors, + std::vector indices, + Shader* lit_shader +) +{ + this->vertices = vertices; + this->normals = normals; + this->colors = colors; + this->indices = indices; + this->lit_shader = lit_shader; + this->shadow_shader = shadow_shader; + + this->SetupBuffers(); + + //if (shadow_shader != nullptr) + //{ + // //std::cout << "Setup lighting" << std::endl; + // this->SetupLighting(); + //} + +} + +void MeshRenderer::Render(Shader &shader) +{ + //std::cout << "Rendering with Shader: " << shader.ID << std::endl; + shader.Use(); + glm::mat4 model = glm::mat4(1.0f); + shader.SetMatrix4("model", model); + + glBindVertexArray(this->VAO); + + //std::cout << this->indices.size() << std::endl; + glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); +} + +void MeshRenderer::Render +( + glm::mat4 projection, + glm::mat4 view, + glm::vec3 light_position, + glm::vec3 light_color, + glm::vec3 view_position +) +{ + glm::mat4 model = glm::mat4(1.0f); + + //glEnable(GL_CULL_FACE); + //glCullFace(GL_BACK); + + //if (shadow_shader != nullptr) + //{ + // this->shader = shadow_shader; + // RenderShadows(projection, view, model, light_position); + //} + + this->shader = lit_shader; + RenderObject(projection, view, model, light_position, light_color, view_position); +} + +void MeshRenderer::Render +( + glm::mat4 projection, + glm::mat4 view, + glm::vec3 light_position, + glm::vec3 light_color, + glm::vec3 view_position, + glm::vec3 position, + glm::vec3 scale, + glm::vec3 rotation +) +{ + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, position); + model = glm::rotate(model, glm::radians(rotation.x), glm::vec3(1, 0, 0)); + model = glm::rotate(model, glm::radians(rotation.y), glm::vec3(0, 1, 0)); + model = glm::rotate(model, glm::radians(rotation.z), glm::vec3(0, 0, 1)); + model = glm::scale(model, scale); + + if (shadow_shader != nullptr) + { + this->lit_shader = shadow_shader; + RenderShadows(projection, view, model, light_position); + } + this->shader = lit_shader; + + RenderObject(projection, view, model, light_position, light_color, view_position); +} + +void MeshRenderer::SetupBuffers() +{ + /*for (int i = 0; i < this->normals.size(); i += 3) + { + std::cout << this->normals[i] << " " << this->normals[i + 1] << " " << this->normals[i + 2] << std::endl; + }*/ + glGenVertexArrays(1, &this->VAO); + + unsigned int VBO, NBO, CBO, EBO; + + glGenBuffers(1, &VBO); + glGenBuffers(1, &NBO); + glGenBuffers(1, &CBO); + glGenBuffers(1, &EBO); + + glBindVertexArray(this->VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, this->vertices.size() * sizeof(float), this->vertices.data(), GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, NBO); + glBufferData(GL_ARRAY_BUFFER, this->normals.size() * sizeof(float), this->normals.data(), GL_STATIC_DRAW); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + + glBindBuffer(GL_ARRAY_BUFFER, CBO); + glBufferData(GL_ARRAY_BUFFER, this->colors.size() * sizeof(float), this->colors.data(), GL_STATIC_DRAW); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(2); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->indices.size() * sizeof(unsigned int), this->indices.data(), GL_STATIC_DRAW); + + glBindVertexArray(0); +} + +void MeshRenderer::SetupLighting() +{ + /*glGenFramebuffers(1, &depth_map_FBO); + glGenTextures(1, &depth_map); + + for (unsigned int i = 0; i < 6; i++) + { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + 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); + + glBindFramebuffer(GL_FRAMEBUFFER, depth_map_FBO); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_map, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0);*/ +} + +void MeshRenderer::RenderObject +( + glm::mat4 projection, + glm::mat4 view, + glm::mat4 model, + glm::vec3 light_position, + glm::vec3 light_color, + glm::vec3 view_position +) +{ + this->shader->Use(); + this->shader->SetMatrix4("projection", projection); + this->shader->SetMatrix4("view", view); + this->shader->SetMatrix4("model", model); + this->shader->SetVector3f("lightPos", light_position); + this->shader->SetVector3f("lightColor", light_color); + this->shader->SetVector3f("viewPos", view_position); + this->shader->SetFloat("far_plane", 25.0f); + + glBindVertexArray(this->VAO); + + glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); +} + +void MeshRenderer::RenderShadows(glm::mat4 projection, glm::mat4 view, glm::mat4 model, glm::vec3 light_position) +{ + this->shader->Use(); + this->shader->SetMatrix4("projection", projection); + this->shader->SetMatrix4("view", view); + this->shader->SetMatrix4("model", model); + float near_plane = 1.0f; + float far_plane = 50.0f; + + glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)SHADOW_WIDTH / (float)SHADOW_HEIGHT, near_plane, far_plane); + std::vector shadowTransforms; + shadowTransforms.push_back(shadowProj * glm::lookAt(light_position, light_position + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(light_position, light_position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(light_position, light_position + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(light_position, light_position + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(light_position, light_position + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(light_position, light_position + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f))); + + glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); + glBindFramebuffer(GL_FRAMEBUFFER, depth_map_FBO); + //glClear(GL_DEPTH_BUFFER_BIT); + + for (unsigned int i = 0; i < 6; ++i) + { + std::string matrix_name = "shadowMatrices[" + std::to_string(i) + "]"; + this->shader->SetMatrix4(matrix_name.c_str(), shadowTransforms[i]); + } + this->shader->SetFloat("far_plane", far_plane); + this->shader->SetVector3f("lightPos", light_position); + + glBindVertexArray(this->VAO); + + glDrawElements(GL_TRIANGLES, this->indices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBindTexture(GL_TEXTURE_CUBE_MAP, depth_map); +} + + diff --git a/MeshRenderer.h b/MeshRenderer.h new file mode 100644 index 0000000..9fb1efc --- /dev/null +++ b/MeshRenderer.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include +#include +#include +#include +#include + +#include "Shader.h" + +class MeshRenderer +{ +public: + MeshRenderer(); + ~MeshRenderer(); + + void Setup + ( + std::vector vertices, + std::vector normals, + std::vector colors, + std::vector indices, + Shader* lit_shader + ); + + void Render(Shader &shader); + + void Render(glm::mat4 projection, glm::mat4 view, glm::vec3 light_position, glm::vec3 light_color, glm::vec3 view_position); + void Render(glm::mat4 projection, glm::mat4 view, glm::vec3 light_position, glm::vec3 light_color, glm::vec3 view_position, glm::vec3 position, glm::vec3 scale, glm::vec3 rotation); +private: + std::vector vertices; + std::vector normals; + std::vector colors; + std::vector indices; + + unsigned int VAO; + unsigned int depth_map; + unsigned int depth_map_FBO; + + unsigned int SHADOW_WIDTH = 1024, SHADOW_HEIGHT = 1024; + int SCR_WIDTH = 1600; + int SCR_HEIGHT = 900; + + Shader *shader; + Shader *lit_shader; + Shader *shadow_shader; + + void SetupBuffers(); + void SetupLighting(); + + void RenderObject(glm::mat4 projection, glm::mat4 view, glm::mat4 model, glm::vec3 light_position, glm::vec3 light_color, glm::vec3 view_position); + void RenderShadows(glm::mat4 projection, glm::mat4 view, glm::mat4 model, glm::vec3 light_position); +}; + diff --git a/PhysicsComponent.h b/PhysicsComponent.h new file mode 100644 index 0000000..2f5e1d0 --- /dev/null +++ b/PhysicsComponent.h @@ -0,0 +1,8 @@ +#pragma once + +class PhysicsComponent +{ +public: + virtual ~PhysicsComponent() {}; + virtual void Update() = 0; +}; \ No newline at end of file diff --git a/Player.cpp b/Player.cpp new file mode 100644 index 0000000..cefae8f --- /dev/null +++ b/Player.cpp @@ -0,0 +1,64 @@ +#include "Player.h" +#include "Camera.h" +#include + +Player::Player(glm::vec3 Position, glm::vec3 Rotation) + : GameObject(Position, Rotation, glm::vec3(1.0f, 1.0f, 1.0f)), + PlayerCamera(new Camera(glm::vec3(0.0f, 1.0f, 0.0f))) +{ + + PlayerCamera->Position = Position + PlayerCamera->CameraOffset; + PlayerCamera->WorldUp = this->WorldUp; + std::cout << "{" << Position.x << ", " << Position.y << ", " << Position.z << "}" << std::endl; + std::cout << "{" << PlayerCamera->Position.x << ", " << PlayerCamera->Position.y << ", " << PlayerCamera->Position.z << "}" << std::endl; +} + +void Player::Update() +{ + +} + +void Player::ProcessKeyboard(EInputDirection Direction, float Delta) +{ + float Velocity = bIsRunning ? RunSpeed : WalkSpeed; + Velocity = Velocity * Delta; + if (Direction == FORWARD) + Position += Front * Velocity; + if (Direction == BACKWARD) + Position -= Front * Velocity; + if (Direction == LEFT) + Position -= Right * Velocity; + if (Direction == RIGHT) + Position += Right * Velocity; + + PlayerCamera->Position = Position + PlayerCamera->CameraOffset; + PlayerCamera->WorldUp = this->WorldUp; +} + +void Player::ProcessMouseMovement(float XOffset, float YOffset, GLboolean bConstrainPitch) +{ + XOffset *= MOUSE_SENSITIVITY; + YOffset *= MOUSE_SENSITIVITY; + + Yaw += XOffset; + PlayerCamera->Yaw = Yaw; + + PlayerCamera->ProcessMouseMovement(XOffset, YOffset); + UpdatePlayerVectors(); +} + +glm::mat4 Player::GetViewMatrix() const +{ + return PlayerCamera->GetViewMatrix(); +} + +void Player::UpdatePlayerVectors() +{ + glm::vec3 UpdatedFront; + UpdatedFront.x = cos(glm::radians(Yaw)) * cos(0); + UpdatedFront.y = sin(0); + UpdatedFront.z = sin(glm::radians(Yaw)) * cos(0); + Front = glm::normalize(UpdatedFront); + Right = glm::normalize(glm::cross(Front, WorldUp)); + Up = glm::normalize(glm::cross(Right, Front)); +} \ No newline at end of file diff --git a/Player.h b/Player.h new file mode 100644 index 0000000..9db3491 --- /dev/null +++ b/Player.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include + + +enum EInputDirection +{ + FORWARD, + BACKWARD, + LEFT, + RIGHT +}; + +class Player : public GameObject +{ +public: + Player(glm::vec3 Position, glm::vec3 Rotation); + ~Player() = default; + + void Update(); + + void ProcessKeyboard(EInputDirection Direction, float Delta); + void ProcessMouseMovement(float XOffset, float YOffset, GLboolean ConstrainPitch = true); + glm::mat4 GetViewMatrix() const; + +private: + Camera* PlayerCamera; + float Yaw; + float MouseSensitivity; + + float WalkSpeed = 5.0f; + float RunSpeed = 15.0f; + + bool bIsRunning = false; + + void UpdatePlayerVectors(); + +}; + diff --git a/PlayerInputComponent.h b/PlayerInputComponent.h new file mode 100644 index 0000000..59e79bd --- /dev/null +++ b/PlayerInputComponent.h @@ -0,0 +1,22 @@ +#pragma once + +#include + +enum EInputDirection +{ + FORWARD, + BACKWARD, + LEFT, + RIGHT +}; + +class PlayerInputComponent : public InputComponent +{ +private: + +public: + virtual void Update(float deltaTime) + { + + } +}; \ No newline at end of file diff --git a/PointLight.cpp b/PointLight.cpp new file mode 100644 index 0000000..b0b040b --- /dev/null +++ b/PointLight.cpp @@ -0,0 +1 @@ +#include "PointLight.h" diff --git a/PointLight.h b/PointLight.h new file mode 100644 index 0000000..90a15e3 --- /dev/null +++ b/PointLight.h @@ -0,0 +1,115 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include + +#include "Shader.h" +#include "MeshRenderer.h" + +#define SHADOW_WIDTH 1024 +#define SHADOW_HEIGHT 1024 + +class PointLight +{ +public: + unsigned int depth_map, depth_map_FBO; + float near_plane = 1.0f, + far_plane = 100.0f, + ambient_intensity = 0.5f, + diffuse_intensity = 1.0f, + attenuation_constant = 1.0f, + attenuation_linear = 0.09f, + attenuation_exponential = 0.032f; + glm::vec3 Position; + glm::vec3 color; + Shader shader; + + PointLight(glm::vec3 position, glm::vec3 color, Shader shader) + { + this->Position = position; + this->color = color; + this->shader = shader; + SetupLighting(); + } + + void RenderSceneShadows(std::vector meshes) + { + glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)SHADOW_WIDTH / (float)SHADOW_HEIGHT, near_plane, far_plane); + std::vector shadowTransforms; + shadowTransforms.push_back(shadowProj * glm::lookAt(Position, Position + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f))); // Right + shadowTransforms.push_back(shadowProj * glm::lookAt(Position, Position + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f))); // Left + shadowTransforms.push_back(shadowProj * glm::lookAt(Position, Position + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f))); // Up + shadowTransforms.push_back(shadowProj * glm::lookAt(Position, Position + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f))); // Down + shadowTransforms.push_back(shadowProj * glm::lookAt(Position, Position + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f))); // Forward + shadowTransforms.push_back(shadowProj * glm::lookAt(Position, Position + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f))); // Backward + + glEnable(GL_CULL_FACE); + + glCullFace(GL_FRONT); + + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); + glBindFramebuffer(GL_FRAMEBUFFER, depth_map_FBO); + glClear(GL_DEPTH_BUFFER_BIT); + shader.Use(); + for (unsigned int i = 0; i < 6; ++i) + { + std::string matrix_name = "shadowMatrices[" + std::to_string(i) + "]"; + shader.SetMatrix4(matrix_name.c_str(), shadowTransforms[i]); + } + shader.SetFloat("farPlane", far_plane); + shader.SetVector3f("lightPosition", Position); + + for (MeshRenderer* mesh : meshes) + { + mesh->Render(shader); + } + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + std::cout << "Framebuffer not complete!" << std::endl; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glCullFace(GL_BACK); + + } +private: + + void SetupLighting() + { + //std::cout << "SetupLighting" << std::endl; + glGenFramebuffers(1, &depth_map_FBO); + glGenTextures(1, &depth_map); + glBindTexture(GL_TEXTURE_CUBE_MAP, depth_map); + + for (unsigned int i = 0; i < 6; i++) + { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + 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); + + glBindFramebuffer(GL_FRAMEBUFFER, depth_map_FBO); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depth_map, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + { + std::cout << "Framebuffer not complete!" << std::endl; + } + glBindFramebuffer(GL_FRAMEBUFFER, 0); + } +}; + diff --git a/ResourceManager.cpp b/ResourceManager.cpp new file mode 100644 index 0000000..22488ce --- /dev/null +++ b/ResourceManager.cpp @@ -0,0 +1,102 @@ +#include "ResourceManager.h" + +#include +#include +#include +#include + +// Instantiate static variables +std::map ResourceManager::shaders; +std::map ResourceManager::levelMaps; + + +Shader ResourceManager::LoadShader(const char* vShaderFile, const char* fShaderFile, const char* gShaderFile, std::string name) +{ + shaders[name] = LoadShaderFromFile(vShaderFile, fShaderFile, gShaderFile); + return shaders[name]; +} + +Shader ResourceManager::GetShader(std::string name) +{ + return shaders[name]; +} + +void ResourceManager::Clear() +{ + // (properly) delete all shaders + for (auto iter : shaders) + glDeleteProgram(iter.second.ID); +} + +Shader ResourceManager::LoadShaderFromFile(const char* vShaderFile, const char* fShaderFile, const char* gShaderFile) +{ + // 1. retrieve the vertex/fragment source code from filePath + std::string vertexCode; + std::string fragmentCode; + std::string geometryCode; + try + { + // open files + std::ifstream vertexShaderFile(vShaderFile); + std::ifstream fragmentShaderFile(fShaderFile); + std::stringstream vShaderStream, fShaderStream; + // read file's buffer contents into streams + vShaderStream << vertexShaderFile.rdbuf(); + fShaderStream << fragmentShaderFile.rdbuf(); + // close file handlers + vertexShaderFile.close(); + fragmentShaderFile.close(); + // convert stream into string + vertexCode = vShaderStream.str(); + fragmentCode = fShaderStream.str(); + // if geometry shader path is present, also load a geometry shader + if (gShaderFile != nullptr) + { + std::ifstream geometryShaderFile(gShaderFile); + std::stringstream gShaderStream; + gShaderStream << geometryShaderFile.rdbuf(); + geometryShaderFile.close(); + geometryCode = gShaderStream.str(); + } + } + catch (std::exception e) + { + std::cout << "ERROR::SHADER: Failed to read shader files" << std::endl; + } + const char* vShaderCode = vertexCode.c_str(); + const char* fShaderCode = fragmentCode.c_str(); + const char* gShaderCode = geometryCode.c_str(); + // 2. now create shader object from source code + Shader shader; + shader.Compile(vShaderCode, fShaderCode, gShaderFile != nullptr ? gShaderCode : nullptr); + return shader; +} + +LevelMap ResourceManager::LoadLevelMap(const char* filePath, std::string name) +{ + levelMaps[name] = LoadLevelMapFromFile(filePath); + return levelMaps[name]; +} + +LevelMap ResourceManager::LoadLevelMapFromFile(const char* filePath) +{ + std::string level_map_code; + try + { + std::ifstream level_map_file(filePath); + std::stringstream level_map_stream; + + level_map_stream << level_map_file.rdbuf(); + + level_map_file.close(); + + level_map_code = level_map_stream.str(); + } + catch (std::exception e) + { + std::cout << "ERROR::LEVELMAP: Failed to read level map file: " << filePath << std::endl; + } + LevelMap level_map; + level_map.Compile(level_map_code); + return level_map; +} diff --git a/ResourceManager.h b/ResourceManager.h new file mode 100644 index 0000000..e1c2e49 --- /dev/null +++ b/ResourceManager.h @@ -0,0 +1,33 @@ +#pragma once + +#include +#include + +#include + +#include "Shader.h" +#include "LevelMap.h" + +class ResourceManager +{ +public: + // resource storage + static std::map shaders; + static std::map levelMaps; + // loads (and generates) a shader program from file loading vertex, fragment (and geometry) shader's source code. If gShaderFile is not nullptr, it also loads a geometry shader + static Shader LoadShader(const char* vShaderFile, const char* fShaderFile, const char* gShaderFile, std::string name); + // retrieves a stored sader + static Shader GetShader(std::string name); + // properly de-allocates all loaded resources + static void Clear(); + + static LevelMap LoadLevelMap(const char* filePath, std::string name); +private: + // private constructor, that is we do not want any actual resource manager objects. Its members and functions should be publicly available (static). + ResourceManager() { } + // loads and generates a shader from file + static Shader LoadShaderFromFile(const char* vShaderFile, const char* fShaderFile, const char* gShaderFile = nullptr); + + static LevelMap LoadLevelMapFromFile(const char* filePath); +}; + diff --git a/Shader.cpp b/Shader.cpp new file mode 100644 index 0000000..91c42fb --- /dev/null +++ b/Shader.cpp @@ -0,0 +1,129 @@ +#include "Shader.h" + +#include + +Shader& Shader::Use() +{ + glUseProgram(this->ID); + return *this; +} + +void Shader::Compile(const char* vertexSource, const char* fragmentSource, const char* geometrySource) +{ + unsigned int sVertex, sFragment, gShader; + // vertex Shader + sVertex = glCreateShader(GL_VERTEX_SHADER); + glShaderSource(sVertex, 1, &vertexSource, NULL); + glCompileShader(sVertex); + checkCompileErrors(sVertex, "VERTEX"); + // fragment Shader + sFragment = glCreateShader(GL_FRAGMENT_SHADER); + glShaderSource(sFragment, 1, &fragmentSource, NULL); + glCompileShader(sFragment); + checkCompileErrors(sFragment, "FRAGMENT"); + // if geometry shader source code is given, also compile geometry shader + if (geometrySource != nullptr) + { + gShader = glCreateShader(GL_GEOMETRY_SHADER); + glShaderSource(gShader, 1, &geometrySource, NULL); + glCompileShader(gShader); + checkCompileErrors(gShader, "GEOMETRY"); + } + // shader program + this->ID = glCreateProgram(); + glAttachShader(this->ID, sVertex); + glAttachShader(this->ID, sFragment); + if (geometrySource != nullptr) + glAttachShader(this->ID, gShader); + glLinkProgram(this->ID); + checkCompileErrors(this->ID, "PROGRAM"); + // delete the shaders as they're linked into our program now and no longer necessary + glDeleteShader(sVertex); + glDeleteShader(sFragment); + if (geometrySource != nullptr) + glDeleteShader(gShader); +} + +void Shader::SetFloat(const char* name, float value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform1f(glGetUniformLocation(this->ID, name), value); +} +void Shader::SetInteger(const char* name, int value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform1i(glGetUniformLocation(this->ID, name), value); +} +void Shader::SetVector2f(const char* name, float x, float y, bool useShader) +{ + if (useShader) + this->Use(); + glUniform2f(glGetUniformLocation(this->ID, name), x, y); +} +void Shader::SetVector2f(const char* name, const glm::vec2& value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform2f(glGetUniformLocation(this->ID, name), value.x, value.y); +} +void Shader::SetVector3f(const char* name, float x, float y, float z, bool useShader) +{ + if (useShader) + this->Use(); + glUniform3f(glGetUniformLocation(this->ID, name), x, y, z); +} +void Shader::SetVector3f(const char* name, const glm::vec3& value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform3f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z); +} +void Shader::SetVector4f(const char* name, float x, float y, float z, float w, bool useShader) +{ + if (useShader) + this->Use(); + glUniform4f(glGetUniformLocation(this->ID, name), x, y, z, w); +} +void Shader::SetVector4f(const char* name, const glm::vec4& value, bool useShader) +{ + if (useShader) + this->Use(); + glUniform4f(glGetUniformLocation(this->ID, name), value.x, value.y, value.z, value.w); +} +void Shader::SetMatrix4(const char* name, const glm::mat4& matrix, bool useShader) +{ + if (useShader) + this->Use(); + glUniformMatrix4fv(glGetUniformLocation(this->ID, name), 1, false, glm::value_ptr(matrix)); +} + + +void Shader::checkCompileErrors(unsigned int object, std::string type) +{ + int success; + char infoLog[1024]; + if (type != "PROGRAM") + { + glGetShaderiv(object, GL_COMPILE_STATUS, &success); + if (!success) + { + glGetShaderInfoLog(object, 1024, NULL, infoLog); + std::cout << "| ERROR::SHADER: Compile-time error: Type: " << type << "\n" + << infoLog << "\n -- --------------------------------------------------- -- " + << std::endl; + } + } + else + { + glGetProgramiv(object, GL_LINK_STATUS, &success); + if (!success) + { + glGetProgramInfoLog(object, 1024, NULL, infoLog); + std::cout << "| ERROR::Shader: Link-time error: Type: " << type << "\n" + << infoLog << "\n -- --------------------------------------------------- -- " + << std::endl; + } + } +} \ No newline at end of file diff --git a/camera.h b/camera.h index a1437ba..3299de6 100644 --- a/camera.h +++ b/camera.h @@ -8,16 +8,16 @@ enum Camera_Movement { - FORWARD, - BACKWARD, - LEFT, - RIGHT + _FORWARD, + _BACKWARD, + _LEFT, + _RIGHT }; const float YAW = -90.0f; const float PITCH = 0.0f; -const float SPEED = 2.5f; -const float SENSITIVITY = 0.1f; +const float SPEED = 5.0f; +const float MOUSE_SENSITIVITY = 0.1f; const float ZOOM = 45.0f; class Camera @@ -28,6 +28,7 @@ public: glm::vec3 Up; glm::vec3 Right; glm::vec3 WorldUp; + glm::vec3 CameraOffset; float Yaw; float Pitch; @@ -39,15 +40,17 @@ public: Camera( glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), + glm::vec3 offset = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), - MouseSensitivity(SENSITIVITY), + MouseSensitivity(MOUSE_SENSITIVITY), Zoom(ZOOM) { Position = position; + CameraOffset = offset; WorldUp = up; Yaw = yaw; Pitch = pitch; @@ -62,25 +65,22 @@ public: void ProcessKeyboard(Camera_Movement direction, float deltaTime) { float velocity = MovementSpeed * deltaTime; - if (direction == FORWARD) + if (direction == _FORWARD) Position += Front * velocity; - if (direction == BACKWARD) + if (direction == _BACKWARD) Position -= Front * velocity; - if (direction == LEFT) + if (direction == _LEFT) Position -= Right * velocity; - if (direction == RIGHT) + if (direction == _RIGHT) Position += Right * velocity; } - void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true) + void ProcessMouseMovement(float XOffset, float YOffset, GLboolean bConstrainPitch = true) { - xoffset *= MouseSensitivity; - yoffset *= MouseSensitivity; + //Yaw += XOffset; + Pitch += YOffset; - Yaw += xoffset; - Pitch += yoffset; - - if (constrainPitch) + if (bConstrainPitch) { if (Pitch > 89.0f) Pitch = 89.0f; @@ -100,6 +100,7 @@ public: Zoom = 45.0f; } private: + void updateCameraVectors() { glm::vec3 front; diff --git a/cube.h b/cube.h index 07973dd..708aabc 100644 --- a/cube.h +++ b/cube.h @@ -10,7 +10,7 @@ class Cube { private: - glm::vec3 position; + glm::vec3 Position; glm::vec3 scale; glm::vec3 rotation; glm::vec3 color; @@ -30,7 +30,7 @@ public: Cube(glm::vec3 position, glm::vec3 scale, glm::vec3 rotation, glm::vec3 color) { - this->position = position; + this->Position = position; this->scale = scale; this->rotation = rotation; this->color = color; @@ -48,7 +48,7 @@ public: glm::mat4 getModelMatrix() const { glm::mat4 model = glm::mat4(1.0f); - model = glm::translate(model, position); + model = glm::translate(model, Position); model = glm::rotate(model, glm::radians(rotation.x), glm::vec3(1, 0, 0)); model = glm::rotate(model, glm::radians(rotation.y), glm::vec3(0, 1, 0)); model = glm::rotate(model, glm::radians(rotation.z), glm::vec3(0, 0, 1)); @@ -59,7 +59,7 @@ public: void setPosition(glm::vec3 position) { - this->position = position; + this->Position = position; } void setScale(glm::vec3 scale) @@ -79,7 +79,7 @@ public: glm::vec3 getPosition() const { - return position; + return Position; } glm::vec3 getScale() const diff --git a/cubeFactory.h b/cubeFactory.h index 19401af..143fe81 100644 --- a/cubeFactory.h +++ b/cubeFactory.h @@ -153,6 +153,43 @@ public: } } + void render(glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float deltaTime, int amountOfCubes) + { + shader.use(); + shader.setMat4("projection", projection); + shader.setMat4("view", view); + + int i = 0; + for (Cube& cube : cubes) + { + if (i >= amountOfCubes) + { + break; + } + //std::cout << "Cube position: (" << cube.getColor().x << "," << cube.getColor().y << "," << cube.getColor().z << ")" << std::endl; + cube.setRotation(cube.getRotation() + (glm::vec3(5.0f, 10.0f, 20.0f)) * deltaTime); + glm::mat4 model = cube.getModelMatrix(); + glm::vec3 color = cube.getColor(); + shader.setMat4("model", model); + shader.setVec3("objectColor", color); + shader.setVec3("lightColor", 1.0f, 1.0f, 1.0f); + shader.setVec3("lightPos", lightPos); + + glBindVertexArray(VAO); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawArrays(GL_TRIANGLES, 0, 36); + //glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); + //shader.setVec3("objectColor", 0.0f, 0.0f, 0.0f); + //glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); + //glDrawArrays(GL_TRIANGLES, 0, 36); + //glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + i++; + } + } + + std::list getCubes() { return cubes; diff --git a/imgui.ini b/imgui.ini new file mode 100644 index 0000000..918e4e7 --- /dev/null +++ b/imgui.ini @@ -0,0 +1,12 @@ +[Window][Debug##Default] +Pos=60,60 +Size=400,400 +Collapsed=0 + +[Window][Settings] +Pos=69,71 +Size=445,126 +Collapsed=0 + +[Docking][Data] + diff --git a/input_processor.h b/input_processor.h new file mode 100644 index 0000000..6f70f09 --- /dev/null +++ b/input_processor.h @@ -0,0 +1 @@ +#pragma once diff --git a/main.cpp b/main.cpp index f9fba4a..83dda72 100644 --- a/main.cpp +++ b/main.cpp @@ -7,23 +7,29 @@ #include #include #include +#include +#include #include #include #include -#include -#include +#include "ResourceManager.h" +#include "PointLight.h" void framebuffer_size_callback(GLFWwindow* window, int width, int height); void processInput(GLFWwindow* window); void mouse_callback(GLFWwindow* window, double xpos, double ypos); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); -int SCR_WIDTH = 800; -int SCR_HEIGHT = 800; +int SCR_WIDTH = 1600; +int SCR_HEIGHT = 900; + +//Camera camera(glm::vec3(20.0f, 1.0f, 20.0f)); +glm::vec3 StartingPosition = glm::vec3(20.0f, 0.0f, 20.0f); +glm::vec3 StartingRotation = glm::vec3(0.0f, 0.0f, 0.0f); +Player PlayerCharacter(StartingPosition, StartingRotation); -Camera camera(glm::vec3(0.0f, 0.0f, 20.0f)); float lastX = SCR_WIDTH / 2.0f; float lastY = SCR_HEIGHT / 2.0f; bool firstMouse = true; @@ -32,17 +38,13 @@ float deltaTime = 0.0f; float lastFrame = 0.0f; float elapsedTime = 0.0f; +int amountOfCubes = 1000; + //glm::vec3 lightPos(1.2f, 1.0f, 2.0f); int main() { - IMGUI_CHECKVERSION(); - ImGui::CreateContext(); - ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; - io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - + const char* glsl_version = "#version 330"; std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl; glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); @@ -61,7 +63,7 @@ int main() glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + //glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { std::cout << "Failed to initialize GLAD" << std::endl; @@ -69,41 +71,76 @@ int main() } glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); std::cout << "Loaded GLFW context, OpenGL 3.3" << std::endl; - CubeFactory cubeFactory; + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - float offset = 2.0f; - int xAmount = 10; - int yAmount = 10; - int zAmount = 10; + //ImGui_ImplGlfw_InitForOpenGL(window, true); + //ImGui_ImplOpenGL3_Init(glsl_version); - for (int x = 0; x < xAmount; x++) - { - for (int y = 0; y < yAmount; y++) - { - for (int z = 0; z < zAmount; z++) - { - glm::vec3 position = glm::vec3( (x * offset) - (xAmount * offset / 2.0f), - (y * offset) - (yAmount * offset / 2.0f), - (z * offset) - (zAmount * offset / 2.0f)); - glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f); - glm::vec3 rotation = glm::vec3(0.0f, 0.0f, 0.0f); - glm::vec3 color = glm::vec3(x/10.0f, y/10.0f, z/10.0f); - - cubeFactory.addCube(position, scale, rotation, color); - } - } + if (!ImGui_ImplGlfw_InitForOpenGL(window, true)) { + std::cout << "Failed to initialize ImGui GLFW backend" << std::endl; + } + if (!ImGui_ImplOpenGL3_Init(glsl_version)) { + std::cout << "Failed to initialize ImGui OpenGL backend" << std::endl; } - //std::cout << "Amount of cubes: " << cubeFactory.getCubes().size() << std::endl; + Shader simple_depth_shader = ResourceManager::LoadShader("point_shadow_depth.vert", "point_shadow_depth.frag", "point_shadow_depth.geom", "simple_depth_shader"); + + Shader wall_shader = ResourceManager::LoadShader("wall_test.vert", "wall_test.frag", nullptr, "wall"); + + LevelMap level_map = ResourceManager::LoadLevelMap("map_test.txt", "test_level"); + + level_map.RenderSetup(&wall_shader, &wall_shader, &wall_shader); + + int number_of_point_lights = 0; + + std::vector point_lights_vector; + + //PointLight point_light3(glm::vec3(30.0f, 3.0f, 30.0f), glm::vec3(1.0f, 1.0f, 1.0f), simple_depth_shader); + + //PointLight point_light2(glm::vec3(70.0f, 2.0f, 55.0f), glm::vec3(1.0f, 1.0f, 1.0f), simple_depth_shader); + + //PointLight point_light(glm::vec3(20.0f, 3.0f, 35.0f), glm::vec3(1.0f, 1.0f, 1.0f), simple_depth_shader); + + //PointLight point_lights[3] = { point_light, point_light2, point_light3 }; + + /*unsigned int depthCubemap, depthMapFBO; + + glGenFramebuffers(1, &depthMapFBO); + glGenTextures(1, &depthCubemap); + + glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap); + + for (unsigned int i = 0; i < 6; ++i) + { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_DEPTH_COMPONENT, SHADOW_WIDTH, SHADOW_HEIGHT, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + 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); + + glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); + glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthCubemap, 0); + glDrawBuffer(GL_NONE); + glReadBuffer(GL_NONE); + glBindFramebuffer(GL_FRAMEBUFFER, 0);*/ float r = 0.05f, g = 0.05f, b = 0.05f; while (!glfwWindowShouldClose(window)) { //timing - float currentFrame = glfwGetTime(); + float currentFrame = (float)glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; elapsedTime += deltaTime; @@ -111,25 +148,142 @@ int main() //input processInput(window); + ImGui_ImplOpenGL3_NewFrame(); + ImGui_ImplGlfw_NewFrame(); + ImGui::NewFrame(); + + ImGui::Begin("Settings"); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate); + if (ImGui::Button("Create Light") && number_of_point_lights < 10) { + point_lights_vector.push_back(PointLight(PlayerCharacter.Position, glm::vec3(1.0f, 1.0f, 1.0f), simple_depth_shader)); + number_of_point_lights = point_lights_vector.size(); + } + //ImGui::SliderInt("Amount of cubes: ", &amountOfCubes, 0, 1000); + ImGui::End(); + + ImGui::Render(); + + // view/projection transformations + glClearColor(r, g, b, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - // view/projection transformations - glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); - glm::mat4 view = camera.GetViewMatrix(); + //glDisable(GL_CULL_FACE); - glm::vec3 lightPos = glm::vec3(100.2f, 100.0f, 200.0f); + //level_map.GetMeshes(); - cubeFactory.render(view, projection, lightPos, deltaTime); + for (PointLight& point_light : point_lights_vector) + { + point_light.RenderSceneShadows(level_map.GetMeshes()); + } + //for (int i = 0; i < numOfPointLights; i++) + //{ + // point_lights[i].RenderSceneShadows(level_map.GetMeshes()); + //} + + glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + wall_shader.Use(); + // CHANGED PROJECTION TO USE FLAT 45 TO GET PLAYER CHARACTER TO WORK + glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); + glm::mat4 view = PlayerCharacter.GetViewMatrix(); + wall_shader.SetMatrix4("projection", projection); + wall_shader.SetMatrix4("view", view); + wall_shader.SetVector3f("viewPosition", PlayerCharacter.Position); + + wall_shader.SetVector3f("material.ambientColor", glm::vec3(1.0f, 0.0f, 0.0f)); + wall_shader.SetVector3f("material.diffuseColor", glm::vec3(0.5f, 0.5f, 0.5f)); + wall_shader.SetVector3f("material.specularColor", glm::vec3(0.0f, 0.0f, 1.0f)); + wall_shader.SetFloat("material.shininess", 1.0f); + // set lighting uniforms + wall_shader.SetInteger("numOfPointLights", number_of_point_lights); + int light_index = 0; + for (PointLight& point_light : point_lights_vector) + { + std::string name = "pointLights[" + std::to_string(light_index) + "]."; + wall_shader.SetVector3f((name + "base.color").c_str(), point_light.color); + wall_shader.SetFloat((name + "base.ambientIntensity").c_str(), point_light.ambient_intensity); + wall_shader.SetFloat((name + "base.diffuseIntensity").c_str(), point_light.diffuse_intensity); + wall_shader.SetFloat((name + "atten.constant").c_str(), point_light.attenuation_constant); + wall_shader.SetFloat((name + "atten.linear").c_str(), point_light.attenuation_linear); + wall_shader.SetFloat((name + "atten.exponential").c_str(), point_light.attenuation_exponential); + wall_shader.SetVector3f((name + "position").c_str(), point_light.Position); + wall_shader.SetFloat((name + "farPlane").c_str(), point_light.far_plane); + wall_shader.SetInteger((name + "depthMap").c_str(), light_index); + glActiveTexture(GL_TEXTURE0 + light_index); + glBindTexture(GL_TEXTURE_CUBE_MAP, point_light.depth_map); + + light_index++; + } + /*wall_shader.SetVector3f("pointLights[0].base.color", point_light.color); + wall_shader.SetVector3f("pointLights[0].base.ambientIntensity", point_light.ambient); + wall_shader.SetVector3f("pointLights[0].position", point_light.position); + wall_shader.SetVector3f("lightPosition2", point_light2.position); + wall_shader.SetVector3f("lightColor", point_light.color);*/ + //wall_shader.SetInteger("shadows", 1); // enable/disable shadows by pressing 'SPACE' + //wall_shader.SetInteger("depthMap", 0); + + + GLenum err; + while(err = glGetError()) + { + std::cout << "Error: " << err << std::endl; + } + + for (auto* mesh : level_map.GetMeshes()) + { + // //std::cout << "Rendering mesh" << std::endl; + mesh->Render(wall_shader); + } + + + /*float near_plane = 1.0f; + float far_plane = 50.0f; + glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), (float)SHADOW_WIDTH / (float)SHADOW_HEIGHT, near_plane, far_plane);*/ + /*std::vector shadowTransforms; + shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f))); + shadowTransforms.push_back(shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)));*/ + + /*glViewport(0, 0, SHADOW_WIDTH, SHADOW_HEIGHT); + glBindFramebuffer(GL_FRAMEBUFFER, depthMapFBO); + glClear(GL_DEPTH_BUFFER_BIT); + glCullFace(GL_FRONT); + simpleDepthShader.Use(); + for (unsigned int i = 0; i < 6; ++i) + simpleDepthShader.SetMatrix4("shadowMatrices[" + std::to_string(i) + "]", shadowTransforms[i]); + simpleDepthShader.SetFloat("far_plane", far_plane); + simpleDepthShader.SetVector3f("lightPos", lightPos); + levelMap.Update(projection, view); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glCullFace(GL_BACK); + + glViewport(0, 0, SCR_WIDTH, SCR_HEIGHT); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glBindTexture(GL_TEXTURE_CUBE_MAP, depthCubemap);*/ + //map.render(projection, view, lightPos, deltaTime, glm::vec3(SCR_WIDTH, SCR_HEIGHT, 0.0f), far_plane); + + //level_map.Update(projection, view, point_light.position, point_light.color, camera.Position); + + //cubeFactory.render(view, projection, lightPos, deltaTime, amountOfCubes); + + ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); //check and call glfwSwapBuffers(window); glfwPollEvents(); } - //cubeFactory.clear(); + // Cleanup + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); + ImGui::DestroyContext(); + glfwDestroyWindow(window); glfwTerminate(); - return 0; } void framebuffer_size_callback(GLFWwindow* window, int width, int height) @@ -145,18 +299,26 @@ void processInput(GLFWwindow* window) const float cameraSpeed = 5.0f * deltaTime; if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) - camera.ProcessKeyboard(FORWARD, deltaTime); + PlayerCharacter.ProcessKeyboard(FORWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) - camera.ProcessKeyboard(BACKWARD, deltaTime); + PlayerCharacter.ProcessKeyboard(BACKWARD, deltaTime); if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) - camera.ProcessKeyboard(LEFT, deltaTime); + PlayerCharacter.ProcessKeyboard(LEFT, deltaTime); if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) - camera.ProcessKeyboard(RIGHT, deltaTime); + PlayerCharacter.ProcessKeyboard(RIGHT, deltaTime); } void mouse_callback(GLFWwindow* window, double xposIn, double yposIn) { - //std::cout << "Mouse callback" << std::endl; + if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) != GLFW_PRESS) + { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + firstMouse = true; + return; + } + + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + //std::cout << "Mouse callback" << std::endl; float xpos = static_cast(xposIn); float ypos = static_cast(yposIn); @@ -173,10 +335,10 @@ void mouse_callback(GLFWwindow* window, double xposIn, double yposIn) lastX = xpos; lastY = ypos; - camera.ProcessMouseMovement(xoffset, yoffset); + PlayerCharacter.ProcessMouseMovement(xoffset, yoffset); } void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { - camera.ProcessMouseScroll(static_cast(yoffset)); + //PlayerCharacter.ProcessMouseScroll(static_cast(yoffset)); } diff --git a/map_reader.h b/map_reader.h new file mode 100644 index 0000000..f59053f --- /dev/null +++ b/map_reader.h @@ -0,0 +1,489 @@ +#pragma once + +#ifndef MAP_READER_H +#define MAP_READER_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "Shader.h" + +struct Wall +{ + glm::vec2 a, b; + int portal; +}; + +struct Sector +{ + int id; + int index; + int numberOfWalls; + float floorHeight; + float ceilingHeight; + + bool outwardFacing; + + glm::vec3 color; + + std::vector walls; +}; + +class Map +{ +public: + Map(std::string filename) : wallShader(Shader("wall_test.vert", "wall_test.frag")), floorShader(Shader("wall_test.vert", "wall_test.frag")) + { + parseMapFile(filename); + setupBuffers(); + } + + void render(glm::mat4 projection, glm::mat4 view, glm::vec3 lightPos) + { + wallShader.use(); + wallShader.setMat4("projection", projection); + wallShader.setMat4("view", view); + + glm::mat4 model = glm::mat4(1.0f); + wallShader.setMat4("model", model); + //shader.setVec3("objectColor", 1.0f, 0.0f, 0.0f); + wallShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f); + wallShader.setVec3("lightPos", lightPos); + + glBindVertexArray(wallVAO); + + // Use glDrawElements since we are using indices + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, wallIndices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + + floorShader.use(); + floorShader.setMat4("projection", projection); + floorShader.setMat4("view", view); + + model = glm::mat4(1.0f); + floorShader.setMat4("model", model); + floorShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f); + floorShader.setVec3("lightPos", lightPos); + + glBindVertexArray(floorVAO); + + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, floorIndices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + } + + void render(glm::mat4 projection, glm::mat4 view, glm::vec3 lightPos, float deltaTime, glm::vec3 resolution, float far_plane) + { + time += deltaTime; + + wallShader.use(); + wallShader.setMat4("projection", projection); + wallShader.setMat4("view", view); + wallShader.setVec3("iResolution", resolution); + wallShader.setFloat("iTime", time); + wallShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f); + wallShader.setVec3("lightPos", lightPos); + wallShader.setInt("shadows", 1); + wallShader.setFloat("far_plane", far_plane); + wallShader.setInt("diffuseTexture", 0); + wallShader.setInt("shadowMap", 1); + + glm::mat4 model = glm::mat4(1.0f); + wallShader.setMat4("model", model); + //shader.setVec3("objectColor", 1.0f, 0.0f, 0.0f); + + glBindVertexArray(wallVAO); + + // Use glDrawElements since we are using indices + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, wallIndices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + + floorShader.use(); + floorShader.setMat4("projection", projection); + floorShader.setMat4("view", view); + floorShader.setVec3("iResolution", resolution); + floorShader.setFloat("iTime", time); + floorShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f); + floorShader.setVec3("lightPos", lightPos); + floorShader.setInt("shadows", 1); + floorShader.setFloat("far_plane", far_plane); + floorShader.setInt("diffuseTexture", 0); + floorShader.setInt("shadowMap", 1); + + model = glm::mat4(1.0f); + floorShader.setMat4("model", model); + + glBindVertexArray(floorVAO); + + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, floorIndices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + } + + void render(glm::mat4 projection, glm::mat4 view, glm::vec3 lightPos, Shader _shader) + { + glm::mat4 model = glm::mat4(1.0f); + _shader.setMat4("model", model); + + glBindVertexArray(wallVAO); + + // Use glDrawElements since we are using indices + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, wallIndices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + + glBindVertexArray(floorVAO); + + //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, floorIndices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0); + + /*floorShader.use(); + floorShader.setMat4("projection", projection); + floorShader.setMat4("view", view); + + model = glm::mat4(1.0f); + floorShader.setMat4("model", model); + floorShader.setVec3("lightColor", 1.0f, 1.0f, 1.0f); + floorShader.setVec3("lightPos", lightPos); + + glBindVertexArray(floorVAO); + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glDrawElements(GL_TRIANGLES, floorIndices.size(), GL_UNSIGNED_INT, 0); + + glBindVertexArray(0);*/ + } +private: + std::vector sectors; + + unsigned int wallVAO; + unsigned int wallVBO, wallEBO, wallNBO, wallCBO; + unsigned int floorVAO; + unsigned int floorVBO, floorEBO, floorNBO, floorCBO; + + std::vector wallVertices, wallNormals, wallColors; + std::vector wallIndices; + + std::vector floorVertices, floorNormals, floorColors; + std::vector floorIndices; + + Shader wallShader; + + Shader floorShader; + + float time; + + Sector parseSector(std::string& line) + { + Sector sector; + std::stringstream ss(line); + ss >> sector.id >> sector.index >> sector.numberOfWalls >> sector.floorHeight >> sector.ceilingHeight >> sector.outwardFacing; + + static std::random_device rd; // Obtain a random number from hardware + static std::mt19937 eng(rd()); // Seed the generator + std::uniform_real_distribution distr(0.0f, 1.0f); // Define the range + + glm::vec3 randomColor(distr(eng), distr(eng), distr(eng)); + + sector.color = randomColor; + + return sector; + } + + Wall parseWall(std::string& line) + { + Wall wall; + std::stringstream ss(line); + ss >> wall.a.x >> wall.a.y >> wall.b.x >> wall.b.y >> wall.portal; + return wall; + } + + void parseMapFile(std::string filename) + { + //std::cout << "Parsing map file: " << filename << std::endl; + std::ifstream file(filename); + std::string line; + + bool inSector = false, inWall = false; + while (std::getline(file, line)) + { + //std::cout << "Line: " << line << std::endl; + if (line.empty() || line[0] == '#') continue; + + if (line.find("[SECTOR]") != std::string::npos) + { + inSector = true; + inWall = false; + continue; + } + else if (line.find("[WALL]") != std::string::npos) + { + inSector = false; + inWall = true; + continue; + } + + if (inSector) + { + sectors.push_back(parseSector(line)); + } + + if (inWall && !sectors.empty()) + { + Wall wall = parseWall(line); + sectors.back().walls.push_back(wall); + } + } + } + + void setupBuffers() + { + std::cout << "Setting up buffers" << std::endl; + + int wallBaseIndex = 0; + int floorBaseIndex = 0; + for (Sector sector : sectors) + { + std::vector _floorVertices; + std::vector _ceilingVertices; + for (Wall wall : sector.walls) + { + glm::vec3 v0(wall.a.x, sector.floorHeight, wall.a.y); + glm::vec3 v1(wall.b.x, sector.floorHeight, wall.b.y); + glm::vec3 v2(wall.b.x, sector.ceilingHeight, wall.b.y); + glm::vec3 v3(wall.a.x, sector.ceilingHeight, wall.a.y); + + _floorVertices.push_back(v0); + + _ceilingVertices.push_back(v3); + + if (wall.portal != 0) + { + Sector& portalSector = sectors[wall.portal - 1]; + if (portalSector.floorHeight > sector.floorHeight) + { + v2.y = portalSector.floorHeight; + v3.y = portalSector.floorHeight; + + addWallVectors(v0, v1, v2, v3, sector.color, wallBaseIndex, sector.outwardFacing); + } + + if (portalSector.ceilingHeight < sector.ceilingHeight) + { + v0.y = portalSector.ceilingHeight; + v1.y = portalSector.ceilingHeight; + v2.y = sector.ceilingHeight; + v3.y = sector.ceilingHeight; + + addWallVectors(v0, v1, v2, v3, sector.color, wallBaseIndex, sector.outwardFacing); + } + continue; + } + + addWallVectors(v0, v1, v2, v3, sector.color, wallBaseIndex, sector.outwardFacing); + continue; + } + + addFloorVectors(_floorVertices, floorBaseIndex, true); + addFloorVectors(_ceilingVertices, floorBaseIndex, false); + } + + glGenVertexArrays(1, &wallVAO); + glGenBuffers(1, &wallVBO); + glGenBuffers(1, &wallEBO); + glGenBuffers(1, &wallNBO); + glGenBuffers(1, &wallCBO); + + glBindVertexArray(wallVAO); + + glBindBuffer(GL_ARRAY_BUFFER, wallVBO); + glBufferData(GL_ARRAY_BUFFER, wallVertices.size() * sizeof(float), wallVertices.data(), GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, wallNBO); + glBufferData(GL_ARRAY_BUFFER, wallNormals.size() * sizeof(float), wallNormals.data(), GL_STATIC_DRAW); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + + glBindBuffer(GL_ARRAY_BUFFER, wallCBO); + glBufferData(GL_ARRAY_BUFFER, wallColors.size() * sizeof(float), wallColors.data(), GL_STATIC_DRAW); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(2); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wallEBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, wallIndices.size() * sizeof(unsigned int), wallIndices.data(), GL_STATIC_DRAW); + + glBindVertexArray(0); + + glGenVertexArrays(1, &floorVAO); + glGenBuffers(1, &floorVBO); + glGenBuffers(1, &floorEBO); + glGenBuffers(1, &floorNBO); + glGenBuffers(1, &floorCBO); + + glBindVertexArray(floorVAO); + + glBindBuffer(GL_ARRAY_BUFFER, floorVBO); + glBufferData(GL_ARRAY_BUFFER, floorVertices.size() * sizeof(float), floorVertices.data(), GL_STATIC_DRAW); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, floorNBO); + glBufferData(GL_ARRAY_BUFFER, floorNormals.size() * sizeof(float), floorNormals.data(), GL_STATIC_DRAW); + glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + + glBindBuffer(GL_ARRAY_BUFFER, floorCBO); + glBufferData(GL_ARRAY_BUFFER, floorColors.size() * sizeof(float), floorColors.data(), GL_STATIC_DRAW); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); + glEnableVertexAttribArray(2); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, floorEBO); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, floorIndices.size() * sizeof(unsigned int), floorIndices.data(), GL_STATIC_DRAW); + + glBindVertexArray(0); + } + + void addWallVectors(glm::vec3 v0, glm::vec3 v1, glm::vec3 v2, glm::vec3 v3, glm::vec3 color, int& baseIndex, bool outward) + { + wallVertices.push_back(v0.x); + wallVertices.push_back(v0.y); + wallVertices.push_back(v0.z); + + wallVertices.push_back(v1.x); + wallVertices.push_back(v1.y); + wallVertices.push_back(v1.z); + + wallVertices.push_back(v2.x); + wallVertices.push_back(v2.y); + wallVertices.push_back(v2.z); + + wallVertices.push_back(v3.x); + wallVertices.push_back(v3.y); + wallVertices.push_back(v3.z); + + glm::vec3 normal = glm::normalize(glm::cross(v1 - v0, v3 - v0)); + normal = outward ? normal : -normal; + + wallNormals.push_back(normal.x); + wallNormals.push_back(normal.y); + wallNormals.push_back(normal.z); + + wallNormals.push_back(normal.x); + wallNormals.push_back(normal.y); + wallNormals.push_back(normal.z); + + wallNormals.push_back(normal.x); + wallNormals.push_back(normal.y); + wallNormals.push_back(normal.z); + + wallNormals.push_back(normal.x); + wallNormals.push_back(normal.y); + wallNormals.push_back(normal.z); + + wallColors.push_back(color.x); + wallColors.push_back(color.y); + wallColors.push_back(color.z); + + wallColors.push_back(color.x); + wallColors.push_back(color.y); + wallColors.push_back(color.z); + + wallColors.push_back(color.x); + wallColors.push_back(color.y); + wallColors.push_back(color.z); + + wallColors.push_back(color.x); + wallColors.push_back(color.y); + wallColors.push_back(color.z); + + // First triangle + wallIndices.push_back(baseIndex); + wallIndices.push_back(baseIndex + 1); + wallIndices.push_back(baseIndex + 2); + + // Second triangle + wallIndices.push_back(baseIndex); + wallIndices.push_back(baseIndex + 2); + wallIndices.push_back(baseIndex + 3); + + baseIndex += 4; + + } + + void addFloorVectors(std::vector _vertices, int& baseIndex, bool floor) + { + for (int i = 0; i + 2 < _vertices.size() ; i+=1) + { + this->floorVertices.push_back(_vertices[0].x); + this->floorVertices.push_back(_vertices[0].y); + this->floorVertices.push_back(_vertices[0].z); + + this->floorVertices.push_back(_vertices[i + 1].x); + this->floorVertices.push_back(_vertices[i + 1].y); + this->floorVertices.push_back(_vertices[i + 1].z); + + this->floorVertices.push_back(_vertices[i + 2].x); + this->floorVertices.push_back(_vertices[i + 2].y); + this->floorVertices.push_back(_vertices[i + 2].z); + + glm::vec3 normal = glm::normalize(glm::cross(_vertices[i + 1] - _vertices[0], _vertices[i + 2] - _vertices[0])); + normal = floor ? -normal : normal; + + floorNormals.push_back(normal.x); + floorNormals.push_back(normal.y); + floorNormals.push_back(normal.z); + + floorNormals.push_back(normal.x); + floorNormals.push_back(normal.y); + floorNormals.push_back(normal.z); + + floorNormals.push_back(normal.x); + floorNormals.push_back(normal.y); + floorNormals.push_back(normal.z); + + glm::vec3 color; + color = floor ? glm::vec3(0.75f, 0.5f, 0.25f) : glm::vec3(0.25f, 0.5f, 0.75f); + + this->floorColors.push_back(color.x); + this->floorColors.push_back(color.y); + this->floorColors.push_back(color.z); + + this->floorColors.push_back(color.x); + this->floorColors.push_back(color.y); + this->floorColors.push_back(color.z); + + this->floorColors.push_back(color.x); + this->floorColors.push_back(color.y); + this->floorColors.push_back(color.z); + + floorIndices.push_back(baseIndex); + floorIndices.push_back(baseIndex + 1); + floorIndices.push_back(baseIndex + 2); + + baseIndex += 3; + } + } +}; + +#endif diff --git a/map_test.txt b/map_test.txt new file mode 100644 index 0000000..75e0910 --- /dev/null +++ b/map_test.txt @@ -0,0 +1,36 @@ +[SECTOR] +0 8 0.0 5.0 0 0.65 0.1 0.2 +8 3 1.0 4.0 0 0.65 0.65 0.2 +11 4 0.2 6.0 0 0.65 0.1 0.65 +15 5 0.0 3.0 0 0.1 0.1 0.65 +20 4 0.0 5.0 1 0.1 0.65 0.2 + +[WALL] +40 10 20 10 0 +50 20 40 10 0 +50 30 50 20 0 +40 40 50 30 3 +20 40 40 40 0 +10 30 20 40 2 +10 20 10 30 0 +20 10 10 20 0 + +20 40 10 30 1 +10 50 20 40 0 +10 30 10 50 0 + +50 30 40 40 1 +60 50 50 30 0 +60 70 60 50 4 +40 40 60 70 0 + +70 40 60 50 0 +80 50 70 40 0 +80 70 80 50 0 +60 70 80 70 0 +60 50 60 70 3 + +25 25 25 26 0 +26 25 25 25 0 +26 26 26 25 0 +25 26 26 26 0 diff --git a/map_test_2.txt b/map_test_2.txt new file mode 100644 index 0000000..54ab924 --- /dev/null +++ b/map_test_2.txt @@ -0,0 +1,9 @@ +[SECTOR] +1 0 4 -1.0 5.0 + +[WALL] +# SECTOR 1: 0..7 +-10 -10 10 -10 0 + 10 -10 10 10 0 + 10 10 -10 10 0 +-10 10 -10 -10 0 \ No newline at end of file diff --git a/point_shadow_depth.frag b/point_shadow_depth.frag new file mode 100644 index 0000000..03beb62 --- /dev/null +++ b/point_shadow_depth.frag @@ -0,0 +1,15 @@ + +#version 330 +in vec4 FragPosition; + +uniform vec3 lightPosition; +uniform float farPlane; + +void main() +{ + float lightDistance = length(FragPosition.xyz - lightPosition); + + lightDistance = lightDistance / farPlane; + + gl_FragDepth = lightDistance; +} \ No newline at end of file diff --git a/point_shadow_depth.geom b/point_shadow_depth.geom new file mode 100644 index 0000000..70c6396 --- /dev/null +++ b/point_shadow_depth.geom @@ -0,0 +1,25 @@ + + +#version 330 core +layout (triangles) in; +layout (triangle_strip, max_vertices=18) out; + +uniform mat4 shadowMatrices[6]; + +out vec4 FragPosition; // FragPos from GS (output per emitvertex) + +void main() +{ + for(int face = 0; face < 6; ++face) + { + gl_Layer = face; // built-in variable that specifies to which face we render. + for(int i = 0; i < 3; ++i) // for each triangle's vertices + { + FragPosition = gl_in[i].gl_Position; + gl_Position = shadowMatrices[face] * FragPosition; + EmitVertex(); + } + EndPrimitive(); + } +} + diff --git a/point_shadow_depth.vert b/point_shadow_depth.vert new file mode 100644 index 0000000..7219f85 --- /dev/null +++ b/point_shadow_depth.vert @@ -0,0 +1,10 @@ + +#version 330 core +layout (location = 0) in vec3 aPosition; + +uniform mat4 model; + +void main() +{ + gl_Position = model * vec4(aPosition, 1.0); +} diff --git a/shader.h b/shader.h index efe0cc5..38b291c 100644 --- a/shader.h +++ b/shader.h @@ -2,154 +2,40 @@ #ifndef SHADER_H #define SHADER_H -#include - #include -#include -#include -#include +#include +#include +#include + + +// General purpose shader object. Compiles from file, generates +// compile/link-time error messages and hosts several utility +// functions for easy management. class Shader { public: - unsigned int ID; - - Shader(const char* vertexPath, const char* fragmentPath) - { - std::string vertexCode; - std::string fragmentCode; - std::ifstream vShaderFile; - std::ifstream fShaderFile; - - vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); - try - { - vShaderFile.open(vertexPath); - fShaderFile.open(fragmentPath); - std::stringstream vShaderStream, fShaderStream; - vShaderStream << vShaderFile.rdbuf(); - fShaderStream << fShaderFile.rdbuf(); - vShaderFile.close(); - fShaderFile.close(); - vertexCode = vShaderStream.str(); - fragmentCode = fShaderStream.str(); - } - catch (std::ifstream::failure e) - { - std::cout << "ERROR::SHADER::FILE_NOT_SUCCESFULLY_READ" << std::endl; - } - const char* vShaderCode = vertexCode.c_str(); - const char* fShaderCode = fragmentCode.c_str(); - - unsigned int vertex, fragment; - - vertex = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(vertex, 1, &vShaderCode, NULL); - glCompileShader(vertex); - checkCompileErrors(vertex, "VERTEX"); - - fragment = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(fragment, 1, &fShaderCode, NULL); - glCompileShader(fragment); - checkCompileErrors(fragment, "FRAGMENT"); - - ID = glCreateProgram(); - glAttachShader(ID, vertex); - glAttachShader(ID, fragment); - glLinkProgram(ID); - checkCompileErrors(ID, "PROGRAM"); - - glDeleteShader(vertex); - glDeleteShader(fragment); - } - void use() - { - glUseProgram(ID); - } - // utility uniform functions - // ------------------------------------------------------------------------ - void setBool(const std::string& name, bool value) const - { - glUniform1i(glGetUniformLocation(ID, name.c_str()), (int)value); - } - // ------------------------------------------------------------------------ - void setInt(const std::string& name, int value) const - { - glUniform1i(glGetUniformLocation(ID, name.c_str()), value); - } - // ------------------------------------------------------------------------ - void setFloat(const std::string& name, float value) const - { - glUniform1f(glGetUniformLocation(ID, name.c_str()), value); - } - // ------------------------------------------------------------------------ - void setVec2(const std::string& name, const glm::vec2& value) const - { - glUniform2fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); - } - void setVec2(const std::string& name, float x, float y) const - { - glUniform2f(glGetUniformLocation(ID, name.c_str()), x, y); - } - // ------------------------------------------------------------------------ - void setVec3(const std::string& name, const glm::vec3& value) const - { - glUniform3fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); - } - void setVec3(const std::string& name, float x, float y, float z) const - { - glUniform3f(glGetUniformLocation(ID, name.c_str()), x, y, z); - } - // ------------------------------------------------------------------------ - void setVec4(const std::string& name, const glm::vec4& value) const - { - glUniform4fv(glGetUniformLocation(ID, name.c_str()), 1, &value[0]); - } - void setVec4(const std::string& name, float x, float y, float z, float w) const - { - glUniform4f(glGetUniformLocation(ID, name.c_str()), x, y, z, w); - } - // ------------------------------------------------------------------------ - void setMat2(const std::string& name, const glm::mat2& mat) const - { - glUniformMatrix2fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); - } - // ------------------------------------------------------------------------ - void setMat3(const std::string& name, const glm::mat3& mat) const - { - glUniformMatrix3fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); - } - // ------------------------------------------------------------------------ - void setMat4(const std::string& name, const glm::mat4& mat) const - { - glUniformMatrix4fv(glGetUniformLocation(ID, name.c_str()), 1, GL_FALSE, &mat[0][0]); - } - + // state + unsigned int ID; + // constructor + Shader() { } + // sets the current shader as active + Shader& Use(); + // compiles the shader from given source code + void Compile(const char* vertexSource, const char* fragmentSource, const char* geometrySource = nullptr); // note: geometry source code is optional + // utility functions + void SetFloat(const char* name, float value, bool useShader = false); + void SetInteger(const char* name, int value, bool useShader = false); + void SetVector2f(const char* name, float x, float y, bool useShader = false); + void SetVector2f(const char* name, const glm::vec2& value, bool useShader = false); + void SetVector3f(const char* name, float x, float y, float z, bool useShader = false); + void SetVector3f(const char* name, const glm::vec3& value, bool useShader = false); + void SetVector4f(const char* name, float x, float y, float z, float w, bool useShader = false); + void SetVector4f(const char* name, const glm::vec4& value, bool useShader = false); + void SetMatrix4(const char* name, const glm::mat4& matrix, bool useShader = false); private: - void checkCompileErrors(unsigned int shader, std::string type) - { - int success; - char infoLog[1024]; - if (type != "PROGRAM") - { - glGetShaderiv(shader, GL_COMPILE_STATUS, &success); - if (!success) - { - glGetShaderInfoLog(shader, 1024, NULL, infoLog); - std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- ---------------------------------------------------- -- " << std::endl; - } - } - else - { - glGetProgramiv(shader, GL_LINK_STATUS, &success); - if (!success) - { - glGetProgramInfoLog(shader, 1024, NULL, infoLog); - std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- ---------------------------------------------------- -- " << std::endl; - } - } - } + // checks if compilation or linking failed and if so, print the error logs + void checkCompileErrors(unsigned int object, std::string type); }; -#endif +#endif \ No newline at end of file diff --git a/wall.frag b/wall.frag new file mode 100644 index 0000000..b63970c --- /dev/null +++ b/wall.frag @@ -0,0 +1,71 @@ +#version 330 core +out vec4 FragColor; + +uniform vec3 lightColor; +uniform vec3 lightPos; +uniform vec3 viewPos; + +uniform sampler2D diffuseTexture; +uniform samplerCube depthMap; + +uniform float far_plane; +uniform bool shadows; + +uniform vec3 iResolution; // viewport resolution (in pixels) +uniform float iTime; // shader playback time (in seconds) +uniform float iTimeDelta; // render time (in seconds) +uniform float iFrameRate; // shader frame rate +uniform int iFrame; // shader playback frame +uniform float iChannelTime[4]; // channel playback time (in seconds) +uniform vec3 iChannelResolution[4]; // channel resolution (in pixels) +uniform vec4 iMouse; // mouse pixel coords. xy: current (if MLB down), zw: click +uniform sampler2D iChannel0; // input channel. XX = 2D/Cube +uniform vec4 iDate; // (year, month, day, time in seconds) + +in vec3 FragPos; +in vec3 Normal; +in vec3 Color; + +float ShadowCalculation(vec3 fragPos) +{ + // get vector between fragment position and light position + vec3 fragToLight = fragPos - lightPos; + // ise the fragment to light vector to sample from the depth map + float closestDepth = texture(depthMap, fragToLight).r; + // it is currently in linear range between [0,1], let's re-transform it back to original depth value + closestDepth *= far_plane; + // now get current linear depth as the length between the fragment and light position + float currentDepth = length(fragToLight); + // test for shadows + float bias = 0.05; // we use a much larger bias since depth is now in [near_plane, far_plane] range + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + // display closestDepth as debug (to visualize depth cubemap) + //FragColor = vec4(vec3(closestDepth / far_plane), 1.0); + + return shadow; +} + +void main() +{ + //vec3 color = texture(diffuseTexture, FragPos.xy).rgb; + vec3 normal = normalize(Normal); + vec3 lightColor = vec3(0.3); + // ambient + vec3 ambient = 0.3 * lightColor; + // diffuse + vec3 lightDir = normalize(lightPos - FragPos); + float diff = max(dot(lightDir, normal), 0.0); + vec3 diffuse = diff * lightColor; + // specular + vec3 viewDir = normalize(viewPos - FragPos); + vec3 reflectDir = reflect(-lightDir, normal); + float spec = 0.0; + vec3 halfwayDir = normalize(lightDir + viewDir); + spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0); + vec3 specular = spec * lightColor; + // calculate shadow + float shadow = ShadowCalculation(FragPos); + vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular)) * Color; + + FragColor = vec4(lighting, 1.0); +} \ No newline at end of file diff --git a/wall.vert b/wall.vert new file mode 100644 index 0000000..7ce6c79 --- /dev/null +++ b/wall.vert @@ -0,0 +1,22 @@ + +#version 330 core +layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec3 aColor; + +out vec3 FragPos; +out vec3 Normal; +out vec3 Color; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + FragPos = vec3(model * vec4(aPos, 1.0)); + Normal = mat3(transpose(inverse(model))) * aNormal; + Color = aColor; + + gl_Position = projection * view * vec4(FragPos, 1.0); +} diff --git a/wall_test.frag b/wall_test.frag new file mode 100644 index 0000000..4439458 --- /dev/null +++ b/wall_test.frag @@ -0,0 +1,238 @@ +#version 330 core +out vec4 FragColor; + +const int MAX_POINT_LIGHTS = 10; + +in vec3 FragPosition; +in vec3 Normal; +in vec3 Color; + +struct BaseLight +{ + vec3 color; + float ambientIntensity; + float diffuseIntensity; +}; + +struct Attenuation +{ + float constant; + float linear; + float exponential; +}; + +struct PointLight +{ + BaseLight base; + Attenuation atten; + vec3 position; + float farPlane; + samplerCube depthMap; +}; + +struct Material +{ + vec3 ambientColor; + vec3 diffuseColor; + vec3 specularColor; + float shininess; +}; + +uniform int numOfPointLights; +uniform PointLight pointLights[MAX_POINT_LIGHTS]; +uniform Material material; + +//uniform sampler2D diffuseTexture; + + +uniform vec3 viewPosition; + +//uniform float farPlane; +//uniform bool shadows; + +vec3 gridSamplingDisk[20] = vec3[] +( + vec3(1, 1, 1), vec3( 1, -1, 1), vec3(-1, -1, 1), vec3(-1, 1, 1), + vec3(1, 1, -1), vec3( 1, -1, -1), vec3(-1, -1, -1), vec3(-1, 1, -1), + vec3(1, 1, 0), vec3( 1, -1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3(1, 0, 1), vec3(-1, 0, 1), vec3( 1, 0, -1), vec3(-1, 0, -1), + vec3(0, 1, 1), vec3( 0, -1, 1), vec3( 0, -1, -1), vec3( 0, 1, -1) +); + +int bayer[64] = int[64]( + 0, 32, 8, 40, 2, 34, 10, 42, + 48, 16, 56, 24, 50, 18, 58, 26, + 12, 44, 4, 36, 14, 46, 6, 38, + 60, 28, 52, 20, 62, 30, 54, 22, + 3, 35, 11, 43, 1, 33, 9, 41, + 51, 19, 59, 27, 49, 17, 57, 25, + 15, 47, 7, 39, 13, 45, 5, 37, + 63, 31, 55, 23, 61, 29, 53, 21 +); + +float ShadowCalculation(PointLight light, vec3 normal) +{ + // get vector between fragment position and light position + vec3 fragToLight = FragPosition - light.position; + float currentDepth = length(fragToLight); + + vec3 lightDir = normalize(light.position - FragPosition); + + float shadow = 0.0; + float bias = max(0.05 * (1.0 - dot(normal, lightDir)), 0.005); + //float bias = 0.15; + int samples = 20; + float viewDistance = length(viewPosition - FragPosition); + float diskRadius = (1.0 + (viewDistance / light.farPlane)) / 25.0; + for(int i = 0; i < samples; ++i) + { + float closestDepth = texture(light.depthMap, fragToLight + gridSamplingDisk[i] * diskRadius).r; + //FragColor = vec4(vec3(closestDepth / farPlane), 1.0); + closestDepth *= light.farPlane; // undo mapping [0;1] + if(currentDepth - bias > closestDepth) + shadow += 1.0; + } + shadow /= float(samples); + + //shadow = dither(shadow); + + // display closestDepth as debug (to visualize depth cubemap) + // FragColor = vec4(vec3(closestDepth / farPlane), 1.0); + + return shadow; +} + +vec4 dither(vec4 color) +{ + float downsampleFactor = 2; + float ditherSize = 0.05; + float colorSize = 8.0; + + float _x = (gl_FragCoord.x/downsampleFactor); + float _y = (gl_FragCoord.y/downsampleFactor); + _x = mod(_x, 8); + _y = mod(_y, 8); + int _M = bayer[8*int(_y) + int(_x)]; + float _z = float(_M) * (1.0 / pow(8, 2.0)); + _z -= 0.5; + + color.x += _z * ditherSize; + color.y += _z * ditherSize; + color.z += _z * ditherSize; + + //color = greyscale; + color = floor(color * (colorSize - 1) + 0.5) / (colorSize - 1); + vec3 greyscale = vec3(0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b); + + return color; +} + +/*vec3 diffuse(vec3 _lightColor, vec3 _lightPosition) +{ + // diffuse + vec3 lightDir = normalize(_lightPosition - FragPosition); + vec3 lightDist = _lightPosition - FragPosition; + float diff = max(dot(lightDir, Normal), 0.0); + + float linear = 0.2; + float exponential = 0.2; + // Apply attenuation: light fades over distance + float attenuation = 1.0 / (1.0 + (linear * length(lightDist)) + (exponential * pow(length(lightDist), 2.0))); + + vec3 diffuse = diff * lightColor; + return diffuse; +}*/ + +/*vec3 specular(vec3 _lightPosition) +{ + // specular + vec3 lightDir = normalize(_lightPosition - FragPosition); + vec3 viewDir = normalize(viewPosition - FragPosition); + vec3 reflectDir = reflect(-lightDir, Normal); + float spec = 0.0; + vec3 halfwayDir = normalize(lightDir + viewDir); + spec = pow(max(dot(Normal, halfwayDir), 0.0), 64.0); + vec3 specular = spec * lightColor; + return specular; +}*/ + +vec4 calculateAmbient(BaseLight light) +{ + vec4 ambientColor = vec4(light.color, 1.0) * + light.ambientIntensity * + vec4(material.ambientColor, 1.0); + + return ambientColor; +} + +vec4 calculateDiffuse(BaseLight light, vec3 lightDirection, vec3 normal) +{ + vec4 diffuseColor = vec4(0.0); + float diffuseFactor = dot(normal, -lightDirection); + + if (diffuseFactor > 0.0) + { + diffuseColor = vec4(light.color, 1.0) * + light.diffuseIntensity * + vec4(material.diffuseColor, 1.0) * + diffuseFactor; + } + + return diffuseColor; +} + +vec4 calculateSpecular(BaseLight light, vec3 lightDirection, vec3 normal) +{ + vec4 specularColor = vec4(0.0); + vec3 pixelToCamera = normalize(viewPosition - FragPosition); + vec3 lightReflect = normalize(reflect(lightDirection, normal)); + float specularFactor = dot(pixelToCamera, lightReflect); + + if (specularFactor > 0.0) + { + specularColor = vec4(light.color, 1.0) * + light.diffuseIntensity * + vec4(material.specularColor, 1.0) * + specularFactor; + } + + return specularColor * material.shininess; +} + +vec4 caclulatePointLight(int index, vec3 normal) +{ + vec3 lightDirection = FragPosition - pointLights[index].position; + float lightDistance = length(lightDirection); + lightDirection = normalize(lightDirection); + + float shadow = 1.0 - ShadowCalculation(pointLights[index], normal); + + vec4 color = calculateAmbient(pointLights[index].base) + + shadow * + (calculateDiffuse(pointLights[index].base, lightDirection, normal) + + calculateSpecular(pointLights[index].base, lightDirection, normal)); + + + // color = vec4(Color, 1.0); + + float attenuation = pointLights[index].atten.constant + + pointLights[index].atten.linear * lightDistance + + pointLights[index].atten.exponential * (lightDistance * lightDistance); + + return color / attenuation; +} + +void main() +{ + vec3 normal = normalize(Normal); + vec4 totalLight = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < numOfPointLights; i++) + { + totalLight += caclulatePointLight(i, normal); + } + + //totalLight = dither(totalLight); + FragColor = totalLight; +} + diff --git a/wall_test.vert b/wall_test.vert new file mode 100644 index 0000000..11dbf04 --- /dev/null +++ b/wall_test.vert @@ -0,0 +1,22 @@ + +#version 330 core +layout (location = 0) in vec3 aPosition; +layout (location = 1) in vec3 aNormal; +layout (location = 2) in vec3 aColor; + +out vec3 FragPosition; +out vec3 Normal; +out vec3 Color; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + FragPosition = vec3(model * vec4(aPosition, 1.0)); + Normal = mat3(transpose(inverse(model))) * aNormal; + Color = aColor; + + gl_Position = projection * view * vec4(FragPosition, 1.0); +}