131 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			131 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // 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> 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<BackBufferRenderTarget>();
 | |
| 
 | |
|   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> 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();
 | |
|   glEnable(GL_BLEND);
 | |
|   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<RenderTarget> RenderHost::getBackBufferRenderTarget() {
 | |
|   return std::static_pointer_cast<RenderTarget>(backBufferRenderTarget);
 | |
| }
 | |
| 
 | |
| RenderHost::~RenderHost() {
 | |
|   if(this->window != nullptr) {
 | |
|     glfwDestroyWindow(this->window);
 | |
|     this->window = nullptr;
 | |
|   }
 | |
|   glfwTerminate();
 | |
| } |