Render textg
This commit is contained in:
@@ -5,6 +5,4 @@
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "display/render.h"
|
||||
|
||||
uint8_t RENDER_FRAME = 0;
|
||||
#include "display/render.h"
|
@@ -15,8 +15,6 @@
|
||||
#define RENDER_HEIGHT 240
|
||||
#endif
|
||||
|
||||
extern uint8_t RENDER_FRAME;
|
||||
|
||||
/**
|
||||
* Initializes the rendering system.
|
||||
*/
|
||||
|
@@ -7,6 +7,8 @@
|
||||
target_sources(${DUSK_TARGET_NAME}
|
||||
PRIVATE
|
||||
render.c
|
||||
renderbackbuffer.c
|
||||
rendertext.c
|
||||
)
|
||||
|
||||
# Subdirs
|
||||
|
@@ -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);
|
||||
|
||||
// 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);
|
||||
// Bind the backbuffer
|
||||
renderBackBufferBind();
|
||||
|
||||
// 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();
|
||||
|
@@ -6,30 +6,89 @@
|
||||
*/
|
||||
|
||||
#include "renderbackbuffer.h"
|
||||
#include "render.h"
|
||||
|
||||
#if RENDER_USE_FRAMEBUFFER
|
||||
SDL_Texture *RENDER_BACKBUFFER;
|
||||
SDL_Texture *RENDER_BACKBUFFER;
|
||||
#else
|
||||
|
||||
#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();
|
||||
}
|
@@ -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);
|
113
src/dusksdl2/display/rendertext.c
Normal file
113
src/dusksdl2/display/rendertext.c
Normal 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;
|
||||
}
|
||||
}
|
42
src/dusksdl2/display/rendertext.h
Normal file
42
src/dusksdl2/display/rendertext.h
Normal 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
|
||||
);
|
Reference in New Issue
Block a user