From d1ab8b0cc8ec8d48cd860b6e4a00538714aba922 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Fri, 15 Aug 2025 18:50:43 -0500 Subject: [PATCH] Framebuffer done. --- src/dusksdl2/display/CMakeLists.txt | 1 + src/dusksdl2/display/camera/camera.c | 1 + .../display/framebuffer/CMakeLists.txt | 10 ++++ .../display/framebuffer/framebuffer.c | 57 +++++++++++++++++++ .../display/framebuffer/framebuffer.h | 42 ++++++++++++++ src/dusksdl2/display/render.c | 16 ++---- src/dusksdl2/display/renderbackbuffer.c | 36 ++++-------- src/dusksdl2/display/renderbackbuffer.h | 5 ++ src/dusksdl2/display/texture/texture.c | 1 - 9 files changed, 133 insertions(+), 36 deletions(-) create mode 100644 src/dusksdl2/display/framebuffer/CMakeLists.txt create mode 100644 src/dusksdl2/display/framebuffer/framebuffer.c create mode 100644 src/dusksdl2/display/framebuffer/framebuffer.h diff --git a/src/dusksdl2/display/CMakeLists.txt b/src/dusksdl2/display/CMakeLists.txt index e10d2e8..2859449 100644 --- a/src/dusksdl2/display/CMakeLists.txt +++ b/src/dusksdl2/display/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(${DUSK_TARGET_NAME} # Subdirs add_subdirectory(camera) +add_subdirectory(framebuffer) add_subdirectory(mesh) add_subdirectory(texture) add_subdirectory(spritebatch) \ No newline at end of file diff --git a/src/dusksdl2/display/camera/camera.c b/src/dusksdl2/display/camera/camera.c index 75e0f9d..83bddc4 100644 --- a/src/dusksdl2/display/camera/camera.c +++ b/src/dusksdl2/display/camera/camera.c @@ -11,6 +11,7 @@ void cameraUIPush(void) { glPushMatrix(); glLoadIdentity(); + glViewport(0, 0, RENDER_WIDTH, RENDER_HEIGHT); glOrtho( 0.0f, (float_t)RENDER_WIDTH, (float_t)RENDER_HEIGHT, 0.0f, diff --git a/src/dusksdl2/display/framebuffer/CMakeLists.txt b/src/dusksdl2/display/framebuffer/CMakeLists.txt new file mode 100644 index 0000000..9f0656b --- /dev/null +++ b/src/dusksdl2/display/framebuffer/CMakeLists.txt @@ -0,0 +1,10 @@ +# Copyright (c) 2025 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(${DUSK_TARGET_NAME} + PRIVATE + framebuffer.c +) \ No newline at end of file diff --git a/src/dusksdl2/display/framebuffer/framebuffer.c b/src/dusksdl2/display/framebuffer/framebuffer.c new file mode 100644 index 0000000..8198ebd --- /dev/null +++ b/src/dusksdl2/display/framebuffer/framebuffer.c @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "framebuffer.h" +#include "assert/assert.h" +#include "util/memory.h" + +void frameBufferInit( + framebuffer_t *framebuffer, + const uint32_t width, + const uint32_t height +) { + assertNotNull(framebuffer, "Framebuffer cannot be NULL"); + assertTrue(width > 0 && height > 0, "Width & height must be greater than 0"); + + memoryZero(framebuffer, sizeof(framebuffer_t)); + textureInit(&framebuffer->texture, width, height, NULL); + + // Generate the framebuffer object + glGenFramebuffers(1, &framebuffer->id); + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); + + // Attach the texture to the framebuffer + glFramebufferTexture2D( + GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, framebuffer->texture.id, 0 + ); + + // Check if the framebuffer is complete + if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + assertUnreachable("Framebuffer is not complete"); + } + + // Unbind the framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +void frameBufferBind(const framebuffer_t *framebuffer) { + if(framebuffer == NULL) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + return; + } + + // Bind the framebuffer for rendering + glBindFramebuffer(GL_FRAMEBUFFER, framebuffer->id); +} + +void frameBufferDispose(framebuffer_t *framebuffer) { + assertNotNull(framebuffer, "Framebuffer cannot be NULL"); + + glDeleteFramebuffers(1, &framebuffer->id); + textureDispose(&framebuffer->texture); +} \ No newline at end of file diff --git a/src/dusksdl2/display/framebuffer/framebuffer.h b/src/dusksdl2/display/framebuffer/framebuffer.h new file mode 100644 index 0000000..d61c524 --- /dev/null +++ b/src/dusksdl2/display/framebuffer/framebuffer.h @@ -0,0 +1,42 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "display/texture/texture.h" + +typedef struct { + GLuint id; + texture_t texture; +} framebuffer_t; + +/** + * Initializes a framebuffer. + * + * @param framebuffer The framebuffer to initialize. + * @param width The width of the framebuffer. + * @param height The height of the framebuffer. + * @return An error code indicating success or failure. + */ +void frameBufferInit( + framebuffer_t *framebuffer, + const uint32_t width, + const uint32_t height +); + +/** + * Binds the framebuffer for rendering. + * + * @param framebuffer The framebuffer to bind, or NULL to unbind. + */ +void frameBufferBind(const framebuffer_t *framebuffer); + +/** + * Disposes of the framebuffer. + * + * @param framebuffer The framebuffer to dispose of. + */ +void frameBufferDispose(framebuffer_t *framebuffer); \ No newline at end of file diff --git a/src/dusksdl2/display/render.c b/src/dusksdl2/display/render.c index 8a47612..efffaf6 100644 --- a/src/dusksdl2/display/render.c +++ b/src/dusksdl2/display/render.c @@ -74,8 +74,6 @@ errorret_t renderInit(void) { spriteBatchInit(); renderTextInit(); renderBackBufferInit(); - - // Init other things renderSceneInit(); RENDER_RUNNING = true; @@ -101,17 +99,14 @@ errorret_t renderDraw(void) { // Draw everything renderSceneDraw(); - + // UI cameraUIPush(); renderConsoleDraw(); spriteBatchFlush(); cameraUIPop(); - // Finish rendering - spriteBatchFlush(); + // Finish rendering, now render back buffer. renderBackBufferUnbind(); - - // Draw the back buffer to the window renderBackBufferDraw(); SDL_GL_SwapWindow(RENDER_WINDOW); @@ -119,12 +114,11 @@ errorret_t renderDraw(void) { } errorret_t renderDispose(void) { + renderSceneDispose(); + renderBackBufferDispose(); + renderTextDispose(); spriteBatchDispose(); - // renderTextDispose(); - // renderSceneDispose(); - // renderBackBufferDispose(); - // Destroy OpenGL context SDL_GL_DeleteContext(RENDER_GL_CONTEXT); SDL_DestroyWindow(RENDER_WINDOW); diff --git a/src/dusksdl2/display/renderbackbuffer.c b/src/dusksdl2/display/renderbackbuffer.c index b37f9b3..b6a9fb6 100644 --- a/src/dusksdl2/display/renderbackbuffer.c +++ b/src/dusksdl2/display/renderbackbuffer.c @@ -11,27 +11,16 @@ #include "display/camera/camera.h" #if RENDER_USE_FRAMEBUFFER - SDL_Texture *RENDER_BACKBUFFER; -#else - + framebuffer_t RENDER_BACKBUFFER; #endif errorret_t renderBackBufferInit(void) { #if RENDER_USE_FRAMEBUFFER - // RENDER_BACKBUFFER = SDL_CreateTexture( - // RENDER_RENDERER, - // SDL_PIXELFORMAT_RGBA8888, - // SDL_TEXTUREACCESS_TARGET, - // RENDER_WIDTH, - // RENDER_HEIGHT - // ); - - if(!RENDER_BACKBUFFER) { - errorThrow("SDL_CreateTexture failed: %s", SDL_GetError()); - } - - // Make sure we unbind the back buffer after creation - // SDL_SetRenderTarget(RENDER_RENDERER, NULL); + frameBufferInit( + &RENDER_BACKBUFFER, + RENDER_WIDTH, + RENDER_HEIGHT + ); #else // No back buffer needed for window rendering #endif @@ -41,7 +30,7 @@ errorret_t renderBackBufferInit(void) { void renderBackBufferBind(void) { #if RENDER_USE_FRAMEBUFFER - // SDL_SetRenderTarget(RENDER_RENDERER, RENDER_BACKBUFFER); + frameBufferBind(&RENDER_BACKBUFFER); #endif // Fill background with cornflower blue. @@ -51,7 +40,7 @@ void renderBackBufferBind(void) { void renderBackBufferUnbind(void) { #if RENDER_USE_FRAMEBUFFER - // SDL_SetRenderTarget(RENDER_RENDERER, NULL); + frameBufferBind(NULL); #endif } @@ -82,11 +71,11 @@ void renderBackBufferDraw(void) { // Draw the back buffer texture spriteBatchClear(); spriteBatchPush( - NULL, + &RENDER_BACKBUFFER.texture, renderX, renderY, renderX+renderWidth, renderY+renderHeight, - 0xFF, 0x00, 0xFF, 0xFF, - 0, 0, 1, 1 + 0xFF, 0xFF, 0xFF, 0xFF, + 0, 1, 1, 0 ); spriteBatchFlush(); cameraScreenPop(); @@ -97,8 +86,7 @@ void renderBackBufferDraw(void) { errorret_t renderBackBufferDispose(void) { #if RENDER_USE_FRAMEBUFFER - SDL_DestroyTexture(RENDER_BACKBUFFER); - RENDER_BACKBUFFER = NULL; + frameBufferDispose(&RENDER_BACKBUFFER); #endif errorOk(); diff --git a/src/dusksdl2/display/renderbackbuffer.h b/src/dusksdl2/display/renderbackbuffer.h index 996d683..6d65919 100644 --- a/src/dusksdl2/display/renderbackbuffer.h +++ b/src/dusksdl2/display/renderbackbuffer.h @@ -7,6 +7,11 @@ #pragma once #include "display/renderbase.h" +#include "display/framebuffer/framebuffer.h" + +#if RENDER_USE_FRAMEBUFFER + extern framebuffer_t RENDER_BACKBUFFER; +#endif /** * Initializes the render back buffer. May be either a framebuffer or a texture diff --git a/src/dusksdl2/display/texture/texture.c b/src/dusksdl2/display/texture/texture.c index 270ed34..410e432 100644 --- a/src/dusksdl2/display/texture/texture.c +++ b/src/dusksdl2/display/texture/texture.c @@ -17,7 +17,6 @@ void textureInit( ) { assertNotNull(texture, "Texture cannot be NULL"); assertTrue(width > 0 && height > 0, "Width and height must be greater than 0"); - assertNotNull(data, "Data cannot be NULL"); #if PSP || 1 assertTrue(