6 Commits
Author SHA1 Message Date
odweta 18b7df5f0c refactor file structure 2026-10-06 12:07:12 +02:00
odweta 6ee6b1482b start using cmake 2026-10-06 12:05:26 +02:00
odweta 599ec6662a update gitignore 2026-10-06 12:04:54 +02:00
odweta 67bc093c54 Merge pull request 'allow for custom SDL window parameters' (#8) from feat/custom-sdl-window-params into dev
Reviewed-on: #8
2026-10-06 10:42:33 +02:00
odweta a32a3db9bc allow for custom SDL window parameters, fixes #5 2026-10-06 10:31:10 +02:00
odweta 6b3b5b0241 update demo window 2026-10-06 10:30:39 +02:00
18 changed files with 292 additions and 227 deletions
+4 -1
View File
@@ -1,2 +1,5 @@
.clangd
*.sublime-*
*.sublime-*
build/
src/engine/CMakeFiles
examples/CMakeFiles
+12
View File
@@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.20)
project(dangerzone LANGUAGES C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
find_package(PkgConfig REQUIRED)
pkg_check_modules(SDL3 REQUIRED IMPORTED_TARGET sdl3)
add_subdirectory(src/engine)
add_subdirectory(src/examples)
-41
View File
@@ -1,41 +0,0 @@
CC := gcc
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/text.c
OUT := build/main
SNAKE_SRC := src/examples/snake.c $(SRC)
SNAKE := build/snake
2048_SRC := src/examples/2048.c $(SRC)
2048 := build/2048
build:
$(CC) -o $(OUT) -O3 -DNDEBUG src/main.c $(SRC) $(INC) $(LIBS)
run:
$(OUT)
build-snake:
$(CC) -o $(SNAKE) -O3 -DNDEBUG $(SNAKE_SRC) $(INC) $(LIBS)
run-snake:
$(SNAKE)
clean-snake:
rm $(SNAKE)
build-2048:
$(CC) -o $(2048) -O3 -DNDEBUG $(2048_SRC) $(INC) $(LIBS)
run-2048:
$(2048)
clean-2048:
rm $(2048)
clean:
rm $(OUT)
.PHONY: build run
+31
View File
@@ -0,0 +1,31 @@
#pragma once
#include <SDL3/SDL.h>
#include <stdbool.h>
#include <stdint.h>
typedef struct {
SDL_Event event;
bool is_running;
bool framebuffer_dirty;
SDL_Rect dirty_rect;
uint16_t width, height;
uint32_t *framebuffer;
} game_state_t;
extern game_state_t *game_state;
bool
engine_init(
uint32_t window_width,
uint32_t window_height,
const char window_name[],
void (*engine_poll_events)(void),
void (*engine_update_framebuffer)(void)
);
void
engine_start();
void
engine_stop();
+15
View File
@@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
void
put_pixel(
unsigned int x,
unsigned int y,
uint32_t color
);
void
clear_framebuffer(
uint32_t color
);
+18
View File
@@ -0,0 +1,18 @@
#pragma once
#include <stdint.h>
void
put_rect(
uint32_t x,
uint32_t y,
uint32_t w,
uint32_t h,
uint32_t color
);
void
clear_rect(int x, int y, int w, int h, uint32_t color);
void
mark_dirty_rect(int x, int y, int w, int h);
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
void
put_char(
char c,
uint32_t x,
uint32_t y,
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
);
-119
View File
@@ -1,119 +0,0 @@
#pragma once
#include <SDL3/SDL.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define WINDOW_WIDTH 1280
#define WINDOW_HEIGHT 720
#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];
uint16_t width, height;
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
} engine_sdl_state_t;
typedef struct {
/**
* this function runs inside of the SDL_PollEvent loop
* useful for user input, quitting the program and so on
*/
void (*engine_poll_events)(void);
/**
* meant as the "area" for manupulating the framebuffer;
* after this is executed, the contents of
* game_state->framebuffer get drawn
*/
void (*engine_update_framebuffer)(void);
engine_sdl_state_t *sdl_state;
} engine_internal_state_t;
typedef struct {
uint32_t framebuffer[WINDOW_WIDTH * WINDOW_HEIGHT];
SDL_Event event;
bool is_running;
bool framebuffer_dirty;
SDL_Rect dirty_rect;
uint16_t width, height;
} game_state_t;
extern engine_internal_state_t *internal_state;
extern game_state_t *game_state;
engine_sdl_state_t*
engine_sdl_init();
void
engine_sdl_destroy(
engine_sdl_state_t *state
);
bool
engine_init(
void (*engine_poll_events)(void),
void (*engine_update_framebuffer)(void)
);
void
engine_start();
void
engine_stop();
void
put_pixel(
unsigned int x,
unsigned int y,
uint32_t color
);
void
put_rect(
uint32_t x,
uint32_t y,
uint32_t w,
uint32_t h,
uint32_t color
);
void
clear_framebuffer(
uint32_t color
);
void
clear_rect(int x, int y, int w, int h, uint32_t color);
void
mark_dirty_rect(int x, int y, int w, int h);
void
put_char(
char c,
uint32_t x,
uint32_t y,
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
);
+19
View File
@@ -0,0 +1,19 @@
file(GLOB_RECURSE ENGINE_SOURCES CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/*.c"
)
add_library(dangerzone_engine STATIC
${ENGINE_SOURCES}
)
target_include_directories(dangerzone_engine
PUBLIC
${PROJECT_SOURCE_DIR}/include
PRIVATE
${PROJECT_SOURCE_DIR}/src
)
target_link_libraries(dangerzone_engine
PUBLIC
PkgConfig::SDL3
)
+5 -2
View File
@@ -1,4 +1,6 @@
#include "engine.h"
#include <dangerzone/engine.h>
#include "internal/engine_internal.h"
engine_internal_state_t *internal_state = NULL;
game_state_t *game_state = NULL;
@@ -172,5 +174,6 @@ void
engine_stop() {
engine_sdl_destroy(internal_state->sdl_state);
free(internal_state);
free(game_state);
free(game_state->framebuffer);
free(game_state);
}
+43 -13
View File
@@ -1,10 +1,15 @@
#include "engine.h"
#include "error.h"
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_video.h>
#include <dangerzone/engine.h>
#include "internal/engine_internal.h"
#include "internal/util/error.h"
bool
engine_sdl_init_state(engine_sdl_state_t **state) {
engine_sdl_init_state(
engine_sdl_state_t **state,
uint32_t window_width,
uint32_t window_height,
const char window_name[]
) {
*state = (engine_sdl_state_t *)
malloc(sizeof(engine_sdl_state_t));
@@ -13,12 +18,13 @@ engine_sdl_init_state(engine_sdl_state_t **state) {
return RCODE_FAILURE;
}
(*state)->width = WINDOW_WIDTH;
(*state)->height = WINDOW_HEIGHT;
(*state)->width = window_width;
(*state)->height = window_height;
strncpy(
(*state)->window_name, DEFAULT_WINDOW_NAME,
WINDOW_NAME_LENGTH
(*state)->window_name, window_name,
WINDOW_NAME_MAX_LENGTH - 1
);
(*state)->window_name[WINDOW_NAME_MAX_LENGTH - 1] = '\0';
return RCODE_SUCCESS;
}
@@ -94,11 +100,19 @@ engine_sdl_init_texture(
}
engine_sdl_state_t*
engine_sdl_init()
{
engine_sdl_init(
uint32_t window_width,
uint32_t window_height,
const char window_name[]
) {
engine_sdl_state_t *state;
if (!engine_sdl_init_state(&state) ||
if (!engine_sdl_init_state(
&state,
window_width,
window_height,
window_name
) ||
!engine_sdl_init_root() ||
!engine_sdl_init_window(state) ||
!engine_sdl_init_renderer(state) ||
@@ -127,6 +141,9 @@ engine_sdl_destroy(
bool
engine_init(
uint32_t window_width,
uint32_t window_height,
const char window_name[],
void (*engine_poll_events)(void),
void (*engine_update_framebuffer)(void)
) {
@@ -143,15 +160,28 @@ engine_init(
return RCODE_FAILURE;
}
game_state->framebuffer = (uint32_t *)
malloc(sizeof(uint32_t) * window_width * window_height);
if (game_state->framebuffer == NULL) {
free(internal_state);
free(game_state);
return RCODE_FAILURE;
}
internal_state->engine_poll_events
= engine_poll_events;
internal_state->engine_update_framebuffer
= engine_update_framebuffer;
internal_state->sdl_state = engine_sdl_init();
internal_state->sdl_state = engine_sdl_init(
window_width,
window_height,
window_name
);
if (internal_state->sdl_state == NULL) {
free(internal_state);
free(game_state->framebuffer);
free(game_state);
return RCODE_FAILURE;
}
+48
View File
@@ -0,0 +1,48 @@
#include <dangerzone/engine.h>
#include <dangerzone/render/misc.h>
#include <dangerzone/render/rect.h>
#include "internal/util/error.h"
#include <stdint.h>
// alter a pixel at an imaginary x & y coordinates
void
put_pixel(
unsigned int x,
unsigned int y,
uint32_t color
) {
uint16_t w = game_state->width;
uint16_t h = game_state->height;
if (x < 0 || x >= w || y < 0 || y >= h) {
eprintf(
"CRITICAL: attempted buffer overflow in put_pixel\n"
"at x = %d, y = %d", x, y
);
} else {
game_state->framebuffer[game_state->width * y + x]
= color;
mark_dirty_rect(x, y, 1, 1);
}
}
// fill the entire framebuffer with a given color
void
clear_framebuffer(
uint32_t color
) {
for (size_t i = 0;
i < (size_t)game_state->width * game_state->height;
++i) {
game_state->framebuffer[i] = color;
}
mark_dirty_rect(
0,
0,
game_state->width,
game_state->height
);
}
@@ -1,30 +1,9 @@
#include "engine.h"
#include "error.h"
#include <dangerzone/engine.h>
#include <dangerzone/render/misc.h>
#include <dangerzone/render/rect.h>
#include <stdint.h>
// alter a pixel at an imaginary x & y coordinates
void
put_pixel(
unsigned int x,
unsigned int y,
uint32_t color
) {
uint16_t w = game_state->width;
uint16_t h = game_state->height;
if (x < 0 || x >= w || y < 0 || y >= h) {
eprintf(
"CRITICAL: attempted buffer overflow in put_pixel\n"
"at x = %d, y = %d", x, y
);
} else {
game_state->framebuffer[game_state->width * y + x]
= color;
mark_dirty_rect(x, y, 1, 1);
}
}
/**
* draws a rectangle with its left-top corner at (x,y) with
* a width of 'w' and height of 'h' filled with color 'color'
@@ -45,25 +24,6 @@ put_rect(
mark_dirty_rect(x, y, w, h);
}
// fill the entire framebuffer with a given color
void
clear_framebuffer(
uint32_t color
) {
for (size_t i = 0;
i < (size_t)game_state->width * game_state->height;
++i) {
game_state->framebuffer[i] = color;
}
mark_dirty_rect(
0,
0,
game_state->width,
game_state->height
);
}
void
clear_rect(int x, int y, int w, int h, uint32_t color)
{
@@ -1,7 +1,10 @@
// rendering characters in the framebuffer
#include "engine.h"
#include <stdint.h>
#include <dangerzone/engine.h>
#include <dangerzone/render/rect.h>
#include <dangerzone/render/text.h>
#include "internal/engine_internal.h"
/*
* each character has 8 rows
+8
View File
@@ -0,0 +1,8 @@
#add_executable(snake snake.c)
#target_link_libraries(snake PRIVATE dangerzone_engine)
#add_executable(game_2048 2048.c)
#target_link_libraries(game_2048 PRIVATE dangerzone_engine)
add_executable(game_window window.c)
target_link_libraries(game_window PRIVATE dangerzone_engine)
+7 -5
View File
@@ -1,4 +1,6 @@
#include "engine.h"
#include <dangerzone/engine.h>
#include <dangerzone/render/misc.h>
#include <dangerzone/render/text.h>
// polling events every frame
void
@@ -25,10 +27,8 @@ client_poll_event()
void
client_update_framebuffer()
{
// single green demo pixel
game_state->framebuffer[0] = 0x00FF00;
put_rect(0, 0, 1100, 200, 0xFFFF00);
// example window contents
clear_framebuffer(0xFFFF00);
put_string("Hello, traveller. You have come\nto the right place!",
20, 20, 2, 2, 3, 0x000000, 0xFFFF00
);
@@ -39,6 +39,8 @@ main()
{
// initialize the engine
if (engine_init(
500, 100,
"Dangerzone",
client_poll_event,
client_update_framebuffer
)) {
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#include <SDL3/SDL.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#define WINDOW_NAME_MAX_LENGTH 128
#define FONT_ROWS 7
#define FONT_COLS 5
typedef struct {
char window_name[WINDOW_NAME_MAX_LENGTH];
uint16_t width, height;
SDL_Window *window;
SDL_Renderer *renderer;
SDL_Texture *texture;
} engine_sdl_state_t;
typedef struct {
/**
* this function runs inside of the SDL_PollEvent loop
* useful for user input, quitting the program and so on
*/
void (*engine_poll_events)(void);
/**
* meant as the "area" for manupulating the framebuffer;
* after this is executed, the contents of
* game_state->framebuffer get drawn
*/
void (*engine_update_framebuffer)(void);
engine_sdl_state_t *sdl_state;
} engine_internal_state_t;
extern engine_internal_state_t *internal_state;
engine_sdl_state_t*
engine_sdl_init(
uint32_t window_width,
uint32_t window_height,
const char window_name[]
);
void
engine_sdl_destroy(
engine_sdl_state_t *state
);