// Copyright (c) 2023 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "RenderHost.hpp" #include "assert/assertgl.hpp" #include "assert/assert.hpp" #include "game/Game.hpp" #include "display/RenderPipeline.hpp" using namespace Dawn; RenderHost::RenderHost() : IRenderHost() { } void RenderHost::init(const std::shared_ptr game) { // Init GLFW if(!glfwInit()) { assertUnreachable("Failed to initialize GLFW!"); } // Set the error callback for error handling. glfwSetErrorCallback([](int error, const char *description) { assertUnreachable(description); }); // Setup window hints glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, false); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Create the window window = glfwCreateWindow( DAWN_GLFW_WINDOW_WIDTH_DEFAULT, DAWN_GLFW_WINDOW_HEIGHT_DEFAULT, "Dawn", NULL, NULL ); // Validate window exists if(!window) assertUnreachable("Failed to create GLFW window!"); // Setup the user pointer glfwSetWindowUserPointer(window, game.get()); // Load GLAD glfwMakeContextCurrent(window); glfwSwapInterval(1); gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); assertNoGLError(); // Get the resolution and scale/dpi backBufferRenderTarget = std::make_shared(); int32_t fbWidth, fbHeight; int32_t windowWidth, windowHeight; glfwGetFramebufferSize(window, &fbWidth, &fbHeight); glfwGetWindowSize(window, &windowWidth, &windowHeight); assertTrue(fbWidth > 0, "Detected framebuffer width is too small?"); assertTrue(fbWidth > 0, "Detected framebuffer height is too small?"); assertTrue(windowWidth > 0, "Detected window width is too small?"); assertTrue(windowHeight > 0, "Detected window height is too small?"); backBufferRenderTarget->setSize(fbWidth, fbHeight); backBufferRenderTarget->scale = (float_t)fbWidth / (float_t)windowWidth; // Framebuffer callback glfwSetFramebufferSizeCallback(window, []( GLFWwindow *window, int32_t width, int32_t height ) { // if(this->window == nullptr || window != this->window) return; Game* game = (Game*)glfwGetWindowUserPointer(window); assertNotNull(game, "Game cannot be null!"); game->renderHost.backBufferRenderTarget->setSize(width, height); }); } void RenderHost::update(const std::shared_ptr game) { // Prepare the initial values glPixelStorei(GL_UNPACK_ALIGNMENT, 1); assertNoGLError(); glBlendFuncSeparate( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); assertNoGLError(); glDepthMask(GL_TRUE); assertNoGLError(); glDepthFunc(GL_LESS); assertNoGLError(); glEnable(GL_DEPTH_TEST); assertNoGLError(); // Pipeline renderPipeline.render(game); // Tick the engine. glfwSwapBuffers(window); // Update events glfwPollEvents(); } bool_t RenderHost::isCloseRequested() { if(this->window == nullptr) return false; return glfwWindowShouldClose(this->window); } std::shared_ptr RenderHost::getBackBufferRenderTarget() { return std::static_pointer_cast(backBufferRenderTarget); } RenderHost::~RenderHost() { if(this->window != nullptr) { glfwDestroyWindow(this->window); this->window = nullptr; } glfwTerminate(); }