Render textg

This commit is contained in:
2025-08-11 23:06:48 -05:00
parent e9d2f4904a
commit 294abab501
8 changed files with 282 additions and 30 deletions

View File

@@ -6,5 +6,3 @@
*/
#include "display/render.h"
uint8_t RENDER_FRAME = 0;

View File

@@ -15,8 +15,6 @@
#define RENDER_HEIGHT 240
#endif
extern uint8_t RENDER_FRAME;
/**
* Initializes the rendering system.
*/

View File

@@ -7,6 +7,8 @@
target_sources(${DUSK_TARGET_NAME}
PRIVATE
render.c
renderbackbuffer.c
rendertext.c
)
# Subdirs

View File

@@ -7,12 +7,15 @@
#include "render.h"
#include "assert/assert.h"
#include "renderbackbuffer.h"
#include "rendertext.h"
SDL_Window *RENDER_WINDOW;
SDL_Renderer *RENDER_RENDERER;
bool_t RENDER_RUNNING;
errorret_t renderInit(void) {
// Init SDL
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
errorThrow(
"SDL Failed to Initialize: %s",
@@ -20,31 +23,36 @@ errorret_t renderInit(void) {
);
}
// Create window.
RENDER_WINDOW = SDL_CreateWindow(
"DuskSDL2",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
RENDER_WINDOW_WIDTH_DEFAULT,
RENDER_WINDOW_HEIGHT_DEFAULT,
SDL_WINDOW_SHOWN
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI
);
if(!RENDER_WINDOW) {
errorThrow("SDL_CreateWindow failed: %s", SDL_GetError());
}
#if RENDER_USE_FRAMEBUFFER
printf("Using framebuffer for rendering\n");
#else
printf("Using window for rendering\n");
#endif
// Create renderer
RENDER_RENDERER = SDL_CreateRenderer(
RENDER_WINDOW,
-1,
SDL_RENDERER_ACCELERATED
);
if(!RENDER_RENDERER) {
errorThrow("SDL_CreateRenderer failed: %s", SDL_GetError());
}
// Create back buffer.
renderBackBufferInit();
// Init other things
renderTextInit();
// Mark ready.
RENDER_RUNNING = true;
errorOk();
@@ -58,23 +66,27 @@ errorret_t renderDraw(void) {
}
}
SDL_SetRenderDrawColor(RENDER_RENDERER, 0, 0, 0, 255);
SDL_RenderClear(RENDER_RENDERER);
// Bind the backbuffer
renderBackBufferBind();
// Draw red triangle
SDL_SetRenderDrawColor(RENDER_RENDERER, 255, 0, 0, 255);
SDL_RenderDrawLine(RENDER_RENDERER, 100, 100, 200, 100);
SDL_RenderDrawLine(RENDER_RENDERER, 200, 100, 150, 50);
SDL_RenderDrawLine(RENDER_RENDERER, 150, 50, 100, 100);
// Draw everything
renderTextDraw(0.0f, 0.0f, "Hello World!");
// Unbind the backbuffer
renderBackBufferUnbind();
renderBackBufferDraw();
// Draw things that render above the back buffer quad.
// Present the renderer
SDL_RenderPresent(RENDER_RENDERER);
RENDER_FRAME++;
errorOk();
}
errorret_t renderDispose(void) {
renderBackBufferDispose();
SDL_DestroyRenderer(RENDER_RENDERER);
SDL_DestroyWindow(RENDER_WINDOW);
SDL_Quit();

View File

@@ -6,6 +6,7 @@
*/
#include "renderbackbuffer.h"
#include "render.h"
#if RENDER_USE_FRAMEBUFFER
SDL_Texture *RENDER_BACKBUFFER;
@@ -13,23 +14,81 @@ SDL_Texture *RENDER_BACKBUFFER;
#endif
void renderBackBufferInit(void) {
errorret_t renderBackBufferInit(void) {
#if RENDER_USE_FRAMEBUFFER
RENDER_BACKBUFFER = SDL_CreateTexture(
RENDER_RENDERER,
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
RENDER_WINDOW_WIDTH_DEFAULT,
RENDER_WINDOW_HEIGHT_DEFAULT
RENDER_WIDTH,
RENDER_HEIGHT
);
if(!RENDER_BACKBUFFER) {
assertUnreachable("SDL_CreateTexture failed\n");
return;
errorThrow("SDL_CreateTexture failed: %s", SDL_GetError());
}
// Make sure we unbind the back buffer after creation
SDL_SetRenderTarget(RENDER_RENDERER, NULL);
#else
// No back buffer needed for window rendering
#endif
errorOk();
}
void renderBackBufferBind(void) {
#if RENDER_USE_FRAMEBUFFER
SDL_SetRenderTarget(RENDER_RENDERER, RENDER_BACKBUFFER);
#endif
// Fill background with cornflower blue.
SDL_SetRenderDrawColor(RENDER_RENDERER, 100, 149, 237, 255);
SDL_RenderClear(RENDER_RENDERER);
}
void renderBackBufferUnbind(void) {
#if RENDER_USE_FRAMEBUFFER
SDL_SetRenderTarget(RENDER_RENDERER, NULL);
#endif
}
void renderBackBufferDraw(void) {
#if RENDER_USE_FRAMEBUFFER
// Clear background black
SDL_SetRenderDrawColor(RENDER_RENDERER, 0, 0, 0, 255);
SDL_RenderClear(RENDER_RENDERER);
// Create a quad that is scaled to fit but maintain original aspect ratio
int32_t windowWidth, windowHeight;
SDL_GetWindowSize(RENDER_WINDOW, &windowWidth, &windowHeight);
int32_t renderWidth, renderHeight, renderX, renderY;
if(RENDER_WIDTH * windowHeight > RENDER_HEIGHT * windowWidth) {
renderWidth = windowWidth;
renderHeight = (RENDER_HEIGHT * windowWidth) / RENDER_WIDTH;
renderX = 0;
renderY = (windowHeight - renderHeight) / 2;
} else {
renderWidth = (RENDER_WIDTH * windowHeight) / RENDER_HEIGHT;
renderHeight = windowHeight;
renderX = (windowWidth - renderWidth) / 2;
renderY = 0;
}
// Draw the back buffer texture
SDL_Rect destRect = { renderX, renderY, renderWidth, renderHeight };
SDL_RenderCopy(RENDER_RENDERER, RENDER_BACKBUFFER, NULL, &destRect);
#else
// No back buffer to draw
#endif
}
errorret_t renderBackBufferDispose(void) {
#if RENDER_USE_FRAMEBUFFER
SDL_DestroyTexture(RENDER_BACKBUFFER);
RENDER_BACKBUFFER = NULL;
#endif
errorOk();
}

View File

@@ -6,4 +6,32 @@
*/
#pragma once
#include "dusksdl2.h"
#include "display/renderbase.h"
/**
* Initializes the render back buffer. May be either a framebuffer or a texture
* depending on the render settings.
*/
errorret_t renderBackBufferInit(void);
/**
* Binds the render back buffer as the current render target.
*/
void renderBackBufferBind(void);
/**
* Unbinds the render back buffer, returning to the default render target.
*/
void renderBackBufferUnbind(void);
/**
* Draws the render back buffer to the screen, scaling it to fit the window.
*/
void renderBackBufferDraw(void);
/**
* Disposes of the render back buffer, freeing any resources it holds.
*
* @return An error state if an error occurred, otherwise OK.
*/
errorret_t renderBackBufferDispose(void);

View File

@@ -0,0 +1,113 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "rendertext.h"
#include "render.h"
#include "ui/font.h"
#include "assert/assert.h"
SDL_Texture* RENDER_TEXT_TEXTURE = NULL;
void renderTextInit(void) {
const int32_t cols = FONT_COLUMN_COUNT;
const int32_t rows = (FONT_TILE_COUNT + cols - 1) / cols;
const int32_t fontWidth = cols * FONT_TILE_WIDTH;
const int32_t fontHeight = rows * FONT_TILE_HEIGHT;
// RGBA8888 surface
SDL_Surface* surface = SDL_CreateRGBSurfaceWithFormat(
0,
fontWidth,
fontHeight,
32,
SDL_PIXELFORMAT_RGBA32
);
assertNotNull(surface, "Failed to create surface for text rendering");
const int32_t pitch_px = surface->pitch / 4;
uint32_t *pixels = (uint32_t *)surface->pixels;
for(int tileIndex = 0; tileIndex < FONT_TILE_COUNT; ++tileIndex) {
const int32_t tileX = (tileIndex % FONT_COLUMN_COUNT) * FONT_TILE_WIDTH;
const int32_t tileY = (tileIndex / FONT_COLUMN_COUNT) * FONT_TILE_HEIGHT;
const uint8_t* tile = TILE_PIXEL_DATA[tileIndex];
for (int y = 0; y < FONT_TILE_HEIGHT; ++y) {
for (int x = 0; x < FONT_TILE_WIDTH; ++x) {
const uint8_t color = tile[y * FONT_TILE_WIDTH + x] ? 0xFF : 0;
// Convert to RGBA (8 bits per channel)
const uint32_t rgba = color ? 0xFFFFFFFF : 0x00000000;
pixels[(tileY + y) * pitch_px + (tileX + x)] = rgba;
}
}
}
RENDER_TEXT_TEXTURE = SDL_CreateTextureFromSurface(
RENDER_RENDERER,
surface
);
assertNotNull(RENDER_TEXT_TEXTURE, "Failed to create texture from surface");
SDL_FreeSurface(surface);
SDL_SetTextureBlendMode(RENDER_TEXT_TEXTURE, SDL_BLENDMODE_BLEND);
}
void renderTextDrawChar(
const float_t x,
const float_t y,
const char_t c
) {
int32_t tileIndex = (int32_t)(c) - FONT_CHAR_START;
assertTrue(
tileIndex >= 0 && tileIndex < FONT_TILE_COUNT,
"Character is out of bounds for font tiles"
);
assertNotNull(RENDER_TEXT_TEXTURE, "Texture cannot be NULL");
const int32_t tileX = (tileIndex % FONT_COLUMN_COUNT) * FONT_TILE_WIDTH;
const int32_t tileY = (tileIndex / FONT_COLUMN_COUNT) * FONT_TILE_HEIGHT;
SDL_Rect srcRect = {
.x = tileX,
.y = tileY,
.w = FONT_TILE_WIDTH,
.h = FONT_TILE_HEIGHT
};
SDL_Rect dstRect = {
.x = (int32_t)roundf(x),
.y = (int32_t)roundf(y),
.w = FONT_TILE_WIDTH,
.h = FONT_TILE_HEIGHT
};
SDL_RenderCopy(RENDER_RENDERER, RENDER_TEXT_TEXTURE, &srcRect, &dstRect);
}
void renderTextDraw(
const float_t x,
const float_t y,
const char_t *text
) {
assertNotNull(text, "Text cannot be NULL");
float_t posX = x;
float_t posY = y;
char_t c;
int32_t i = 0;
while((c = text[i++]) != '\0') {
if(c == '\n') {
posX = x;
posY += FONT_TILE_HEIGHT;
continue;
}
renderTextDrawChar(posX, posY, c);
posX += FONT_TILE_WIDTH;
}
}

View File

@@ -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 "dusksdl2.h"
extern SDL_Texture* RENDER_TEXT_TEXTURE;
/**
* Initializes the text rendering system.
*/
void renderTextInit(void);
/**
* Draws a single character at the specified position.
*
* @param x The x-coordinate to draw the character at.
* @param y The y-coordinate to draw the character at.
* @param c The character to draw.
*/
void renderTextDrawChar(
const float_t x,
const float_t y,
const char_t c
);
/**
* Draws a string of text at the specified position.
*
* @param x The x-coordinate to draw the text at.
* @param y The y-coordinate to draw the text at.
* @param text The null-terminated string of text to draw.
*/
void renderTextDraw(
const float_t x,
const float_t y,
const char_t *text
);