diff --git a/src/common/platform.cpp b/src/common/platform.cpp index d38c39e..784492f 100644 --- a/src/common/platform.cpp +++ b/src/common/platform.cpp @@ -21,7 +21,10 @@ #include #include +#include + #include "src/common/platform.h" +#include "src/common/exception.h" #include "src/common/types.h" #include "src/common/crc32.h" #include "src/common/strutil.h" @@ -135,4 +138,4 @@ std::string getUserDataDirectory() { return userData; } -} +} // End of namespace Common diff --git a/src/configuration.h b/src/configuration.h index 2ae3d3b..5070994 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -21,6 +21,11 @@ #ifndef OPENAWE_CONFIGURATION_H #define OPENAWE_CONFIGURATION_H +struct ResolutionData { + unsigned int width, height; + bool fullscreen; +}; + /*! * \brief Class representing the global configuration of the engine * @@ -32,10 +37,7 @@ class Configuration { public: virtual ~Configuration() = default; - struct { - unsigned int width, height; - bool fullscreen; - } resolution; + ResolutionData resolution; /*! * Write the configuration diff --git a/src/engines/awan/configuration.cpp b/src/engines/awan/configuration.cpp index a746092..1e2e98f 100644 --- a/src/engines/awan/configuration.cpp +++ b/src/engines/awan/configuration.cpp @@ -81,6 +81,12 @@ void Configuration::read() { if (std::filesystem::is_regular_file(resolutionFile)) { auto resolutionStream = std::make_unique(resolutionFile); readResolution(*resolutionStream); + } else { + resolution = { + 0, + 0, + false + }; } if (std::filesystem::is_regular_file(configFile)) { diff --git a/src/engines/awan/engine.cpp b/src/engines/awan/engine.cpp index f8e9094..102cc6f 100644 --- a/src/engines/awan/engine.cpp +++ b/src/engines/awan/engine.cpp @@ -37,6 +37,7 @@ Engine::Engine(entt::registry ®istry, const LocaleConfig::Config &config) : ::Engine(registry, config, new Functions(registry, *this)) { _storyModeRound = 1; _configuration.reset(new AlanWakesAmericanNightmare::Configuration()); + _configuration->read(); } void Engine::init() { diff --git a/src/game.cpp b/src/game.cpp index 652a152..0b59cf7 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -23,6 +23,11 @@ #include +#include +#include "src/configuration.h" +#include "src/graphics/gfxman.h" +#include "src/graphics/text.h" + #include "src/common/crc32.h" #include "src/common/threadpool.h" #include "src/common/strutil.h" @@ -38,6 +43,7 @@ #include "src/platform/keyconversion.h" #include "src/platform/gamepadconversion.h" #include "src/platform/gamepadman.h" +#include "src/platform/platform.h" #include "src/graphics/fontman.h" #include "src/graphics/text.h" @@ -270,6 +276,23 @@ void Game::init() { _engine->init(); }); + + // set window resolution and fullscreen mode + Configuration & config = _engine->getConfiguration(); + + if (config.resolution.width == 0 || config.resolution.height == 0) { + Platform::VideoMode videoMode = _platform.getPrimaryMonitorVideoMode(); + config.resolution.width = videoMode.width; + config.resolution.height = videoMode.height; + config.resolution.fullscreen = true; + } + + _window->setFullscreen(config.resolution.fullscreen); + _window->setSize(config.resolution.width, config.resolution.height); + spdlog::error("Window size: {} x {}", _window->getSize().x, _window->getSize().y); + spdlog::error("Content scale: {} x {}", _window->getContentScale().x, _window->getContentScale().y); + GfxMan.setScreenSize(config.resolution.width, config.resolution.height); + GfxMan.setContentScale(_window->getContentScale()); } void Game::start() { diff --git a/src/graphics/gfxman.cpp b/src/graphics/gfxman.cpp index f9b8fef..c4dbc39 100644 --- a/src/graphics/gfxman.cpp +++ b/src/graphics/gfxman.cpp @@ -196,6 +196,14 @@ void GraphicsManager::drawFrame() { _renderer->drawFrame(); } +void GraphicsManager::setScreenSize(unsigned int width, unsigned int height) { + _renderer->setRenderPlane(width, height); +} + +void GraphicsManager::setContentScale(glm::vec2 scale) { + _renderer->setContentScale(scale); +} + void GraphicsManager::setAmbianceState(const std::string &id) { if (!_renderer) return; diff --git a/src/graphics/gfxman.h b/src/graphics/gfxman.h index 0021a6b..6b2175b 100644 --- a/src/graphics/gfxman.h +++ b/src/graphics/gfxman.h @@ -181,6 +181,9 @@ class GraphicsManager : public Common::Singleton { void drawFrame(); + void setScreenSize(unsigned int width, unsigned int height); + void setContentScale(glm::vec2 scale); + private: std::unique_ptr _renderer; }; diff --git a/src/graphics/opengl/framebuffer.cpp b/src/graphics/opengl/framebuffer.cpp index f36ccbc..fa7b273 100644 --- a/src/graphics/opengl/framebuffer.cpp +++ b/src/graphics/opengl/framebuffer.cpp @@ -19,6 +19,7 @@ */ #include +#include #include "src/common/exception.h" @@ -29,8 +30,10 @@ namespace Graphics::OpenGL { Framebuffer::Framebuffer(const std::string &label) { glGenFramebuffers(1, &_id); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - throw CreateException("Failed to initialize framebuffer"); + const GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) + throw CreateException("Failed to initialize framebuffer: {}", framebufferStatus); bind(); if (GLAD_GL_KHR_debug && !label.empty()) @@ -64,8 +67,10 @@ void Framebuffer::attachRenderBuffer(const Renderbuffer &renderbuffer, GLenum at renderbuffer._id ); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - throw CreateException("Failed to attach renderbuffer tot exture"); + const GLenum framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) + throw CreateException("Failed to render buffer to texture: {}", framebufferStatus); } void Framebuffer::clear() { diff --git a/src/graphics/opengl/renderer.cpp b/src/graphics/opengl/renderer.cpp index 4d41ae1..ccbc8e3 100644 --- a/src/graphics/opengl/renderer.cpp +++ b/src/graphics/opengl/renderer.cpp @@ -42,6 +42,8 @@ #include "src/common/strutil.h" #include "src/common/readfile.h" +#include "src/platform/window.h" + #include "src/awe/resman.h" #include "src/awe/objfile.h" #include "src/awe/hg.h" @@ -51,6 +53,7 @@ #include "src/graphics/shaderconverter.h" #include "src/graphics/skeleton.h" #include "src/graphics/images/surface.h" +#include "src/graphics/renderer.h" #include "src/graphics/opengl/renderer.h" #include "src/graphics/opengl/opengl.h" #include "src/graphics/opengl/vbo.h" @@ -64,6 +67,7 @@ static void *loadProcAddress(const char *name) { } Renderer::Renderer(Platform::Window &window, const std::string &shaderDirectory) : + Graphics::Renderer(window.getSize()), _window(window), _shaderDirectory(shaderDirectory) { _window.makeCurrent(); @@ -194,27 +198,35 @@ Renderer::Renderer(Platform::Window &window, const std::string &shaderDirectory) // rebuildShaders(); - // Get width and height of the default framebuffer - unsigned int width, height; - window.getSize(width, height); + setRenderPlane(_window.getSize()); + + // Check for errors + assert(glGetError() == GL_NO_ERROR); +} + +void Renderer::setRenderPlane(unsigned int width, unsigned int height) { + setRenderPlane(glm::vec2(width, height)); +} + +void Renderer::setRenderPlane(const glm::vec2 size) { + Graphics::Renderer::setRenderPlane(size); // Initialize deferred shading // - _depthTexture = std::make_unique(_loadingTasks, width, height, kRGBA16F, "depth_buffer"); - _normalTexture = std::make_unique(_loadingTasks, width, height, kRGBA16F, "normal_buffer"); - _depthstencilBuffer = std::make_unique(width, height, GL_DEPTH24_STENCIL8, + _depthTexture = std::make_unique(_loadingTasks, size.x, size.y, kRGBA16F, "depth_buffer"); + _normalTexture = std::make_unique(_loadingTasks, size.x, size.y, kRGBA16F, "normal_buffer"); + _depthstencilBuffer = std::make_unique(size.x, size.y, GL_DEPTH24_STENCIL8, "depthstencil_renderbuffer"); _deferredBuffer = std::make_unique("Deferred Buffer"); _deferredBuffer->setClearColor({0.0f, 0.0f, 0.0f, 0.0f}); _deferredBuffer->bind(); - _deferredBuffer->attachRenderBuffer(*_depthstencilBuffer, GL_DEPTH_STENCIL_ATTACHMENT); _deferredBuffer->attachTexture(*_depthTexture, GL_COLOR_ATTACHMENT0); _deferredBuffer->attachTexture(*_normalTexture, GL_COLOR_ATTACHMENT1); - _lightBufferTexture = std::make_unique(_loadingTasks, width, height, kRGBA16F, "light_buffer"); + _lightBufferTexture = std::make_unique(_loadingTasks, size.x, size.y, kRGBA16F, "light_buffer"); _lightBuffer = std::make_unique("Light Buffer"); _lightBuffer->setClearColor({0.0f, 0.0f, 0.0f, 0.0f}); @@ -241,11 +253,18 @@ Renderer::Renderer(Platform::Window &window, const std::string &shaderDirectory) // Initialize ImGui ImGui_ImplOpenGL3_Init(); + glViewport(0, 0, size.x, size.y); // Check for errors assert(glGetError() == GL_NO_ERROR); } +void Renderer::setContentScale(glm::vec2 scale) { + Graphics::Renderer::setContentScale(scale); + glm::vec2 scaledResolution = _viewportSize * _contentScale; + glViewport(0, 0, scaledResolution.x, scaledResolution.y); +} + Renderer::~Renderer() { ImGui_ImplOpenGL3_Shutdown(); } @@ -297,8 +316,6 @@ void Renderer::drawWorld(const std::string &stage) { const auto &defaultShader = getProgram("standardmaterial", stage, 0); static const glm::mat4 mirrorZ = glm::scale(glm::vec3(1, 1, -1)); - const auto screenResolution = glm::vec2(1920, 1080); - bool wireframe = false; Material::CullMode cullMode = Material::kNone; @@ -329,7 +346,7 @@ void Renderer::drawWorld(const std::string &stage) { const std::optional skinningMatrices = currentShader->getUniformLocation("GPU_skinning_matrices"); if (screenRes) - currentShader->setUniform2f(*screenRes, screenResolution); + currentShader->setUniform2f(*screenRes, _viewportSize); GLuint textureSlotShader = 0; if (lightBuffer) { @@ -580,7 +597,7 @@ void Renderer::drawLights() { const auto cameraLightPositionView = _view * mirrorZ * light->getTransform()[3]; - pointlightProgram->setUniform2f(screenResIndex, glm::vec2(1920, 1080)); + pointlightProgram->setUniform2f(screenResIndex, _viewportSize); pointlightProgram->setUniformMatrix4f(localToClipIndex, vp * mirrorZ * light->getTransform()); pointlightProgram->setUniformMatrix4f(clipToViewIndex, clipToView); pointlightProgram->setUniform3f(lightPositionIndex, cameraLightPositionView); @@ -605,7 +622,7 @@ void Renderer::drawLights() { } void Renderer::drawGUI() { - glm::mat4 vp = glm::ortho(0.0f, 1920.0f, 0.0f, 1080.0f, -1000.0f, 1000.0f); + glm::mat4 vp = glm::ortho(0.0f, _viewportSize.x, 0.0f, _viewportSize.y, -1000.0f, 1000.0f); pushDebug("Draw GUI"); @@ -621,14 +638,14 @@ void Renderer::drawGUI() { for (const auto &element: _guiElements) { glm::mat4 m = glm::translate(glm::vec3( element->getAbsolutePosition() + - element->getRelativePosition() * glm::vec2(1920.0, 1080.0), + element->getRelativePosition() * _viewportSize, 0.0f )); std::static_pointer_cast(element->getVertexAttributes())->bind(); for (const auto &part: element->getParts()) { glm::mat4 m2 = m * - glm::scale(glm::vec3(part.absoluteSize + part.relativeSize * glm::vec2(1920, 1080), 1.0f)) * + glm::scale(glm::vec3(part.absoluteSize + part.relativeSize * _viewportSize, 1.0f)) * glm::translate(glm::vec3(part.position, 1.0f)); std::static_pointer_cast(part.indices)->bind(); diff --git a/src/graphics/opengl/renderer.h b/src/graphics/opengl/renderer.h index 2fdc649..856d572 100644 --- a/src/graphics/opengl/renderer.h +++ b/src/graphics/opengl/renderer.h @@ -48,6 +48,9 @@ class Renderer : public Graphics::Renderer { void drawFrame() override; bool isLoading() const override; + void setRenderPlane(unsigned int width, unsigned int height) override; + void setRenderPlane(glm::vec2 size) override; + void setContentScale(glm::vec2 scale) override; TexturePtr createTexture( TextureType type, diff --git a/src/graphics/renderer.cpp b/src/graphics/renderer.cpp index 66e62e7..b859193 100644 --- a/src/graphics/renderer.cpp +++ b/src/graphics/renderer.cpp @@ -22,14 +22,31 @@ #include "renderer.h" -Graphics::Renderer::Renderer() { +Graphics::Renderer::Renderer(unsigned int width, unsigned int height) { + setRenderPlane(width, height); +} + +Graphics::Renderer::Renderer(glm::vec2 renderPlane) { + setRenderPlane(renderPlane); +} + +void Graphics::Renderer::setRenderPlane(unsigned int width, unsigned int height) { + setRenderPlane(glm::vec2(width, height)); +} + +void Graphics::Renderer::setRenderPlane(glm::vec2 renderPlane) { // Setup initial projection matrix - _projection = glm::perspectiveFov(45.0f, 1920.0f, 1080.0f, 1.0f, 10000.0f); + _viewportSize = renderPlane; + _projection = glm::perspectiveFov(45.0f, _viewportSize.x, _viewportSize.y, 1.0f, 10000.0f); // Initialize frustrum with projection matrix _frustrum.setProjectionMatrix(_projection); } +void Graphics::Renderer::setContentScale(glm::vec2 scale) { + _contentScale = scale; +} + Graphics::Renderer::~Renderer() { } diff --git a/src/graphics/renderer.h b/src/graphics/renderer.h index a538270..ba47a2e 100644 --- a/src/graphics/renderer.h +++ b/src/graphics/renderer.h @@ -42,9 +42,14 @@ namespace Graphics { class Renderer { public: - Renderer(); + Renderer(unsigned int width, unsigned int height); + Renderer(glm::vec2 renderPlane); virtual ~Renderer(); + virtual void setRenderPlane(unsigned int width, unsigned int height); + virtual void setRenderPlane(glm::vec2 renderPlane); + virtual void setContentScale(glm::vec2 scale); + void addModel(Model *model); void removeModel(Model *model); void addGUIElement(GUIElement *gui); @@ -141,6 +146,8 @@ class Renderer { glm::mat4 _view; glm::mat4 _projection; + glm::vec2 _viewportSize; + glm::vec2 _contentScale; SkyPtr _sky; diff --git a/src/platform/context.h b/src/platform/context.h index 0fe67c6..5f81a62 100644 --- a/src/platform/context.h +++ b/src/platform/context.h @@ -21,11 +21,14 @@ #ifndef AWE_CONTEXT_H #define AWE_CONTEXT_H +#include + namespace Platform { class Context { public: virtual void getSize(unsigned int &width, unsigned int &height) = 0; + virtual glm::vec2 getSize() = 0; }; } diff --git a/src/platform/platform.cpp b/src/platform/platform.cpp index 25404d8..e968bb2 100644 --- a/src/platform/platform.cpp +++ b/src/platform/platform.cpp @@ -22,6 +22,8 @@ #include #include +#include "src/common/exception.h" + #include "platform.h" namespace Platform { @@ -56,6 +58,18 @@ void Platform::monitorCallback(GLFWmonitor *monitor, int event) { ImGui_ImplGlfw_MonitorCallback(monitor, event); } +VideoMode Platform::getPrimaryMonitorVideoMode() { + GLFWmonitor *monitor = glfwGetPrimaryMonitor(); + if (!monitor) + throw CreateException("Failed to get primary monitor"); + const GLFWvidmode *mode = glfwGetVideoMode(monitor); + return VideoMode{ + mode->width, + mode->height, + mode->redBits + mode->greenBits + mode->blueBits, + mode->refreshRate}; +} + void Platform::errorCallback(int code, const char *description) { spdlog::error("GLFW Error {}: {}", code, description); } diff --git a/src/platform/platform.h b/src/platform/platform.h index d82c856..c7adcc9 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -25,6 +25,13 @@ namespace Platform { +struct VideoMode { + int width; + int height; + int bpp; + int refreshRate; +}; + /*! * \brief class for handling platform specific stuff * @@ -42,6 +49,13 @@ class Platform { void update(); + /*! + * Get primary monitor's current video mode + * + * \return The primary monitor's current video mode + */ + VideoMode getPrimaryMonitorVideoMode(); + private: static void monitorCallback(GLFWmonitor* monitor, int event); static void errorCallback(int code, const char *description); diff --git a/src/platform/window.cpp b/src/platform/window.cpp index 01bc811..82e7a5a 100644 --- a/src/platform/window.cpp +++ b/src/platform/window.cpp @@ -63,6 +63,8 @@ Window::Window(ContextType type) { glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); _window = glfwCreateWindow(1920, 1080, "", nullptr, nullptr); + _contentScale = glm::vec2(1, 1); + _desiredResolution = glm::vec2(1920, 1080); glfwSetInputMode(_window, GLFW_STICKY_KEYS, GLFW_TRUE); @@ -265,4 +267,31 @@ void Window::getSize(unsigned int &width, unsigned int &height) { glfwGetFramebufferSize(_window, reinterpret_cast(&width), reinterpret_cast(&height)); } +glm::vec2 Window::getSize() { + unsigned int width, height; + glfwGetFramebufferSize(_window, reinterpret_cast(&width), reinterpret_cast(&height)); + return glm::vec2(width, height); +} + +void Window::setSize(unsigned int width, unsigned int height) { + _desiredResolution = glm::vec2(width, height); + glm::vec2 oldResolution = getSize(); + glfwSetWindowSize(_window, width, height); + // On Wayland, when window is fullscreen, the line above does nothing. + // That means we have to scale the content ourselves... + if (getSize() == oldResolution) { + _contentScale = oldResolution / _desiredResolution; + } +} + +glm::vec2 Window::getContentScale() { + return _contentScale; +} + +void Window::setFullscreen(bool fullscreen) { + unsigned int width, height; + getSize(width, height); + glfwSetWindowMonitor(_window, fullscreen ? glfwGetPrimaryMonitor() : NULL, 0, 0, width, height, GLFW_DONT_CARE); +} + } diff --git a/src/platform/window.h b/src/platform/window.h index 898496c..af57280 100644 --- a/src/platform/window.h +++ b/src/platform/window.h @@ -57,6 +57,10 @@ class Window : public GLContext, public VulkanContext { void swap() override; void getSize(unsigned int &width, unsigned int &height) override; + glm::vec2 getSize() override; + void setSize(unsigned int width, unsigned int height); + void setFullscreen(bool fullscreen); + glm::vec2 getContentScale(); bool isMouseCursorVisible(); void setMouseCursorVisible(bool visible); @@ -92,6 +96,8 @@ class Window : public GLContext, public VulkanContext { GLFWwindow *_window; void *_imguiCtx; + glm::vec2 _desiredResolution; + glm::vec2 _contentScale; KeyCallback _keyCallback; MouseButtonCallback _mouseButtonCallback;