Add backbuffer

This commit is contained in:
2025-08-22 23:30:23 -05:00
parent 995bbe1acd
commit 1bf6fe6eaf
13 changed files with 413 additions and 2 deletions

View File

@@ -12,7 +12,9 @@ target_sources(${DUSK_TARGET_NAME}
)
# Subdirectories
add_subdirectory(framebuffer)
add_subdirectory(mesh)
add_subdirectory(texture)
if(DUSK_TARGET_SYSTEM STREQUAL "linux")
target_compile_definitions(${DUSK_TARGET_NAME}

View File

@@ -9,6 +9,7 @@
#include "display/display.h"
#include "assert/assert.h"
#include "scene/node.h"
#include "display/framebuffer/framebuffer.h"
camera_t CAMERA_DATA[ECS_ENTITY_COUNT_MAX] = { 0 };
ecscomponent_t CAMERA_COMPONENT = ecsComponentInit(
@@ -56,7 +57,10 @@ void cameraPush(const ecsid_t id) {
case CAMERA_TYPE_PERSPECTIVE:
glm_perspective(
cam->perspective.fov,
4.0f / 3.0f,
(
(float_t)frameBufferGetWidth(FRAMEBUFFER_BOUND) /
(float_t)frameBufferGetHeight(FRAMEBUFFER_BOUND)
),
cam->nearClip,
cam->farClip,
projection

View File

@@ -9,6 +9,7 @@
#include "console/console.h"
#include "display/renderer.h"
#include "ecs/ecssystem.h"
#include "display/framebuffer/framebuffer.h"
#include "display/mesh/quad.h"
@@ -58,6 +59,7 @@ errorret_t displayInit(void) {
#endif
quadInit();
frameBufferInitBackbuffer();
errorOk();
}

View File

@@ -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
)

View File

@@ -0,0 +1,141 @@
/**
* 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"
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;
}
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer) {
#if DUSK_DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
int32_t windowWidth, windowHeight;
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
return windowWidth;
}
assertUnreachable("Framebuffer width not implemented");
return 0;
#endif
}
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer) {
#if DUSK_DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
int32_t windowWidth, windowHeight;
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
return windowHeight;
}
assertUnreachable("Framebuffer height not implemented");
return 0;
#endif
}
void frameBufferBind(const framebuffer_t *framebuffer) {
if(framebuffer == NULL) {
#if DUSK_DISPLAY_SDL2
frameBufferBind(&FRAMEBUFFER_BACKBUFFER);
#endif
FRAMEBUFFER_BOUND = &FRAMEBUFFER_BACKBUFFER;
return;
}
// Bind the framebuffer for rendering
#if DUSK_DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
int32_t windowWidth, windowHeight;
SDL_GetWindowSize(DISPLAY.window, &windowWidth, &windowHeight);
} else {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
}
glViewport(
0, 0,
frameBufferGetWidth(framebuffer), frameBufferGetHeight(framebuffer)
);
#endif
FRAMEBUFFER_BOUND = framebuffer;
}
/**
* Disposes of the framebuffer using EXT methods.
*
* @param framebuffer The framebuffer to dispose of.
*/
void frameBufferDispose(framebuffer_t *framebuffer) {
assertNotNull(framebuffer, "Framebuffer cannot be NULL");
#if DUSK_DISPLAY_SDL2
if(framebuffer == &FRAMEBUFFER_BACKBUFFER) {
assertUnreachable("Cannot dispose of backbuffer");
}
glDeleteFramebuffersEXT(1, &framebuffer->id);
#endif
}
// #if RENDER_USE_FRAMEBUFFER
// 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, GL_RGBA, NULL);
// // Generate the framebuffer object using EXT
// glGenFramebuffersEXT(1, &framebuffer->id);
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
// // Attach the texture to the framebuffer
// glFramebufferTexture2DEXT(
// GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
// GL_TEXTURE_2D, framebuffer->texture.id, 0
// );
// // Check if the framebuffer is complete
// if(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT) {
// assertUnreachable("Framebuffer is not complete");
// }
// // Unbind the framebuffer
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// }
// void frameBufferBind(const framebuffer_t *framebuffer) {
// if(framebuffer == NULL) {
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
// return;
// }
// // Bind the framebuffer for rendering
// glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer->id);
// }
// void frameBufferDispose(framebuffer_t *framebuffer) {
// assertNotNull(framebuffer, "Framebuffer cannot be NULL");
// glDeleteFramebuffersEXT(1, &framebuffer->id);
// textureDispose(&framebuffer->texture);
// }
// #endif

View File

@@ -0,0 +1,75 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/display.h"
#include "display/texture/texture.h"
typedef struct {
#if DUSK_DISPLAY_SDL2
// OpenGL Framebuffer Object ID
GLuint id;
#endif
} framebuffer_t;
extern framebuffer_t FRAMEBUFFER_BACKBUFFER;
extern const framebuffer_t *FRAMEBUFFER_BOUND;
void frameBufferInitBackbuffer();
/**
* Gets the width of the framebuffer.
*
* @param framebuffer The framebuffer to get the width of.
* @return The width of the framebuffer, or 0 if the framebuffer is NULL.
*/
int32_t frameBufferGetWidth(const framebuffer_t *framebuffer);
/**
* Gets the height of the framebuffer.
*
* @param framebuffer The framebuffer to get the height of.
* @return The height of the framebuffer, or 0 if the framebuffer is NULL.
*/
int32_t frameBufferGetHeight(const framebuffer_t *framebuffer);
/**
* Binds the framebuffer for rendering, or the backbuffer if the framebuffer
* provided is NULL.
*
* @param framebuffer The framebuffer to bind, or NULL to bind the backbuffer.
*/
void frameBufferBind(const framebuffer_t *framebuffer);
/**
* Disposes of the framebuffer using EXT methods.
*
* @param framebuffer The framebuffer to dispose of.
*/
void frameBufferDispose(framebuffer_t *framebuffer);
// #if RENDER_USE_FRAMEBUFFER
// typedef struct {
// GLuint id;
// texture_t texture;
// } framebuffer_t;
// /**
// * Initializes a framebuffer using EXT methods.
// *
// * @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
// );
// #endif

View File

@@ -22,5 +22,7 @@ void meshRendererDraw(const ecsid_t id) {
if(!meshRendererHas(id)) return;
meshrenderer_t *renderer = &MESH_RENDERER_DATA[id];
if(!renderer->mesh) return;
textureBind(renderer->texture);
meshDraw(renderer->mesh, 0, -1);
}

View File

@@ -8,9 +8,11 @@
#pragma once
#include "ecs/ecscomponent.h"
#include "display/mesh/mesh.h"
#include "display/texture/texture.h"
typedef struct {
mesh_t *mesh;
texture_t *texture;
} meshrenderer_t;
extern meshrenderer_t MESH_RENDERER_DATA[ECS_ENTITY_COUNT_MAX];

View File

@@ -8,6 +8,7 @@
#include "renderer.h"
#include "display/mesh/meshrenderer.h"
#include "scene/node.h"
#include "display/framebuffer/framebuffer.h"
void rendererRender(const ecsid_t camera) {
if(camera == -1) return;
@@ -18,6 +19,7 @@ void rendererRender(const ecsid_t camera) {
ecsid_t id;
meshCount = meshRendererGetAll(meshes);
frameBufferBind(NULL);
cameraPush(camera);
for(uint32_t i = 0; i < meshCount; i++) {
id = meshes[i];

View File

@@ -0,0 +1,13 @@
# 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
texture.c
)
# Subdirs
# add_subdirectory(draw)

View File

@@ -0,0 +1,91 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "texture.h"
#include "assert/assert.h"
#include "util/memory.h"
#include "util/math.h"
const texture_t *TEXTURE_BOUND = NULL;
void textureInit(
texture_t *texture,
const int32_t width,
const int32_t height,
const textureformat_t format,
const void *data
) {
assertNotNull(texture, "Texture cannot be NULL");
assertTrue(width > 0 && height > 0, "width/height must be greater than 0");
memoryZero(texture, sizeof(texture_t));
texture->width = width;
texture->height = height;
#if PSP
assertTrue(
width == mathNextPowTwo(width),
"Width must be powers of 2 for PSP"
);
assertTrue(
height == mathNextPowTwo(height),
"Height must be powers of 2 for PSP"
);
#endif
#if DUSK_DISPLAY_SDL2
glGenTextures(1, &texture->id);
glBindTexture(GL_TEXTURE_2D, texture->id);
glTexImage2D(
GL_TEXTURE_2D, 0, format, width, height, 0,
format, GL_UNSIGNED_BYTE, data
);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
#endif
}
void textureBind(const texture_t *texture) {
if(TEXTURE_BOUND == texture) return;
if(texture == NULL) {
#if DUSK_DISPLAY_SDL2
glDisable(GL_TEXTURE_2D);
#endif
TEXTURE_BOUND = NULL;
return;
}
assertTrue(
texture->id != 0,
"Texture ID must not be 0"
);
assertTrue(
texture->width > 0 && texture->height > 0,
"Texture width and height must be greater than 0"
);
#if DUSK_DISPLAY_SDL2
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture->id);
#endif
TEXTURE_BOUND = texture;
}
void textureDispose(texture_t *texture) {
assertNotNull(texture, "Texture cannot be NULL");
assertTrue(texture->id != 0, "Texture ID must not be 0");
#if DUSK_DISPLAY_SDL2
glDeleteTextures(1, &texture->id);
#endif
}

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "display/display.h"
#include "display/color.h"
typedef enum {
#if DUSK_DISPLAY_SDL2
TEXTURE_FORMAT_RGBA = GL_RGBA,
TEXTURE_FORMAT_ALPHA = GL_ALPHA,
#endif
} textureformat_t;
typedef struct {
#if DUSK_DISPLAY_SDL2
GLuint id;
#endif
int32_t width;
int32_t height;
} texture_t;
extern const texture_t *TEXTURE_BOUND;
/**
* Initializes a texture.
*
* @param texture The texture to initialize.
* @param width The width of the texture.
* @param height The height of the texture.
* @param format The format of the texture (e.g., GL_RGBA, GL_ALPHA).
* @param data The pixel data for the texture.
*/
void textureInit(
texture_t *texture,
const int32_t width,
const int32_t height,
const textureformat_t format,
const void *data
);
/**
* Binds a texture for rendering. Providing NULL will unbind any texture.
*
* @param texture The texture to bind.
*/
void textureBind(const texture_t *texture);
/**
* Disposes a texture.
*
* @param texture The texture to dispose.
*/
void textureDispose(texture_t *texture);

View File

@@ -8,10 +8,11 @@
#include "scenetest.h"
#include "scene/node.h"
#include "display/camera.h"
#include "display/display.h"
#include "display/mesh/meshrenderer.h"
#include "display/mesh/quad.h"
texture_t test;
void sceneTestAdd(void) {
// Initialize the entity with a camera component
ecsid_t camera = ecsEntityAdd();
@@ -27,9 +28,16 @@ void sceneTestAdd(void) {
);
nodeMatrixSet(camera, lookAt);
color4b_t pixels[4] = {
COLOR_RED, COLOR_GREEN,
COLOR_BLUE, COLOR_WHITE
};
textureInit(&test, 2, 2, TEXTURE_FORMAT_RGBA, pixels);
// Test cube
ecsid_t cube = ecsEntityAdd();
node = nodeAdd(cube);
meshrenderer_t *renderer = meshRendererAdd(cube);
renderer->mesh = &QUAD_MESH_SIMPLE;
renderer->texture = &test;
}