Files
dusk/src/display/framebuffer/framebuffer.c
2025-09-12 15:56:21 -05:00

162 lines
4.0 KiB
C

/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "framebuffer.h"
#include "display/display.h"
#include "assert/assert.h"
#include "util/memory.h"
framebuffer_t FRAMEBUFFER_BACKBUFFER = {0};
const framebuffer_t *FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
void frameBufferInitBackbuffer() {
memoryZero(&FRAMEBUFFER_BACKBUFFER, sizeof(framebuffer_t));
FRAMEBUFFER_BACKBUFFER.id = -1;
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
}
#if DISPLAY_SIZE_DYNAMIC == 1
void frameBufferInit(
framebuffer_t *framebuffer,
const uint32_t width,
const uint32_t height
) {
#if DISPLAY_SDL2 == 1
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, GL_RGBA, (texturedata_t){
.rgba = { .colors = NULL }
});
glGenFramebuffersEXT(1, &framebuffer->id);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
glFramebufferTexture2DEXT(
GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
GL_TEXTURE_2D, framebuffer->texture.id, 0
);
if(
glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) !=
GL_FRAMEBUFFER_COMPLETE_EXT
) {
assertUnreachable("Framebuffer is not complete");
}
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#endif
}
#endif
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer) {
#if DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
#if DISPLAY_SIZE_DYNAMIC == 0
return DISPLAY_WIDTH;
#else
int32_t windowWidth, windowHeight;
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
return windowWidth;
#endif
}
return framebuffer->texture.width;
#endif
}
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer) {
#if DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
#if DISPLAY_SIZE_DYNAMIC == 0
return DISPLAY_HEIGHT;
#else
int32_t windowWidth, windowHeight;
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
return windowHeight;
#endif
}
return framebuffer->texture.height;
#endif
}
void frameBufferBind(const framebuffer_t *framebuffer) {
if(framebuffer == NULL) {
#if DISPLAY_SDL2
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
#endif
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
return;
}
// Bind the framebuffer for rendering
#if DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
#if PSP
#else
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
#endif
} else {
#if PSP
assertUnreachable("Framebuffers not supported on PSP");
#else
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
#endif
}
glViewport(
0, 0,
frameBufferGetWidth(framebuffer), frameBufferGetHeight(framebuffer)
);
#endif
FRAMEBUFFER_BOUND = framebuffer;
}
void frameBufferClear(uint8_t flags, color_t color) {
#if DISPLAY_SDL2
GLbitfield glFlags = 0;
if(flags & FRAMEBUFFER_CLEAR_COLOR) {
glFlags |= GL_COLOR_BUFFER_BIT;
glClearColor(
color.r / 255.0f,
color.g / 255.0f,
color.b / 255.0f,
color.a / 255.0f
);
}
if(flags & FRAMEBUFFER_CLEAR_DEPTH) {
glFlags |= GL_DEPTH_BUFFER_BIT;
}
glClear(glFlags);
#endif
}
void frameBufferDispose(framebuffer_t *framebuffer) {
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
#if DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
assertUnreachable("Cannot dispose of backbuffer");
}
#if DISPLAY_SIZE_DYNAMIC == 0
assertUnreachable("Dynamic size framebuffers not supported");
#else
textureDispose(&framebuffer->texture);
glDeleteFramebuffersEXT(1, &framebuffer->id);
#endif
#endif
}