diff options
-rw-r--r-- | cwd/shaders/fbo.fs | 11 | ||||
-rw-r--r-- | cwd/shaders/fbo.vs | 11 | ||||
-rw-r--r-- | src/Framebuffer.cpp | 125 | ||||
-rw-r--r-- | src/Framebuffer.hpp | 29 | ||||
-rw-r--r-- | src/Render.cpp | 46 | ||||
-rw-r--r-- | src/Render.hpp | 5 |
6 files changed, 214 insertions, 13 deletions
diff --git a/cwd/shaders/fbo.fs b/cwd/shaders/fbo.fs new file mode 100644 index 0000000..df624b3 --- /dev/null +++ b/cwd/shaders/fbo.fs @@ -0,0 +1,11 @@ +#version 330 core + +out vec4 FragColor; +in vec2 TexCoords; + +uniform sampler2D inputTexture; + +void main() +{ + FragColor = texture(inputTexture, TexCoords); +}
\ No newline at end of file diff --git a/cwd/shaders/fbo.vs b/cwd/shaders/fbo.vs new file mode 100644 index 0000000..e1e8966 --- /dev/null +++ b/cwd/shaders/fbo.vs @@ -0,0 +1,11 @@ +#version 330 core +layout (location = 0) in vec2 Pos; +layout (location = 1) in vec2 TextureCoords; + +out vec2 TexCoords; + +void main() +{ + gl_Position = vec4(Pos.x, Pos.y, 0.0, 1.0); + TexCoords = TextureCoords; +}
\ No newline at end of file diff --git a/src/Framebuffer.cpp b/src/Framebuffer.cpp new file mode 100644 index 0000000..7127a57 --- /dev/null +++ b/src/Framebuffer.cpp @@ -0,0 +1,125 @@ +#include "Framebuffer.hpp" +#include "Shader.hpp" +#include <string> +#include "Utility.hpp" + +GLuint quadVao, quadVbo; +Shader *quadShader = nullptr; + +Framebuffer::Framebuffer(unsigned int width, unsigned int height, bool createDepthStencilBuffer) : width(width), height(height) { + if (quadShader == nullptr) { + float quadVertices[] = { + // positions // texCoords + -1.0f, 1.0f, 0.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 0.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + + -1.0f, 1.0f, 0.0f, 1.0f, + 1.0f, -1.0f, 1.0f, 0.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + + glGenVertexArrays(1, &quadVao); + glGenBuffers(1, &quadVbo); + glBindVertexArray(quadVao); + glBindBuffer(GL_ARRAY_BUFFER, quadVbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float))); + quadShader = new Shader("./shaders/fbo.vs", "./shaders/fbo.fs"); + quadShader->Use(); + glUniform1i(glGetUniformLocation(quadShader->Program, "inputTexture"), 1); + glActiveTexture(GL_TEXTURE1); + glCheckError(); + } + + glGenTextures(1, &texColor); + glBindTexture(GL_TEXTURE_2D, texColor); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glCheckError(); + + if (createDepthStencilBuffer) { + glGenRenderbuffers(1, &rboDepthStencil); + glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + } + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texColor, 0); + if(createDepthStencilBuffer) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rboDepthStencil); + glCheckError(); + + GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) + throw std::runtime_error("Failed to initialize framebuffer: " + std::to_string(framebufferStatus)); +} + +Framebuffer::~Framebuffer() { + if (rboDepthStencil) + glDeleteRenderbuffers(1, &rboDepthStencil); + if (texColor) + glDeleteTextures(1, &texColor); + + glDeleteFramebuffers(1, &fbo); +} + +void Framebuffer::Activate() { + glViewport(0, 0, width, height); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); +} + +void Framebuffer::RenderTo(Framebuffer &target) { + glBindFramebuffer(GL_FRAMEBUFFER, target.fbo); + glViewport(0, 0, target.width, target.height); + glBindVertexArray(quadVao); + glUseProgram(quadShader->Program); + glBindTexture(GL_TEXTURE_2D, texColor); + glDrawArrays(GL_TRIANGLES, 0, 6); +} + +void Framebuffer::Resize(unsigned int newWidth, unsigned int newHeight) { + width = newWidth; + height = newHeight; + if (texColor) { + glBindTexture(GL_TEXTURE_2D, texColor); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, newWidth, newHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } + if (rboDepthStencil) { + glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); + } +} + +Framebuffer &Framebuffer::GetDefault() +{ + static char fboDefaultData[sizeof(Framebuffer)]; + static Framebuffer *fboDefault = nullptr; + if (fboDefault == nullptr) { + fboDefault = reinterpret_cast<Framebuffer*>(fboDefaultData); + fboDefault->fbo = 0; + fboDefault->width = 1; + fboDefault->height = 1; + fboDefault->texColor = 0; + fboDefault->rboDepthStencil = 0; + } + return *fboDefault; +} + +void Framebuffer::Clear(bool color, bool depth, bool stencil) +{ + Activate(); + GLbitfield clearBits = 0; + if (color) + clearBits |= GL_COLOR_BUFFER_BIT; + if (depth) + clearBits |= GL_DEPTH_BUFFER_BIT; + if (stencil) + clearBits |= GL_STENCIL_BUFFER_BIT; + glClear(clearBits); +} diff --git a/src/Framebuffer.hpp b/src/Framebuffer.hpp new file mode 100644 index 0000000..6e0d33e --- /dev/null +++ b/src/Framebuffer.hpp @@ -0,0 +1,29 @@ +#pragma once + +#include <gl/glew.h> + +class Framebuffer { + unsigned int width, height; + GLuint fbo, texColor = 0, rboDepthStencil = 0; +public: + Framebuffer(unsigned int width, unsigned int height, bool createDepthStencilBuffer); + ~Framebuffer(); + Framebuffer(const Framebuffer&) = delete; + Framebuffer(Framebuffer &&) = delete; + Framebuffer &operator=(const Framebuffer &) = delete; + Framebuffer &operator=(Framebuffer &&) = delete; + + void Activate(); + + void RenderTo(Framebuffer &target); + + void Resize(unsigned int newWidth, unsigned int newHeight); + + inline GLuint GetColor() { + return texColor; + } + + static Framebuffer &GetDefault(); + + void Clear(bool color = true, bool depth = true, bool stencil = true); +};
\ No newline at end of file diff --git a/src/Render.cpp b/src/Render.cpp index 21e815c..41f2c7e 100644 --- a/src/Render.cpp +++ b/src/Render.cpp @@ -13,6 +13,7 @@ #include "GameState.hpp" #include "RendererWorld.hpp" #include "Settings.hpp" +#include "Framebuffer.hpp" Render::Render(unsigned int windowWidth, unsigned int windowHeight, std::string windowTitle) @@ -40,6 +41,7 @@ Render::Render(unsigned int windowWidth, unsigned int windowHeight, fieldWireframe = Settings::ReadBool("wireframe", false); fieldFlight = Settings::ReadBool("flight", false); fieldBrightness = Settings::ReadDouble("brightness", 0.2f); + fieldResolutionScale = Settings::ReadDouble("resolutionScale", 1.0f); //Apply settings if (fieldSensetivity != sensetivity) @@ -52,6 +54,7 @@ Render::Render(unsigned int windowWidth, unsigned int windowHeight, } else SDL_GL_SetSwapInterval(0); + framebuffer->Resize(renderState.WindowWidth * fieldResolutionScale, renderState.WindowHeight * fieldResolutionScale); LOG(INFO) << "Supported threads: " << std::thread::hardware_concurrency(); } @@ -66,8 +69,10 @@ Render::~Render() { Settings::WriteBool("wireframe", fieldWireframe); Settings::WriteBool("flight", fieldFlight); Settings::WriteDouble("brightness", fieldBrightness); + Settings::WriteDouble("resolutionScale", fieldResolutionScale); Settings::Save(); - + + framebuffer.reset(); ImGui_ImplSdlGL3_Shutdown(); SDL_GL_DeleteContext(glContext); SDL_DestroyWindow(window); @@ -115,7 +120,7 @@ void Render::InitGlew() { int width, height; SDL_GL_GetDrawableSize(window, &width, &height); glViewport(0, 0, width, height); - glClearColor(0.8,0.8,0.8, 1.0f); + glClearColor(0.8,0.8,0.8, 1.0f); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); @@ -136,6 +141,12 @@ void Render::PrepareToRendering() { glBindTexture(GL_TEXTURE_2D_ARRAY, AssetManager::GetTextureAtlasId()); ImGui_ImplSdlGL3_Init(window); + + int width, height; + SDL_GL_GetDrawableSize(window, &width, &height); + framebuffer = std::make_unique<Framebuffer>(width, height, true); + Framebuffer::GetDefault().Activate(); + Framebuffer::GetDefault().Resize(width, height); } void Render::UpdateKeyboard() { @@ -160,20 +171,25 @@ void Render::UpdateKeyboard() { } void Render::RenderFrame() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + framebuffer->Clear(); + Framebuffer::GetDefault().Clear(); + if (renderWorld) + framebuffer->Activate(); if (isWireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); if (renderWorld) world->Render(renderState); if (isWireframe) - glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + if (renderWorld) + framebuffer->RenderTo(Framebuffer::GetDefault()); - if (world) { - world->Update(timer.RemainTimeMs()); - } + RenderGui(); - RenderGui(); + if (world) { + world->Update(timer.RemainTimeMs()); + } SDL_GL_SwapWindow(window); } @@ -196,9 +212,10 @@ void Render::HandleEvents() { case SDL_WINDOWEVENT_RESIZED: { int width, height; SDL_GL_GetDrawableSize(window, &width, &height); - glViewport(0, 0, width, height); renderState.WindowWidth = width; renderState.WindowHeight = height; + framebuffer->Resize(width * fieldResolutionScale, height * fieldResolutionScale); + Framebuffer::GetDefault().Resize(width, height); break; } @@ -581,6 +598,8 @@ void Render::RenderGui() { ImGui::SliderFloat("Target FPS", &fieldTargetFps, 1.0f, 300.0f); + ImGui::SliderFloat("Resolution scale", &fieldResolutionScale, 0.1f, 2.0f); + ImGui::Checkbox("Wireframe", &fieldWireframe); ImGui::Checkbox("VSync", &fieldVsync); @@ -608,6 +627,9 @@ void Render::RenderGui() { PUSH_EVENT("SetMinLightLevel", fieldBrightness); + int width, height; + SDL_GL_GetDrawableSize(window, &width, &height); + framebuffer->Resize(width * fieldResolutionScale, height * fieldResolutionScale); } ImGui::Separator(); @@ -648,7 +670,7 @@ void Render::InitEvents() { stateString = "Playing"; renderWorld = true; GlobalState::SetState(State::Playing); - glClearColor(0, 0, 0, 1.0f); + glClearColor(0, 0, 0, 1.0f); world->GameStatePtr()->player->isFlying = this->fieldFlight; PUSH_EVENT("SetMinLightLevel", fieldBrightness); }); @@ -658,7 +680,7 @@ void Render::InitEvents() { renderWorld = false; world.reset(); GlobalState::SetState(State::MainMenu); - glClearColor(0.8, 0.8, 0.8, 1.0f); + glClearColor(0.8, 0.8, 0.8, 1.0f); }); listener.RegisterHandler("Disconnected", [this](const Event& eventData) { @@ -666,7 +688,7 @@ void Render::InitEvents() { renderWorld = false; world.reset(); GlobalState::SetState(State::MainMenu); - glClearColor(0.8, 0.8, 0.8, 1.0f); + glClearColor(0.8, 0.8, 0.8, 1.0f); }); listener.RegisterHandler("Connecting", [this](const Event&) { diff --git a/src/Render.hpp b/src/Render.hpp index adb0547..eea5450 100644 --- a/src/Render.hpp +++ b/src/Render.hpp @@ -12,6 +12,7 @@ #include "Event.hpp" class RendererWorld; +class Framebuffer; class Render { SDL_Window *window; @@ -28,7 +29,8 @@ class Render { std::map<SDL_Scancode, bool> isKeyPressed; bool HasFocus=true; float sensetivity = 0.1f; - bool isWireframe = false; + bool isWireframe = false; + std::unique_ptr<Framebuffer> framebuffer; std::vector<std::string> chatMessages; EventListener listener; std::string stateString; @@ -41,6 +43,7 @@ class Render { bool fieldVsync; bool fieldFlight; float fieldBrightness; + float fieldResolutionScale; void SetMouseCapture(bool IsCaptured); |