2 Commits
Author SHA1 Message Date
odweta e72588f792 update README with text 2026-10-05 02:27:32 +02:00
odweta 760d2abc6c add basic text rendering 2026-10-05 02:24:13 +02:00
7 changed files with 185 additions and 24 deletions
+3 -2
View File
@@ -3,13 +3,14 @@ LIBS := `pkg-config --libs sdl3`
INC := `pkg-config --cflags sdl3` -I./include
SRC := src/engine/engine.c \
src/engine/engine_init.c \
src/engine/render.c
src/engine/render.c \
src/engine/text.c
OUT := build/main
SNAKE_SRC := src/examples/snake.c $(SRC)
SNAKE := build/snake
build:
$(CC) -o $(OUT) $(SRC) $(INC) $(LIBS)
$(CC) -o $(OUT) src/main.c $(SRC) $(INC) $(LIBS)
run:
$(OUT)
+17 -1
View File
@@ -7,7 +7,7 @@
1. Put Pixel - Lets you color one given pixel in the framebuffer.
```c
void put_pixel(unsigned int x, unsigned int y, uint32_t color);
void put_pixel(uint32_t x, uint32_t y, uint32_t color);
```
2. Clear Framebuffer - Lets you fill the entire framebuffer with one color.
@@ -16,6 +16,22 @@ void put_pixel(unsigned int x, unsigned int y, uint32_t color);
void clear_framebuffer(uint32_t color);
```
3. Put String - Lets you display multiline text with a size, foreground and background color on a given (x,y). You can specify the spacing between letters and lines. Supported characters are in `text.c` - feel free to add some if you want to.
```c
void
put_string(
const char *text,
uint32_t x,
uint32_t y,
uint32_t size,
uint32_t spacing,
uint32_t line_spacing,
uint32_t fg_color,
uint32_t bg_color
);
```
#### Usage
The main function of a program that uses this engine should look something like this:
+17 -1
View File
@@ -11,6 +11,8 @@
#define DEFAULT_WINDOW_NAME "Dangerzone"
#define WINDOW_NAME_LENGTH 128
#define TARGET_FRAME 1.0 / 60.0
#define FONT_ROWS 7
#define FONT_COLS 5
typedef struct {
char window_name[WINDOW_NAME_LENGTH];
@@ -91,5 +93,19 @@ put_char(
char c,
uint32_t x,
uint32_t y,
uint8_t size
uint32_t size,
uint32_t fg_color,
uint32_t bg_color
);
void
put_string(
const char *text,
uint32_t x,
uint32_t y,
uint32_t size,
uint32_t spacing,
uint32_t line_spacing,
uint32_t fg_color,
uint32_t bg_color
);
+1
View File
@@ -1,5 +1,6 @@
#include "engine.h"
#include "error.h"
#include <stdint.h>
// alter a pixel at an imaginary x & y coordinates
void
+141
View File
@@ -0,0 +1,141 @@
// rendering characters in the framebuffer
#include "engine.h"
#include <stdint.h>
/*
* each character has 8 rows
* only the lower 4 bits of each byte are used
*/
static const uint8_t font[128][FONT_ROWS] = {
[' '] = { 0, 0, 0, 0, 0, 0, 0 },
['A'] = { 0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11 },
['B'] = { 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E },
['C'] = { 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x0F },
['D'] = { 0x1E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1E },
['E'] = { 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F },
['F'] = { 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10 },
['G'] = { 0x0F, 0x10, 0x10, 0x17, 0x11, 0x11, 0x0F },
['H'] = { 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11 },
['I'] = { 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x1F },
['J'] = { 0x01, 0x01, 0x01, 0x01, 0x11, 0x11, 0x0E },
['K'] = { 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11 },
['L'] = { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F },
['M'] = { 0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11 },
['N'] = { 0x11, 0x19, 0x15, 0x13, 0x11, 0x11, 0x11 },
['O'] = { 0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E },
['P'] = { 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10 },
['Q'] = { 0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D },
['R'] = { 0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11 },
['S'] = { 0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E },
['T'] = { 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 },
['U'] = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E },
['V'] = { 0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04 },
['W'] = { 0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0A },
['X'] = { 0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11 },
['Y'] = { 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04, 0x04 },
['Z'] = { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F },
['0'] = { 0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E },
['1'] = { 0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E },
['2'] = { 0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F },
['3'] = { 0x1E, 0x01, 0x01, 0x0E, 0x01, 0x01, 0x1E },
['4'] = { 0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02 },
['5'] = { 0x1F, 0x10, 0x10, 0x1E, 0x01, 0x01, 0x1E },
['6'] = { 0x0E, 0x10, 0x10, 0x1E, 0x11, 0x11, 0x0E },
['7'] = { 0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08 },
['8'] = { 0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E },
['9'] = { 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x01, 0x0E },
['.'] = { 0, 0, 0, 0, 0, 0x0C, 0x0C },
[','] = { 0, 0, 0, 0, 0, 0x0C, 0x08 },
[':'] = { 0, 0x0C, 0x0C, 0, 0, 0x0C, 0x0C },
[';'] = { 0, 0x0C, 0x0C, 0, 0, 0x0C, 0x08 },
['!'] = { 0x04, 0x04, 0x04, 0x04, 0x04, 0, 0x04 },
['?'] = { 0x0E, 0x11, 0x01, 0x02, 0x04, 0, 0x04 },
['-'] = { 0, 0, 0, 0x1F, 0, 0, 0 },
['_'] = { 0, 0, 0, 0, 0, 0, 0x1F },
['+'] = { 0, 0x04, 0x04, 0x1F, 0x04, 0x04, 0 },
['='] = { 0, 0x1F, 0, 0, 0x1F, 0, 0 },
['/'] = { 0x01, 0x01, 0x02, 0x04, 0x08, 0x10, 0x10 },
['\\'] = { 0x10, 0x10, 0x08, 0x04, 0x02, 0x01, 0x01 },
['('] = { 0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02 },
[')'] = { 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08 },
['['] = { 0x0E, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0E },
[']'] = { 0x0E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x0E },
['<'] = { 0x02, 0x04, 0x08, 0x10, 0x08, 0x04, 0x02 },
['>'] = { 0x08, 0x04, 0x02, 0x01, 0x02, 0x04, 0x08 },
['*'] = { 0, 0x15, 0x0E, 0x1F, 0x0E, 0x15, 0 },
['#'] = { 0x0A, 0x0A, 0x1F, 0x0A, 0x1F, 0x0A, 0x0A },
['%'] = { 0x19, 0x19, 0x02, 0x04, 0x08, 0x13, 0x13 },
['@'] = { 0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0F }
};
/**
* put a char 'c' on 'x' and 'y' in the framebuffer
* with a foreground color of 'color'
*/
void
put_char(
char c,
uint32_t x,
uint32_t y,
uint32_t size,
uint32_t fg_color,
uint32_t bg_color
) {
// convert lowercase letters to uppercase
if (c >= 'a' && c <= 'z') {
c -= 'a' - 'A';
}
// avoid indexing outside font[128]
if ((unsigned char)c >= 128) {
c = '?';
}
for (uint32_t row = 0; row < FONT_ROWS; row++) {
uint8_t bits = font[(unsigned char)c][row];
for (uint32_t col = 0; col < FONT_COLS; col++) {
uint32_t color =
bits & (1u << (FONT_COLS - 1 - col))
? fg_color : bg_color;
put_rect(
x + col * size,
y + row * size,
size,
size,
color
);
}
}
}
void
put_string(
const char *text,
uint32_t x,
uint32_t y,
uint32_t size,
uint32_t spacing,
uint32_t line_spacing,
uint32_t fg_color,
uint32_t bg_color
) {
uint32_t start_x = x;
while (*text) {
if (*text == '\n') {
x = start_x;
y += (FONT_ROWS + line_spacing) * size;
} else {
put_char(*text, x, y, size, fg_color, bg_color);
x += (FONT_COLS + spacing) * size;
}
text++;
}
}
-19
View File
@@ -88,25 +88,6 @@ client_poll_event()
}
}
/**
* draws a rectangle with its left-top corner at (x,y) with
* a width of 'w' and height of 'h' filled with color 'color'
*/
void
put_rect(
unsigned int x,
unsigned int y,
unsigned int w,
unsigned int h,
uint32_t color
) {
for (int i = x; i < x + w; i++) {
for (int j = y; j < y + h; j++) {
put_pixel(i, j, color);
}
}
}
// a wrapper function for put_rect using a v2 struct
void
put_rect_v2(
+6 -1
View File
@@ -18,7 +18,7 @@ client_poll_event()
default:
break;
}
}
}
}
/**
@@ -31,6 +31,11 @@ client_update_framebuffer()
{
// single green demo pixel
game_state->framebuffer[0] = 0x00FF00;
put_rect(0, 0, 1100, 200, 0xFFFF00);
put_string("Hello, traveller. You have come\nto the right place!",
20, 20, 2, 2, 3, 0x000000, 0xFFFF00
);
}
int