Render textg
This commit is contained in:
@@ -5,6 +5,4 @@
|
|||||||
* https://opensource.org/licenses/MIT
|
* https://opensource.org/licenses/MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "display/render.h"
|
#include "display/render.h"
|
||||||
|
|
||||||
uint8_t RENDER_FRAME = 0;
|
|
@@ -15,8 +15,6 @@
|
|||||||
#define RENDER_HEIGHT 240
|
#define RENDER_HEIGHT 240
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern uint8_t RENDER_FRAME;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the rendering system.
|
* Initializes the rendering system.
|
||||||
*/
|
*/
|
||||||
|
@@ -7,6 +7,8 @@
|
|||||||
target_sources(${DUSK_TARGET_NAME}
|
target_sources(${DUSK_TARGET_NAME}
|
||||||
PRIVATE
|
PRIVATE
|
||||||
render.c
|
render.c
|
||||||
|
renderbackbuffer.c
|
||||||
|
rendertext.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# Subdirs
|
# Subdirs
|
||||||
|
@@ -7,12 +7,15 @@
|
|||||||
|
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
|
#include "renderbackbuffer.h"
|
||||||
|
#include "rendertext.h"
|
||||||
|
|
||||||
SDL_Window *RENDER_WINDOW;
|
SDL_Window *RENDER_WINDOW;
|
||||||
SDL_Renderer *RENDER_RENDERER;
|
SDL_Renderer *RENDER_RENDERER;
|
||||||
bool_t RENDER_RUNNING;
|
bool_t RENDER_RUNNING;
|
||||||
|
|
||||||
errorret_t renderInit(void) {
|
errorret_t renderInit(void) {
|
||||||
|
// Init SDL
|
||||||
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
|
if(SDL_Init(SDL_INIT_VIDEO) != 0) {
|
||||||
errorThrow(
|
errorThrow(
|
||||||
"SDL Failed to Initialize: %s",
|
"SDL Failed to Initialize: %s",
|
||||||
@@ -20,31 +23,36 @@ errorret_t renderInit(void) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create window.
|
||||||
RENDER_WINDOW = SDL_CreateWindow(
|
RENDER_WINDOW = SDL_CreateWindow(
|
||||||
"DuskSDL2",
|
"DuskSDL2",
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
RENDER_WINDOW_WIDTH_DEFAULT,
|
RENDER_WINDOW_WIDTH_DEFAULT,
|
||||||
RENDER_WINDOW_HEIGHT_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
|
// Create renderer
|
||||||
printf("Using framebuffer for rendering\n");
|
|
||||||
#else
|
|
||||||
printf("Using window for rendering\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
RENDER_RENDERER = SDL_CreateRenderer(
|
RENDER_RENDERER = SDL_CreateRenderer(
|
||||||
RENDER_WINDOW,
|
RENDER_WINDOW,
|
||||||
-1,
|
-1,
|
||||||
SDL_RENDERER_ACCELERATED
|
SDL_RENDERER_ACCELERATED
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!RENDER_RENDERER) {
|
if(!RENDER_RENDERER) {
|
||||||
errorThrow("SDL_CreateRenderer failed: %s", SDL_GetError());
|
errorThrow("SDL_CreateRenderer failed: %s", SDL_GetError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create back buffer.
|
||||||
|
renderBackBufferInit();
|
||||||
|
|
||||||
|
// Init other things
|
||||||
|
renderTextInit();
|
||||||
|
|
||||||
|
// Mark ready.
|
||||||
RENDER_RUNNING = true;
|
RENDER_RUNNING = true;
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
@@ -58,23 +66,27 @@ errorret_t renderDraw(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SDL_SetRenderDrawColor(RENDER_RENDERER, 0, 0, 0, 255);
|
// Bind the backbuffer
|
||||||
SDL_RenderClear(RENDER_RENDERER);
|
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);
|
SDL_RenderPresent(RENDER_RENDERER);
|
||||||
|
|
||||||
RENDER_FRAME++;
|
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t renderDispose(void) {
|
errorret_t renderDispose(void) {
|
||||||
|
renderBackBufferDispose();
|
||||||
|
|
||||||
SDL_DestroyRenderer(RENDER_RENDERER);
|
SDL_DestroyRenderer(RENDER_RENDERER);
|
||||||
SDL_DestroyWindow(RENDER_WINDOW);
|
SDL_DestroyWindow(RENDER_WINDOW);
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
@@ -6,30 +6,89 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "renderbackbuffer.h"
|
#include "renderbackbuffer.h"
|
||||||
|
#include "render.h"
|
||||||
|
|
||||||
#if RENDER_USE_FRAMEBUFFER
|
#if RENDER_USE_FRAMEBUFFER
|
||||||
SDL_Texture *RENDER_BACKBUFFER;
|
SDL_Texture *RENDER_BACKBUFFER;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void renderBackBufferInit(void) {
|
errorret_t renderBackBufferInit(void) {
|
||||||
#if RENDER_USE_FRAMEBUFFER
|
#if RENDER_USE_FRAMEBUFFER
|
||||||
RENDER_BACKBUFFER = SDL_CreateTexture(
|
RENDER_BACKBUFFER = SDL_CreateTexture(
|
||||||
RENDER_RENDERER,
|
RENDER_RENDERER,
|
||||||
SDL_PIXELFORMAT_RGBA8888,
|
SDL_PIXELFORMAT_RGBA8888,
|
||||||
SDL_TEXTUREACCESS_TARGET,
|
SDL_TEXTUREACCESS_TARGET,
|
||||||
RENDER_WINDOW_WIDTH_DEFAULT,
|
RENDER_WIDTH,
|
||||||
RENDER_WINDOW_HEIGHT_DEFAULT
|
RENDER_HEIGHT
|
||||||
);
|
);
|
||||||
|
|
||||||
if(!RENDER_BACKBUFFER) {
|
if(!RENDER_BACKBUFFER) {
|
||||||
assertUnreachable("SDL_CreateTexture failed\n");
|
errorThrow("SDL_CreateTexture failed: %s", SDL_GetError());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure we unbind the back buffer after creation
|
||||||
|
SDL_SetRenderTarget(RENDER_RENDERER, NULL);
|
||||||
#else
|
#else
|
||||||
// No back buffer needed for window rendering
|
// No back buffer needed for window rendering
|
||||||
#endif
|
#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
|
#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