Add backbuffer
This commit is contained in:
@@ -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}
|
||||
|
@@ -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
|
||||
|
@@ -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();
|
||||
}
|
||||
|
10
src/display/framebuffer/CMakeLists.txt
Normal file
10
src/display/framebuffer/CMakeLists.txt
Normal 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
|
||||
)
|
141
src/display/framebuffer/framebuffer.c
Normal file
141
src/display/framebuffer/framebuffer.c
Normal 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
|
75
src/display/framebuffer/framebuffer.h
Normal file
75
src/display/framebuffer/framebuffer.h
Normal 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
|
@@ -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);
|
||||
}
|
@@ -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];
|
||||
|
@@ -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];
|
||||
|
13
src/display/texture/CMakeLists.txt
Normal file
13
src/display/texture/CMakeLists.txt
Normal 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)
|
91
src/display/texture/texture.c
Normal file
91
src/display/texture/texture.c
Normal 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
|
||||
}
|
59
src/display/texture/texture.h
Normal file
59
src/display/texture/texture.h
Normal 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);
|
@@ -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;
|
||||
}
|
Reference in New Issue
Block a user