diff --git a/assets b/assets index 0bcd7bc2..4bd902b6 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 0bcd7bc2b87d3c19ee794960ebd5e8ee5159273c +Subproject commit 4bd902b697b8eef063da800102e6e9c3b29353eb diff --git a/include/Engine/Rendering/Camera.h b/include/Engine/Rendering/Camera.h index 6a1acdd8..660dfd49 100644 --- a/include/Engine/Rendering/Camera.h +++ b/include/Engine/Rendering/Camera.h @@ -46,10 +46,7 @@ public: float FarClip() const { return m_FarClip; } void SetFarClip(float val); - float m_AspectRatio; - float m_FOV; - float m_NearClip; - float m_FarClip; + private: void UpdateViewMatrix(); @@ -60,6 +57,11 @@ private: glm::mat4 m_ProjectionMatrix; glm::mat4 m_ViewMatrix; + + float m_AspectRatio; + float m_FOV; + float m_NearClip; + float m_FarClip; }; #endif \ No newline at end of file diff --git a/include/Engine/Rendering/IRenderer.h b/include/Engine/Rendering/IRenderer.h index 3c35869d..1acb2454 100644 --- a/include/Engine/Rendering/IRenderer.h +++ b/include/Engine/Rendering/IRenderer.h @@ -3,9 +3,12 @@ #include "../Common.h" #include "../OpenGL.h" +#include "../GLM.h" #include "../Core/Util/Rectangle.h" +#include "Util/ScreenCoords.h" #include "Camera.h" #include "RenderQueue.h" +#include "Model.h" class IRenderer { @@ -28,6 +31,7 @@ public: } virtual void Initialize() = 0; + virtual void Update(double dt) = 0; virtual void Draw(RenderQueueCollection& rq) = 0; protected: diff --git a/include/Engine/Rendering/RenderQueue.h b/include/Engine/Rendering/RenderQueue.h index f3125462..1bbeb7f6 100644 --- a/include/Engine/Rendering/RenderQueue.h +++ b/include/Engine/Rendering/RenderQueue.h @@ -13,6 +13,8 @@ class Skeleton; class Texture; class RenderQueue; +//TODO: Render: Remove obsolete RenderJobs and fix standard values on variables. + struct RenderJob { friend class RenderQueue; diff --git a/include/Engine/Rendering/Renderer.h b/include/Engine/Rendering/Renderer.h new file mode 100644 index 00000000..24dcb74b --- /dev/null +++ b/include/Engine/Rendering/Renderer.h @@ -0,0 +1,62 @@ +#ifndef Renderer_h__ +#define Renderer_h__ + +#include + +#include "IRenderer.h" +#include "ShaderProgram.h" +//TODO: Temp resourceManager +#include "../Core/ResourceManager.h" +#include "Util/UnorderedMapVec2.h" + +class Renderer : public IRenderer +{ +public: + virtual void Initialize() override; + virtual void Update(double dt) override; + virtual void Draw(RenderQueueCollection& rq) override; + +private: + //----------------------Variables----------------------// + RenderQueueCollection m_TempRQ; + Texture* m_ErrorTexture; + Texture* m_WhiteTexture; + float m_CameraMoveSpeed; + GLuint m_PickingBuffer; + GLuint m_PickingTexture; + GLuint m_DepthBuffer; + + Model* m_ScreenQuad; + Model* m_UnitQuad; + Model* m_UnitSphere; + + //Temporary + Model* m; + Model* m2; + Model* m3; + Model* MapModel; + + + std::unordered_map m_PickingColorsToModels; + + //----------------------Functions----------------------// + void InitializeWindow(); + void InitializeShaders(); + void InitializeTextures(); + void InitializeFrameBuffers(); + //TODO: Renderer: Remove ModelsToDraw from Renderer. + void ModelsToDraw(); + //TODO: Renderer: Get EnqueueModel and InputUpdate out of renderer + void EnqueueModel(Model* model); + void InputUpdate(double dt); + void PickingPass(); + void DrawScreenQuad(GLuint textureToDraw); + void DrawScene(RenderQueueCollection& rq); + + //--------------------ShaderPrograms-------------------// + ShaderProgram m_BasicForwardProgram; + ShaderProgram m_PickingProgram; + ShaderProgram m_DrawScreenQuadProgram; +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/ShaderProgram.h b/include/Engine/Rendering/ShaderProgram.h new file mode 100644 index 00000000..1b87650e --- /dev/null +++ b/include/Engine/Rendering/ShaderProgram.h @@ -0,0 +1,81 @@ + +#include "../Common.h" +#include "../OpenGL.h" +#include + +class Shader +{ +public: + static GLuint CompileShader(GLenum shaderType, std::string fileName); + + Shader(GLenum shaderType, std::string fileName); + + virtual ~Shader(); + + GLuint Compile(); + + GLenum GetType() const; + std::string GetFileName() const; + GLuint GetHandle() const; + bool IsCompiled() const; +protected: + GLenum m_ShaderType; + std::string m_FileName; + GLint m_ShaderHandle; +}; + +template +class ShaderType : public Shader +{ +public: + ShaderType(std::string fileName) + : Shader(SHADERTYPE, fileName) { } +}; + +class VertexShader : public ShaderType +{ +public: + VertexShader(std::string fileName) + : ShaderType(fileName) { } +}; + +class FragmentShader : public ShaderType +{ +public: + FragmentShader(std::string fileName) + : ShaderType(fileName) { } +}; + +class GeometryShader : public ShaderType +{ +public: + GeometryShader(std::string fileName) + : ShaderType(fileName) { } +}; + +class ComputeShader : public ShaderType +{ +public: + ComputeShader(std::string fileName) + : ShaderType(fileName) { } +}; + +class ShaderProgram +{ +public: + ShaderProgram() + : m_ShaderProgramHandle(0) { } + ~ShaderProgram(); + + void AddShader(std::shared_ptr shader); + void Compile(); + GLuint Link(); + GLuint GetHandle(); + void Bind(); + void Unbind(); + void BindFragDataLocation(int index, std::string name); + +private: + GLuint m_ShaderProgramHandle; + std::vector> m_Shaders; +}; diff --git a/include/Engine/Rendering/Util/ScreenCoords.h b/include/Engine/Rendering/Util/ScreenCoords.h new file mode 100644 index 00000000..51ad1051 --- /dev/null +++ b/include/Engine/Rendering/Util/ScreenCoords.h @@ -0,0 +1,29 @@ +#ifndef ScreenCoords_h__ +#define ScreenCoords_h__ + +#include "../../Common.h" +#include "../../OpenGL.h" +#include "../../GLM.h" +#include "../../Core/Util/Rectangle.h" + +class ScreenCoords +{ +public: + ScreenCoords() = delete; + //Return world position from given screenspace coordinates and depth value in viewspace. + static glm::vec3 ToWorldPos(glm::vec2 screenCoord, float depth, Rectangle resolution, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat); + static glm::vec3 ToWorldPos(float x, float y, float depth, Rectangle resolution, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat); + static glm::vec3 ToWorldPos(glm::vec2 screenCoord, float depth, float screenWidth, float screenHeight, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat); + static glm::vec3 ToWorldPos(float x, float y, float depth, float screenWidth, float screenHeight, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat); + //Return data from the given buffers at the coordinates given in screenspace. Buffer should probably have a texture that covers the screen. + //Data is given as R = x, B = y, and + static glm::vec3 ToPixelData(glm::vec2 screenCoord, GLuint PickDataBuffer, GLuint DepthBuffer); + static glm::vec3 ToPixelData(float x, float y, GLuint PickDataBuffer, GLuint DepthBuffer); + //Return EntityID of the clicked coordinate in given screenspace coordinates. + //EntityID ScreenCoordsToEntityID(glm::vec2 screenCoord, float depth); + +private: + +}; + +#endif \ No newline at end of file diff --git a/include/Engine/Rendering/Util/UnorderedMapVec2.h b/include/Engine/Rendering/Util/UnorderedMapVec2.h new file mode 100644 index 00000000..0247ac9d --- /dev/null +++ b/include/Engine/Rendering/Util/UnorderedMapVec2.h @@ -0,0 +1,23 @@ +#ifndef UnorderedMapVec2_h__ +#define UnorderedMapVec2_h__ + +#include +#include +#include + +template<> +struct std::hash +{ + inline std::size_t operator()(const glm::vec2 &v) const + { + return boost::hash()(v.x) ^ boost::hash()(v.y); + } + + inline bool operator()(const glm::vec2& a, const glm::vec2& b)const + { + return a.x == b.x && a.y == b.y; + } + +}; + +#endif \ No newline at end of file diff --git a/include/Game/Game.h b/include/Game/Game.h index e63e657f..85c0d6c4 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -4,7 +4,7 @@ #include "Core/ResourceManager.h" #include "Core/ConfigFile.h" #include "Core/EventBroker.h" -#include "Rendering/DummyRenderer.h" +#include "Rendering/Renderer.h" #include "Core/InputManager.h" #include "GUI/Frame.h" #include "Core/World.h" diff --git a/resources/Shaders/BasicForward.frag.glsl b/resources/Shaders/BasicForward.frag.glsl new file mode 100644 index 00000000..a7b7cb1f --- /dev/null +++ b/resources/Shaders/BasicForward.frag.glsl @@ -0,0 +1,27 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; + +uniform sampler2D texture0; + + +in VertexData{ + vec3 Position; + vec3 Normal; + vec2 TextureCoordinate; + vec4 DiffuseColor; +}Input; + + +out vec4 fragmentColor; + + +void main() +{ + vec4 texel = texture2D(texture0, Input.TextureCoordinate); + fragmentColor = texel * Input.DiffuseColor; +} + + diff --git a/resources/Shaders/BasicForward.vert.glsl b/resources/Shaders/BasicForward.vert.glsl new file mode 100644 index 00000000..20ab9051 --- /dev/null +++ b/resources/Shaders/BasicForward.vert.glsl @@ -0,0 +1,34 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec3 Tangent; +layout(location = 3) in vec3 BiTangent; +layout(location = 4) in vec2 TextureCoords; +layout(location = 5) in vec4 DiffuseVertexColor; +layout(location = 6) in vec4 SpecularVertexColor; +layout(location = 7) in vec4 BoneIndices1; +layout(location = 8) in vec4 BoneIndices2; +layout(location = 9) in vec4 BoneWeights1; +layout(location = 10) in vec4 BoneWeights2; + +out VertexData{ + vec3 Position; + vec3 Normal; + vec2 TextureCoordinate; + vec4 DiffuseColor; +}Output; + +void main() +{ + gl_Position = P*V*M * vec4(Position, 1.0); + + Output.Position = Position; + Output.TextureCoordinate = TextureCoords; + Output.Normal = Normal; + Output.DiffuseColor = DiffuseVertexColor; +} \ No newline at end of file diff --git a/resources/Shaders/DrawScreenQuad.frag.glsl b/resources/Shaders/DrawScreenQuad.frag.glsl new file mode 100644 index 00000000..17837a7b --- /dev/null +++ b/resources/Shaders/DrawScreenQuad.frag.glsl @@ -0,0 +1,19 @@ +#version 430 + +layout (binding = 0) uniform sampler2D Texture; + +in VertexData{ + vec2 TextureCoordinate; +}Input; + +out vec4 fragmentColor; + +void main() +{ + vec4 texel = texture(Texture, Input.TextureCoordinate); + + fragmentColor = texel; + //fragmentColor = vec4(1,0.5,0.7,1); +} + + diff --git a/resources/Shaders/DrawScreenQuad.vert.glsl b/resources/Shaders/DrawScreenQuad.vert.glsl new file mode 100644 index 00000000..346bc141 --- /dev/null +++ b/resources/Shaders/DrawScreenQuad.vert.glsl @@ -0,0 +1,13 @@ +#version 430 + +layout (location = 0) in vec3 Position; + +out VertexData{ + vec2 TextureCoordinate; +}Output; + +void main() +{ + gl_Position = vec4(Position, 1.0); + Output.TextureCoordinate = (vec2(Position) + 1) / 2; +} \ No newline at end of file diff --git a/resources/Shaders/Picking.frag.glsl b/resources/Shaders/Picking.frag.glsl new file mode 100644 index 00000000..11f529b0 --- /dev/null +++ b/resources/Shaders/Picking.frag.glsl @@ -0,0 +1,19 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; +uniform vec2 PickingColor; + +in VertexData{ + vec3 Position; +}Input; + +out vec4 TextureFragment; + +void main() +{ + TextureFragment = vec4(PickingColor, 0, 1); +} + + diff --git a/resources/Shaders/Picking.vert.glsl b/resources/Shaders/Picking.vert.glsl new file mode 100644 index 00000000..47c0ecd7 --- /dev/null +++ b/resources/Shaders/Picking.vert.glsl @@ -0,0 +1,28 @@ +#version 430 + +uniform mat4 M; +uniform mat4 V; +uniform mat4 P; + +layout(location = 0) in vec3 Position; +layout(location = 1) in vec3 Normal; +layout(location = 2) in vec3 Tangent; +layout(location = 3) in vec3 BiTangent; +layout(location = 4) in vec2 TextureCoords; +layout(location = 5) in vec4 DiffuseVertexColor; +layout(location = 6) in vec4 SpecularVertexColor; +layout(location = 7) in vec4 BoneIndices1; +layout(location = 8) in vec4 BoneIndices2; +layout(location = 9) in vec4 BoneWeights1; +layout(location = 10) in vec4 BoneWeights2; + +out VertexData{ + vec3 Position; +}Output; + +void main() +{ + gl_Position = P*V*M * vec4(Position, 1.0); + + Output.Position = Position; +} \ No newline at end of file diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index 396a34b4..c5067d10 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -54,6 +54,7 @@ file(GLOB SOURCE_FILES_Rendering_Util "${INCLUDE_PATH}/Rendering/Util/*.h" "Rendering/Util/*.cpp" ) + source_group(Rendering FILES ${SOURCE_FILES_Rendering}) source_group(Rendering\\Util FILES ${SOURCE_FILES_Rendering_Util}) @@ -69,6 +70,7 @@ set(SOURCE_FILES #${SOURCE_FILES_Input} ${SOURCE_FILES_GUI} ${SOURCE_FILES_Rendering} + ${SOURCE_FILES_Rendering_Util} ) set(LIBRARIES diff --git a/src/Engine/Rendering/Camera.cpp b/src/Engine/Rendering/Camera.cpp index 8896b6a8..6ddf1c6c 100644 --- a/src/Engine/Rendering/Camera.cpp +++ b/src/Engine/Rendering/Camera.cpp @@ -17,6 +17,12 @@ glm::vec3 Camera::Forward() { return m_Orientation * glm::vec3(0, 0, -1); } + +glm::vec3 Camera::Right() +{ + return m_Orientation * glm::vec3(1, 0, 0); +} + // //glm::vec3 Camera::Right() //{ diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp new file mode 100644 index 00000000..5a9fcba3 --- /dev/null +++ b/src/Engine/Rendering/Renderer.cpp @@ -0,0 +1,362 @@ +#include "Rendering/Renderer.h" + +void Renderer::Initialize() +{ + InitializeWindow(); + + // Create default camera + m_DefaultCamera = new ::Camera((float)m_Resolution.Width / m_Resolution.Height, glm::radians(45.f), 0.01f, 5000.f); + m_DefaultCamera->SetPosition(glm::vec3(0, 0, 10)); + if (m_Camera == nullptr) { + m_Camera = m_DefaultCamera; + } + + glfwSwapInterval(m_VSYNC); + InitializeShaders(); + InitializeTextures(); + InitializeFrameBuffers(); + ModelsToDraw(); +} + +void Renderer::InitializeWindow() +{ + // Initialize GLFW + if (!glfwInit()) { + LOG_ERROR("GLFW: Initialization failed"); + exit(EXIT_FAILURE); + } + + // Create a window + GLFWmonitor* monitor = nullptr; + if (m_Fullscreen) { + monitor = glfwGetPrimaryMonitor(); + } + //glfwWindowHint(GLFW_SAMPLES, 8); + m_Window = glfwCreateWindow(m_Resolution.Width, m_Resolution.Height, "daydream", monitor, nullptr); + if (!m_Window) { + LOG_ERROR("GLFW: Failed to create window"); + exit(EXIT_FAILURE); + } + glfwMakeContextCurrent(m_Window); + + // GL version info + glGetIntegerv(GL_MAJOR_VERSION, &m_GLVersion[0]); + glGetIntegerv(GL_MINOR_VERSION, &m_GLVersion[1]); + m_GLVendor = (GLchar*)glGetString(GL_VENDOR); + std::stringstream ss; + ss << m_GLVendor << " OpenGL " << m_GLVersion[0] << "." << m_GLVersion[1]; +#ifdef DEBUG + ss << " DEBUG"; +#endif + LOG_INFO(ss.str().c_str()); + glfwSetWindowTitle(m_Window, ss.str().c_str()); + + // Initialize GLEW + if (glewInit() != GLEW_OK) { + LOG_ERROR("GLEW: Initialization failed"); + exit(EXIT_FAILURE); + } +} + +void Renderer::InitializeShaders() +{ + m_BasicForwardProgram.AddShader(std::shared_ptr(new VertexShader("Shaders/BasicForward.vert.glsl"))); + m_BasicForwardProgram.AddShader(std::shared_ptr(new FragmentShader("Shaders/BasicForward.frag.glsl"))); + m_BasicForwardProgram.Compile(); + m_BasicForwardProgram.Link(); + + m_PickingProgram.AddShader(std::shared_ptr(new VertexShader("Shaders/Picking.vert.glsl"))); + m_PickingProgram.AddShader(std::shared_ptr(new FragmentShader("Shaders/Picking.frag.glsl"))); + m_PickingProgram.Compile(); + m_PickingProgram.BindFragDataLocation(0, "TextureFragment"); + m_PickingProgram.Link(); + + m_DrawScreenQuadProgram.AddShader(std::shared_ptr(new VertexShader("Shaders/DrawScreenQuad.vert.glsl"))); + m_DrawScreenQuadProgram.AddShader(std::shared_ptr(new FragmentShader("Shaders/DrawScreenQuad.frag.glsl"))); + m_DrawScreenQuadProgram.Compile(); + m_DrawScreenQuadProgram.Link(); + +} + +void Renderer::ModelsToDraw() +{ + + m = ResourceManager::Load("Models/ScaleWidget.obj"); + EnqueueModel(m); + m2 = ResourceManager::Load("Models/TranslationWidget.obj"); + EnqueueModel(m2); + m3 = ResourceManager::Load("Models/RotationWidget.obj"); + EnqueueModel(m3); + + m_UnitSphere = ResourceManager::Load("Models/Core/UnitSphere.obj"); + EnqueueModel(m_UnitSphere); + m_UnitQuad = ResourceManager::Load("Models/Core/UnitQuad.obj"); + m_ScreenQuad = ResourceManager::Load("Models/Core/ScreenQuad.obj"); + + MapModel = ResourceManager::Load("Models/DummyScene.obj"); + EnqueueModel(MapModel); +} + +void Renderer::EnqueueModel(Model* model) +{ + for (auto texGroup : model->TextureGroups) + { + ModelJob job; + job.TextureID = (texGroup.Texture) ? texGroup.Texture->ResourceID : 0; + job.DiffuseTexture = texGroup.Texture.get(); + job.NormalTexture = texGroup.NormalMap.get(); + job.SpecularTexture = texGroup.SpecularMap.get(); + job.Model = model; + job.StartIndex = texGroup.StartIndex; + job.EndIndex = texGroup.EndIndex; + job.ModelMatrix = model->m_Matrix; + //job.ModelMatrix = modelMatrix * model->m_Matrix; TODO: Render: Make sure modelMatrix work + //job.Color = modelComponent->Color; TODO: Render: Take color from kd in .mtl or a value from modelcomponent. + job.Color = glm::vec4(1.f); + + //TODO: Render: Skeleton animations + //if (model->m_Skeleton != nullptr && animationComponent != nullptr) { + // job.Skeleton = model->m_Skeleton; + // job.AnimationName = animationComponent->Name; + // job.AnimationTime = animationComponent->Time; + // job.NoRootMotion = animationComponent->NoRootMotion; + //} + + m_TempRQ.Forward.Add(job); + } +} + +void Renderer::InputUpdate(double dt) +{ + glm::vec3 m_Position = m_Camera->Position(); + if (glfwGetKey(m_Window, GLFW_KEY_O) == GLFW_PRESS) + { + m_Position = glm::vec3(0.f, 0.f, 5.f); + } + if (glfwGetKey(m_Window, GLFW_KEY_W) == GLFW_PRESS) + { + m_Position += m_Camera->Forward() * m_CameraMoveSpeed * (float)dt; + } + if (glfwGetKey(m_Window, GLFW_KEY_S) == GLFW_PRESS) + { + m_Position -= m_Camera->Forward() * m_CameraMoveSpeed * (float)dt; + } + if (glfwGetKey(m_Window, GLFW_KEY_D) == GLFW_PRESS) + { + m_Position += m_Camera->Right() * m_CameraMoveSpeed * (float)dt; + } + if (glfwGetKey(m_Window, GLFW_KEY_A) == GLFW_PRESS) + { + m_Position -= m_Camera->Right() * m_CameraMoveSpeed * (float)dt; + } + if (glfwGetKey(m_Window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) + { + m_CameraMoveSpeed = 5.f; + } + else { + m_CameraMoveSpeed = 0.5f; + } + + + static double mousePosX, mousePosY; + glfwGetCursorPos(m_Window, &mousePosX, &mousePosY); + if (glfwGetMouseButton(m_Window, GLFW_MOUSE_BUTTON_1) == GLFW_PRESS) { + glm::vec3 data = ScreenCoords::ToPixelData(mousePosX, m_Resolution.Height - mousePosY, m_PickingBuffer, m_DepthBuffer); + glm::vec2 color = glm::vec2(data); + float depth = data.z; + + glm::vec3 viewPos = ScreenCoords::ToWorldPos(mousePosX, m_Resolution.Height - mousePosY, depth, m_Resolution, m_Camera->ProjectionMatrix(), m_Camera->ViewMatrix()); + // glm::vec3 worldPos = glm::vec3(glm::inverse(m_Camera->ViewMatrix()) * glm::vec4(viewPos, 1.f)); + + //printf("R: %f, G: %f, Depth: %f\n", color.r, color.g, depth); + //printf("view: x: %f, y: %f z: %f, Length: %f\n\n", viewPos.x, viewPos.y, viewPos.z, glm::length(viewPos)); + + if (color != glm::vec2(0, 0)) { + const Model* pickModel = m_PickingColorsToModels[color]; + + } + } + + if (glfwGetKey(m_Window, GLFW_KEY_SPACE) == GLFW_PRESS) { + + + double deltaX, deltaY; + deltaX = mousePosX - (float)Resolution().Width / 2; + deltaY = mousePosY - (float)Resolution().Height / 2; + + float rotationY = -deltaY / 300.f; + float rotationX = -deltaX / 300.f; + glm::quat orientation = m_Camera->Orientation(); + + + orientation = orientation * glm::angleAxis(rotationY, glm::vec3(1, 0, 0)); + orientation = glm::angleAxis(rotationX, glm::vec3(0, 1, 0)) * orientation; + + m_Camera->SetOrientation(orientation); + + glfwSetCursorPos(m_Window, Resolution().Width / 2, Resolution().Height / 2); + } + m_Camera->SetPosition(m_Position); +} + +void Renderer::Update(double dt) +{ + InputUpdate(dt); +} + +void Renderer::Draw(RenderQueueCollection& rq) +{ + //TODO: Renderer: Kanske borde vara längst upp i update. + PickingPass(); + DrawScreenQuad(m_PickingTexture); + //DrawScreenQuad(m_DepthBuffer); + //DrawScene(rq); + glfwSwapBuffers(m_Window); +} + +void Renderer::DrawScene(RenderQueueCollection& rq) +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + //TODO: Render: Clean up draw code + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + glClearColor(255.f / 255, 163.f / 255, 176.f / 255, 0.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + //TODO: Render: Add code for more jobs than modeljobs. + for (auto &job : m_TempRQ.Forward) { + auto modelJob = std::dynamic_pointer_cast(job); + if (modelJob) { + GLuint ShaderHandle = m_BasicForwardProgram.GetHandle(); + + m_BasicForwardProgram.Bind(); + //TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms + glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(glm::mat4(1))); + glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_Camera->ViewMatrix())); + glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_Camera->ProjectionMatrix())); + + //TODO: Renderer: bättre textur felhantering samt fler texturer stöd + if (modelJob->DiffuseTexture != nullptr) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, modelJob->DiffuseTexture->m_Texture); + } else { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, m_WhiteTexture->m_Texture); + } + + glBindVertexArray(modelJob->Model->VAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer); + glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex); + + continue; + } + } +} + +void Renderer::PickingPass() +{ + glBindFramebuffer(GL_FRAMEBUFFER, m_PickingBuffer); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + glClearColor(0.f, 0.f, 0.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + int r = 30; + int g = 0; + //TODO: Render: Add code for more jobs than modeljobs. + + + GLuint ShaderHandle = m_PickingProgram.GetHandle(); + m_PickingProgram.Bind(); + + for (auto &job : m_TempRQ.Forward) { + auto modelJob = std::dynamic_pointer_cast(job); + + if (modelJob) { + glm::vec2 pickColor = glm::vec2(r/255.f, g/255.f); + m_PickingColorsToModels[pickColor] = modelJob->Model; + + //Render picking stuff + //TODO: Kolla upp "header/include/common" shader saken så man slipper skicka in asmycket uniforms + glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(glm::mat4(1))); + glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "V"), 1, GL_FALSE, glm::value_ptr(m_Camera->ViewMatrix())); + glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "P"), 1, GL_FALSE, glm::value_ptr(m_Camera->ProjectionMatrix())); + glUniform2fv(glGetUniformLocation(ShaderHandle, "PickingColor"), 1, glm::value_ptr(pickColor)); + + glBindVertexArray(modelJob->Model->VAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, modelJob->Model->ElementBuffer); + glDrawElementsBaseVertex(GL_TRIANGLES, modelJob->EndIndex - modelJob->StartIndex + 1, GL_UNSIGNED_INT, 0, modelJob->StartIndex); + r+=50; + if(r > 255) { + r = 0; + g+=50; + } + } + } + +} + + +void Renderer::DrawScreenQuad(GLuint textureToDraw) +{ + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + glClearColor(0.f, 0.f, 0.f, 1.f); + glClear(GL_COLOR_BUFFER_BIT); + + + m_DrawScreenQuadProgram.Bind(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textureToDraw); + + glBindVertexArray(m_ScreenQuad->VAO); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ScreenQuad->ElementBuffer); + glDrawElementsBaseVertex(GL_TRIANGLES, m_ScreenQuad->TextureGroups[0].EndIndex - m_ScreenQuad->TextureGroups[0].StartIndex +1 + , GL_UNSIGNED_INT, 0, m_ScreenQuad->TextureGroups[0].StartIndex); +} + + +void Renderer::InitializeTextures() +{ + m_ErrorTexture=ResourceManager::Load("Textures/Core/ErrorTexture.png"); + m_WhiteTexture=ResourceManager::Load("Textures/Core/Blank.png"); + + glGenTextures(1, &m_PickingTexture); + glBindTexture(GL_TEXTURE_2D, m_PickingTexture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, m_Resolution.Width, m_Resolution.Height, 0, GL_RGB, GL_FLOAT, NULL);//TODO: Renderer: Fix the precision and Resolution + GLERROR("m_PickingTexture initialization failed"); +} + +void Renderer::InitializeFrameBuffers()//TODO: Renderer: Get this to a better location, as its really big +{ + glGenRenderbuffers(1, &m_DepthBuffer); + glBindRenderbuffer(GL_RENDERBUFFER, m_DepthBuffer); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, m_Resolution.Width, m_Resolution.Height); + + + glGenFramebuffers(1, &m_PickingBuffer); + glBindFramebuffer(GL_FRAMEBUFFER, m_PickingBuffer); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_DepthBuffer); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_PickingTexture, 0); + GLenum PickingBufferTextures[] = { GL_COLOR_ATTACHMENT0 }; + glDrawBuffers(1, PickingBufferTextures); + + if (GLenum fbStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + LOG_ERROR("m_FbDeferred2 incomplete: 0x%x\n", fbStatus); + exit(EXIT_FAILURE); + } + + +} \ No newline at end of file diff --git a/src/Engine/Rendering/ShaderProgram.cpp b/src/Engine/Rendering/ShaderProgram.cpp new file mode 100644 index 00000000..f713cd03 --- /dev/null +++ b/src/Engine/Rendering/ShaderProgram.cpp @@ -0,0 +1,163 @@ +#include "Rendering/ShaderProgram.h" + +GLuint Shader::CompileShader(GLenum shaderType, std::string fileName) +{ + LOG_INFO("Compiling shader \"%s\"", fileName.c_str()); + + std::string shaderFile; + std::ifstream in(fileName, std::ios::in); + if (!in) { + LOG_ERROR("Error: Failed to open shader file \"%s\"", fileName.c_str()); + return 0; + } + in.seekg(0, std::ios::end); + shaderFile.resize((int)in.tellg()); + in.seekg(0, std::ios::beg); + in.read(&shaderFile[0], shaderFile.size()); + in.close(); + + GLuint shader = glCreateShader(shaderType); + if (GLERROR("glCreateShader")) + return 0; + + const GLchar* shaderFiles = shaderFile.c_str(); + const GLint length = shaderFile.length(); + glShaderSource(shader, 1, &shaderFiles, &length); + if (GLERROR("glShaderSource")) + return 0; + + glCompileShader(shader); + + GLint compileStatus; + glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus); + if (compileStatus != GL_TRUE) { + LOG_ERROR("Shader compilation failed"); + GLsizei infoLogLength; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); + GLchar* infolog = new GLchar[infoLogLength]; + glGetShaderInfoLog(shader, infoLogLength, &infoLogLength, infolog); + LOG_ERROR(infolog); + delete[] infolog; + } + + if (GLERROR("glCompileShader")) + return 0; + + return shader; +} + +Shader::Shader(GLenum shaderType, std::string fileName) : m_ShaderType(shaderType), m_FileName(fileName) +{ + m_ShaderHandle = 0; +} + +Shader::~Shader() +{ + if (m_ShaderHandle != 0) { + glDeleteShader(m_ShaderHandle); + } +} + +GLuint Shader::Compile() +{ + m_ShaderHandle = CompileShader(m_ShaderType, m_FileName); + return m_ShaderHandle; +} + +GLenum Shader::GetType() const +{ + return m_ShaderType; +} + +std::string Shader::GetFileName() const +{ + return m_FileName; +} + +GLuint Shader::GetHandle() const +{ + return m_ShaderHandle; +} + +bool Shader::IsCompiled() const +{ + return m_ShaderHandle != 0; +} + +ShaderProgram::~ShaderProgram() +{ + if (m_ShaderProgramHandle != 0) { + glDeleteProgram(m_ShaderProgramHandle); + } +} + +void ShaderProgram::AddShader(std::shared_ptr shader) +{ + m_Shaders.push_back(shader); +} + +void ShaderProgram::Compile() +{ + if (m_ShaderProgramHandle == 0) + { + m_ShaderProgramHandle = glCreateProgram(); + } + + for (auto &shader : m_Shaders) + { + if (!shader->IsCompiled()) + { + shader->Compile(); + } + } +} + +GLuint ShaderProgram::Link() +{ + if (m_Shaders.size() == 0) + { + LOG_ERROR("Failed to link shader program: No shaders bound"); + return 0; + } + + LOG_INFO("Linking shader program"); + + for (auto &shader : m_Shaders) + { + glAttachShader(m_ShaderProgramHandle, shader->GetHandle()); + } + glLinkProgram(m_ShaderProgramHandle); + if (GLERROR("glLinkProgram")) + return 0; + m_Shaders.clear(); + + return m_ShaderProgramHandle; +} + +GLuint ShaderProgram::GetHandle() +{ + return m_ShaderProgramHandle; +} + +void ShaderProgram::Bind() +{ + if (m_ShaderProgramHandle == 0) + return; + + glUseProgram(m_ShaderProgramHandle); +} + +void ShaderProgram::Unbind() +{ + glActiveShaderProgram(0, 0); +} + +void ShaderProgram::BindFragDataLocation(int index, std::string name) +{ + + if (m_ShaderProgramHandle == 0) + return; + + glBindFragDataLocation(m_ShaderProgramHandle, index, name.c_str()); +} + diff --git a/src/Engine/Rendering/Util/ScreenCoords.cpp b/src/Engine/Rendering/Util/ScreenCoords.cpp new file mode 100644 index 00000000..103e576c --- /dev/null +++ b/src/Engine/Rendering/Util/ScreenCoords.cpp @@ -0,0 +1,50 @@ +#include "Rendering/Util/ScreenCoords.h" + +glm::vec3 ScreenCoords::ToWorldPos(float x, float y, float depth, float screenWidth, float screenHeight, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat) +{ + glm::vec3 ndc; + ndc.x = (x / screenWidth)*2.f - 1.f; + ndc.y = (y / screenHeight)*2.f - 1.f; + ndc.z = depth*2.f - 1.f; + glm::vec4 clipSpace = glm::vec4(ndc, 1.0f); + glm::vec4 EyeSpace = glm::inverse(cameraProjectionMat) * clipSpace; + glm::vec4 WorldSpace = glm::inverse(cameraViewMat) * EyeSpace; + WorldSpace = glm::vec4(glm::vec3(WorldSpace) / WorldSpace.w, 1.f); + + return glm::vec3(WorldSpace); +} + +glm::vec3 ScreenCoords::ToWorldPos(glm::vec2 screenCoord, float depth, Rectangle resolution, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat) +{ + return ToWorldPos(screenCoord.x, screenCoord.y, depth, resolution.Width, resolution.Height, cameraProjectionMat, cameraViewMat); +} + +glm::vec3 ScreenCoords::ToWorldPos(float x, float y, float depth, Rectangle resolution, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat) +{ + return ToWorldPos(x, y, depth, resolution.Width, resolution.Height, cameraProjectionMat, cameraViewMat); +} + +glm::vec3 ScreenCoords::ToWorldPos(glm::vec2 screenCoord, float depth, float screenWidth, float screenHeight, glm::mat4 cameraProjectionMat, glm::mat4 cameraViewMat) +{ + return ToWorldPos(screenCoord.x, screenCoord.y, depth, screenWidth, screenHeight, cameraProjectionMat, cameraViewMat); +} + +glm::vec3 ScreenCoords::ToPixelData(float x, float y, GLuint PickDataBuffer, GLuint DepthBuffer) +{ + glBindFramebuffer(GL_FRAMEBUFFER, PickDataBuffer); + glm::vec2 pixelData; + glReadPixels(x, y, 1, 1, GL_RG, GL_FLOAT, &pixelData); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glBindFramebuffer(GL_FRAMEBUFFER, DepthBuffer); + float depthData; + glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depthData); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return glm::vec3(pixelData, depthData); +} + +glm::vec3 ScreenCoords::ToPixelData(glm::vec2 screenCoord, GLuint PickDataBuffer, GLuint DepthBuffer) +{ + return ToPixelData(screenCoord.x, screenCoord.y, PickDataBuffer, DepthBuffer); +} diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index f6421547..10d19baf 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -4,6 +4,8 @@ Game::Game(int argc, char* argv[]) { ResourceManager::RegisterType("ConfigFile"); + ResourceManager::RegisterType("Model"); + ResourceManager::RegisterType("Texture"); m_Config = ResourceManager::Load("Config.ini"); LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); @@ -12,7 +14,7 @@ Game::Game(int argc, char* argv[]) m_EventBroker = new EventBroker(); // Create the renderer - m_Renderer = new DummyRenderer(); + m_Renderer = new Renderer(); m_Renderer->SetFullscreen(m_Config->Get("Video.Fullscreen", false)); m_Renderer->SetVSYNC(m_Config->Get("Video.VSYNC", false)); m_Renderer->SetResolution(Rectangle( @@ -51,8 +53,10 @@ void Game::Tick() m_EventBroker->Swap(); m_InputManager->Update(dt); + m_Renderer->Update(dt); m_EventBroker->Swap(); + //TODO: Render: This is not used, but will be used later when we dont add models to RQ in renderer. RenderQueueCollection rq; m_Renderer->Draw(rq); diff --git a/tools/deploy.bat b/tools/deploy.bat index cdab1c20..5ef074ef 100755 --- a/tools/deploy.bat +++ b/tools/deploy.bat @@ -18,8 +18,6 @@ RMDIR "%DeployLocation%\Schema" MKLINK "%DeployLocation%\Schema\" "resources\Schema" /J :: Shaders RMDIR /S /Q "%DeployLocation%\Shaders" -MKDIR "%DeployLocation%\Shaders" -MKLINK "%DeployLocation%\Shaders\" "resources\Shaders" /J MKLINK "%DeployLocation%\Shaders\" "resources\Shaders" /J :: Configuration files MKLINK "%DeployLocation%\DefaultConfig.ini" "resources\DefaultConfig.ini" /H