From 4bf6b022551fd690b7a311ff197bfabdf10ab9c7 Mon Sep 17 00:00:00 2001 From: onTheZero <114521696+onTheZero@users.noreply.github.com> Date: Wed, 13 Aug 2025 00:59:03 -0400 Subject: [PATCH] GameObjects Began to add GameObjects, starting with the player. --- GameObject.h | 61 ++++ GraphicsComponent.h | 8 + InputComponent.h | 8 + LearningOpenGL.vcxproj | 40 ++- LearningOpenGL.vcxproj.filters | 94 ++++++- LevelMap.cpp | 275 ++++++++++++++++++ LevelMap.h | 94 +++++++ Light.cpp | 1 + Light.h | 0 MeshRenderer.cpp | 240 ++++++++++++++++ MeshRenderer.h | 56 ++++ PhysicsComponent.h | 8 + Player.cpp | 64 +++++ Player.h | 43 +++ PlayerInputComponent.h | 22 ++ PointLight.cpp | 1 + PointLight.h | 115 ++++++++ ResourceManager.cpp | 102 +++++++ ResourceManager.h | 33 +++ Shader.cpp | 129 +++++++++ camera.h | 37 +-- cube.h | 10 +- cubeFactory.h | 37 +++ imgui.ini | 12 + input_processor.h | 1 + main.cpp | 262 ++++++++++++++---- map_reader.h | 489 +++++++++++++++++++++++++++++++++ map_test.txt | 36 +++ map_test_2.txt | 9 + point_shadow_depth.frag | 15 + point_shadow_depth.geom | 25 ++ point_shadow_depth.vert | 10 + shader.h | 172 ++---------- wall.frag | 71 +++++ wall.vert | 22 ++ wall_test.frag | 238 ++++++++++++++++ wall_test.vert | 22 ++ 37 files changed, 2640 insertions(+), 222 deletions(-) create mode 100644 GameObject.h create mode 100644 GraphicsComponent.h create mode 100644 InputComponent.h create mode 100644 LevelMap.cpp create mode 100644 LevelMap.h create mode 100644 Light.cpp create mode 100644 Light.h create mode 100644 MeshRenderer.cpp create mode 100644 MeshRenderer.h create mode 100644 PhysicsComponent.h create mode 100644 Player.cpp create mode 100644 Player.h create mode 100644 PlayerInputComponent.h create mode 100644 PointLight.cpp create mode 100644 PointLight.h create mode 100644 ResourceManager.cpp create mode 100644 ResourceManager.h create mode 100644 Shader.cpp create mode 100644 imgui.ini create mode 100644 input_processor.h create mode 100644 map_reader.h create mode 100644 map_test.txt create mode 100644 map_test_2.txt create mode 100644 point_shadow_depth.frag create mode 100644 point_shadow_depth.geom create mode 100644 point_shadow_depth.vert create mode 100644 wall.frag create mode 100644 wall.vert create mode 100644 wall_test.frag create mode 100644 wall_test.vert 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); +}