diff --git a/include/Engine/Rendering/EPicking.h b/include/Engine/Rendering/EPicking.h new file mode 100644 index 00000000..df75854a --- /dev/null +++ b/include/Engine/Rendering/EPicking.h @@ -0,0 +1,69 @@ +#ifndef Events_Picking_h__ +#define Events_Picking_h__ + +#include "../OpenGL.h" +#include "../GLM.h" + +#include "../Core/EventBroker.h" +#include "Util/ScreenCoords.h" +#include "FrameBuffer.h" +#include "../Core/Entity.h" +#include "Util/UnorderedMapVec2.h" + +namespace Events +{ + +/** Thrown Every frame, use functions to pick*/ +struct Picking : Event +{ +public: + Picking(FrameBuffer* pickingBuffer, GLuint* depthBuffer, glm::mat4 projectionMatrix, glm::mat4 viewMatrix, Rectangle resolution, const std::unordered_map* pickingColorsToEntity) + : PickingBuffer(pickingBuffer) + , DepthBuffer(depthBuffer) + , ProjectionMatrix(projectionMatrix) + , ViewMatrix(viewMatrix) + , Resolution(resolution) + , PickingColorsToEntity(pickingColorsToEntity) + { } + + + + struct PickData + { + //Picked Entity + EntityID Entity; + //World position of the "pick" + glm::vec3 Position; + }; + + PickData Pick(glm::vec2 screenCoord) const + { + PickData pickData; + + ScreenCoords::PixelData data = ScreenCoords::ToPixelData(screenCoord, PickingBuffer, *DepthBuffer); + + auto it = PickingColorsToEntity->find(glm::vec2(data.Color[0], data.Color[1])); + if (it != PickingColorsToEntity->end()) { + pickData.Entity = it->second; + } else { + pickData.Entity = -1; + } + pickData.Position = ScreenCoords::ToWorldPos(screenCoord.x, Resolution.Width - screenCoord.y, data.Depth, Resolution, ProjectionMatrix, ViewMatrix); + + return pickData; + } + + +private: + FrameBuffer* PickingBuffer; + GLuint* DepthBuffer; + const glm::mat4 ProjectionMatrix; + const glm::mat4 ViewMatrix; + const Rectangle Resolution; + const std::unordered_map* PickingColorsToEntity; + +}; + +} + +#endif diff --git a/include/Engine/Rendering/Renderer.h b/include/Engine/Rendering/Renderer.h index b1b76468..76de0818 100644 --- a/include/Engine/Rendering/Renderer.h +++ b/include/Engine/Rendering/Renderer.h @@ -11,15 +11,24 @@ #include "FrameBuffer.h" #include "../Core/World.h" +#include "../Core/EventBroker.h" +#include "EPicking.h" + class Renderer : public IRenderer { public: + Renderer(EventBroker* eventBroker) + : m_EventBroker(eventBroker) + { } + virtual void Initialize() override; virtual void Update(double dt) override; virtual void Draw(RenderQueueCollection& rq) override; private: //----------------------Variables----------------------// + EventBroker* m_EventBroker; + Texture* m_ErrorTexture; Texture* m_WhiteTexture; float m_CameraMoveSpeed; @@ -31,8 +40,6 @@ private: Model* m_UnitQuad; Model* m_UnitSphere; - - std::unordered_map m_PickingColorsToEntity; //----------------------Functions----------------------// diff --git a/include/Engine/Rendering/Util/ScreenCoords.h b/include/Engine/Rendering/Util/ScreenCoords.h index 22c5b9e0..92e92bdc 100644 --- a/include/Engine/Rendering/Util/ScreenCoords.h +++ b/include/Engine/Rendering/Util/ScreenCoords.h @@ -11,6 +11,13 @@ class ScreenCoords { public: ScreenCoords() = delete; + + struct PixelData + { + int Color[2]; + float Depth; + }; + //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); @@ -18,8 +25,8 @@ public: 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, FrameBuffer* PickDataBuffer, GLuint DepthBuffer); - static glm::vec3 ToPixelData(float x, float y, FrameBuffer* PickDataBuffer, GLuint DepthBuffer); + static PixelData ToPixelData(glm::vec2 screenCoord, FrameBuffer* PickDataBuffer, GLuint DepthBuffer); + static PixelData ToPixelData(float x, float y, FrameBuffer* PickDataBuffer, GLuint DepthBuffer); //Return EntityID of the clicked coordinate in given screenspace coordinates. //EntityID ScreenCoordsToEntityID(glm::vec2 screenCoord, float depth); diff --git a/resources/Shaders/Picking.frag.glsl b/resources/Shaders/Picking.frag.glsl index 11f529b0..8c95ead3 100644 --- a/resources/Shaders/Picking.frag.glsl +++ b/resources/Shaders/Picking.frag.glsl @@ -13,7 +13,7 @@ out vec4 TextureFragment; void main() { - TextureFragment = vec4(PickingColor, 0, 1); + TextureFragment = vec4(PickingColor/255, 0, 1); } diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index f39580b7..6f4235d2 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -3,7 +3,6 @@ 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)); @@ -116,23 +115,6 @@ void Renderer::InputUpdate(double dt) 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)) { - EntityID pickedEntity = m_PickingColorsToEntity[color]; - printf("Picked Entity: %i", pickedEntity); - - } - } if (glfwGetKey(m_Window, GLFW_KEY_SPACE) == GLFW_PRESS) { @@ -158,7 +140,8 @@ void Renderer::InputUpdate(double dt) void Renderer::Update(double dt) { - InputUpdate(dt); + m_EventBroker->Process(); + InputUpdate(dt); } @@ -213,10 +196,12 @@ void Renderer::DrawScene(RenderQueueCollection& rq) continue; } } + GLERROR("DrawScene Error"); } void Renderer::PickingPass(RenderQueueCollection& rq) { + m_PickingColorsToEntity.clear(); m_PickingBuffer.Bind(); glEnable(GL_DEPTH_TEST); @@ -225,7 +210,7 @@ void Renderer::PickingPass(RenderQueueCollection& rq) glClearColor(0.f, 0.f, 0.f, 1.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - int r = 30; + int r = 1; int g = 0; //TODO: Render: Add code for more jobs than modeljobs. @@ -237,8 +222,18 @@ void Renderer::PickingPass(RenderQueueCollection& rq) auto modelJob = std::dynamic_pointer_cast(job); if (modelJob) { - glm::vec2 pickColor = glm::vec2(r/255.f, g/255.f); - m_PickingColorsToEntity[pickColor] = modelJob->Entity; + //--------------- + //TODO: Renderer: IMPORTANT: Fixa detta så det inte loopar igenom listan varje frame. + //--------------- + int pickColor[2] = { r, g }; + for (auto i : m_PickingColorsToEntity) { + if(modelJob->Entity == i.second) { + pickColor[0] = i.first.x; + pickColor[1] = i.first.y; + r -= 1; + } + } + m_PickingColorsToEntity[glm::vec2(pickColor[0], pickColor[1])] = modelJob->Entity; //Render picking stuff @@ -246,19 +241,32 @@ void Renderer::PickingPass(RenderQueueCollection& rq) glUniformMatrix4fv(glGetUniformLocation(ShaderHandle, "M"), 1, GL_FALSE, glm::value_ptr(modelJob->ModelMatrix)); 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)); + glUniform2fv(glGetUniformLocation(ShaderHandle, "PickingColor"), 1, glm::value_ptr(glm::vec2(pickColor[0], pickColor[1]))); 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; + r += 1; if(r > 255) { r = 0; - g+=50; + g += 1; } } } m_PickingBuffer.Unbind(); + GLERROR("PickingPass Error"); + + //Publish pick event every frame with the pick data that can be picked by the event + Events::Picking pickEvent = Events::Picking( + &m_PickingBuffer, + &m_DepthBuffer, + m_Camera->ProjectionMatrix(), + m_Camera->ViewMatrix(), + m_Resolution, + &m_PickingColorsToEntity); + + m_EventBroker->Publish(pickEvent); + } @@ -300,7 +308,7 @@ void Renderer::InitializeTextures() */ GenerateTexture(&m_PickingTexture, GL_CLAMP_TO_BORDER, GL_LINEAR, - glm::vec2(m_Resolution.Width, m_Resolution.Height), GL_RG8, GL_RG, GL_FLOAT); + glm::vec2(m_Resolution.Width, m_Resolution.Height), GL_RG8, GL_RG, GL_UNSIGNED_BYTE); } void Renderer::GenerateTexture(GLuint* texture, GLenum wrapping, GLenum filtering, glm::vec2 dimensions, GLint internalFormat, GLint format, GLenum type) diff --git a/src/Engine/Rendering/Util/ScreenCoords.cpp b/src/Engine/Rendering/Util/ScreenCoords.cpp index aad94d67..36dd08a1 100644 --- a/src/Engine/Rendering/Util/ScreenCoords.cpp +++ b/src/Engine/Rendering/Util/ScreenCoords.cpp @@ -29,22 +29,31 @@ glm::vec3 ScreenCoords::ToWorldPos(glm::vec2 screenCoord, float depth, float scr return ToWorldPos(screenCoord.x, screenCoord.y, depth, screenWidth, screenHeight, cameraProjectionMat, cameraViewMat); } -glm::vec3 ScreenCoords::ToPixelData(float x, float y, FrameBuffer* PickDataBuffer, GLuint DepthBuffer) +ScreenCoords::PixelData ScreenCoords::ToPixelData(float x, float y, FrameBuffer* PickDataBuffer, GLuint DepthBuffer) { PickDataBuffer->Bind(); - glm::vec2 pixelData; - glReadPixels(x, y, 1, 1, GL_RG, GL_FLOAT, &pixelData); + unsigned char pdata[2]; + glReadPixels(x, y, 1, 1, GL_RG, GL_UNSIGNED_BYTE, &pdata); PickDataBuffer->Unbind(); + 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); + PixelData p; + p.Color[0] = (int)pdata[0]; + p.Color[1] = (int)pdata[1]; + p.Depth = depthData; + + GLERROR("ScreenCoords::ToPixelData Error"); + + return p; } -glm::vec3 ScreenCoords::ToPixelData(glm::vec2 screenCoord, FrameBuffer* PickDataBuffer, GLuint DepthBuffer) +ScreenCoords::PixelData ScreenCoords::ToPixelData(glm::vec2 screenCoord, FrameBuffer* PickDataBuffer, GLuint DepthBuffer) { return ToPixelData(screenCoord.x, screenCoord.y, PickDataBuffer, DepthBuffer); } + diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index ed7723b1..44533ac0 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -16,7 +16,7 @@ Game::Game(int argc, char* argv[]) m_RenderQueueFactory = new RenderQueueFactory(); // Create the renderer - m_Renderer = new Renderer(); + m_Renderer = new Renderer(m_EventBroker); m_Renderer->SetFullscreen(m_Config->Get("Video.Fullscreen", false)); m_Renderer->SetVSYNC(m_Config->Get("Video.VSYNC", false)); m_Renderer->SetResolution(Rectangle::Rectangle( @@ -80,6 +80,7 @@ void Game::Tick() // DO SYSTEM SHIT HERE m_EventBroker->Process(); testTick(dt); + m_Renderer->Update(dt); m_RenderQueueFactory->Update(m_World); m_Renderer->Update(dt);