diff --git a/.gitignore b/.gitignore index abbdf74..090bf13 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,5 @@ .clangd -*.sublime-* \ No newline at end of file +*.sublime-* +build/ +src/engine/CMakeFiles +examples/CMakeFiles \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d7fb178 --- /dev/null +++ b/CMakeLists.txt @@ -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) diff --git a/Makefile b/Makefile deleted file mode 100644 index 78392bf..0000000 --- a/Makefile +++ /dev/null @@ -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 \ No newline at end of file diff --git a/include/dangerzone/engine.h b/include/dangerzone/engine.h new file mode 100644 index 0000000..114481d --- /dev/null +++ b/include/dangerzone/engine.h @@ -0,0 +1,31 @@ +#pragma once + +#include +#include +#include + +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(); \ No newline at end of file diff --git a/include/dangerzone/render/misc.h b/include/dangerzone/render/misc.h new file mode 100644 index 0000000..10a9b46 --- /dev/null +++ b/include/dangerzone/render/misc.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +void +put_pixel( + unsigned int x, + unsigned int y, + uint32_t color +); + +void +clear_framebuffer( + uint32_t color +); \ No newline at end of file diff --git a/include/dangerzone/render/rect.h b/include/dangerzone/render/rect.h new file mode 100644 index 0000000..e5ea19b --- /dev/null +++ b/include/dangerzone/render/rect.h @@ -0,0 +1,18 @@ +#pragma once + +#include + +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); \ No newline at end of file diff --git a/include/dangerzone/render/text.h b/include/dangerzone/render/text.h new file mode 100644 index 0000000..a7e767d --- /dev/null +++ b/include/dangerzone/render/text.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +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 +); \ No newline at end of file diff --git a/include/engine.h b/include/engine.h deleted file mode 100644 index 709bbed..0000000 --- a/include/engine.h +++ /dev/null @@ -1,123 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#define WINDOW_NAME_MAX_LENGTH 128 -#define TARGET_FRAME 1.0 / 60.0 -#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; - -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 engine_internal_state_t *internal_state; -extern game_state_t *game_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 -); - -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(); - -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 -); \ No newline at end of file diff --git a/src/engine/CMakeLists.txt b/src/engine/CMakeLists.txt new file mode 100644 index 0000000..6d0ce2b --- /dev/null +++ b/src/engine/CMakeLists.txt @@ -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 +) diff --git a/src/engine/engine.c b/src/engine/engine.c index dda5bb7..2a46828 100644 --- a/src/engine/engine.c +++ b/src/engine/engine.c @@ -1,4 +1,6 @@ -#include "engine.h" +#include + +#include "internal/engine_internal.h" engine_internal_state_t *internal_state = NULL; game_state_t *game_state = NULL; diff --git a/src/engine/engine_init.c b/src/engine/engine_init.c index 8e8b65d..1a360c8 100644 --- a/src/engine/engine_init.c +++ b/src/engine/engine_init.c @@ -1,8 +1,7 @@ -#include "engine.h" -#include "error.h" -#include -#include -#include +#include + +#include "internal/engine_internal.h" +#include "internal/util/error.h" bool engine_sdl_init_state( diff --git a/src/engine/render/misc.c b/src/engine/render/misc.c new file mode 100644 index 0000000..2e8159a --- /dev/null +++ b/src/engine/render/misc.c @@ -0,0 +1,48 @@ +#include +#include +#include + +#include "internal/util/error.h" +#include + +// 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 + ); +} \ No newline at end of file diff --git a/src/engine/render.c b/src/engine/render/rect.c similarity index 50% rename from src/engine/render.c rename to src/engine/render/rect.c index 610b399..ab6b74c 100644 --- a/src/engine/render.c +++ b/src/engine/render/rect.c @@ -1,30 +1,9 @@ -#include "engine.h" -#include "error.h" +#include +#include +#include + #include -// 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) { diff --git a/src/engine/text.c b/src/engine/render/text.c similarity index 97% rename from src/engine/text.c rename to src/engine/render/text.c index bb58e4b..3a660c8 100644 --- a/src/engine/text.c +++ b/src/engine/render/text.c @@ -1,7 +1,10 @@ // rendering characters in the framebuffer -#include "engine.h" -#include +#include +#include +#include + +#include "internal/engine_internal.h" /* * each character has 8 rows diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt new file mode 100644 index 0000000..00e3515 --- /dev/null +++ b/src/examples/CMakeLists.txt @@ -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) diff --git a/src/main.c b/src/examples/window.c similarity index 88% rename from src/main.c rename to src/examples/window.c index 8555589..1726dab 100644 --- a/src/main.c +++ b/src/examples/window.c @@ -1,4 +1,6 @@ -#include "engine.h" +#include +#include +#include // polling events every frame void diff --git a/src/internal/engine_internal.h b/src/internal/engine_internal.h new file mode 100644 index 0000000..80e42e9 --- /dev/null +++ b/src/internal/engine_internal.h @@ -0,0 +1,48 @@ +#pragma once + +#include +#include +#include +#include +#include + +#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 +); \ No newline at end of file diff --git a/include/error.h b/src/internal/util/error.h similarity index 100% rename from include/error.h rename to src/internal/util/error.h