From d0dda33a7ab46a45c535120537e958057ee5a2e7 Mon Sep 17 00:00:00 2001 From: Ulysse Cura Date: Sun, 6 Sep 2026 08:59:30 +0200 Subject: [PATCH] Moved headers files into src folders, Started to change build chain, and moved core into its own drectory. --- .gitignore | 2 + .gitmodules | 3 - .vscode/settings.json | 8 +- LICENSE => LICENSE.txt | 0 Makefile | 18 +- README.md | 2 +- SDL3_Core | 1 - assets/asset_builder/src/Makefile | 2 +- .../asset_builder/src/{headers => }/errors.h | 0 .../asset_builder/src/{headers => }/image.h | 0 assets/asset_builder/src/{headers => }/map.h | 0 .../asset_builder/src/{headers => }/object.h | 0 .../asset_builder/src/{headers => }/utils.h | 0 configure | 145 ++++++ core/README.md | 9 + .../host/generic/display.c | 0 core/host/generic/display.h | 0 core/host/linux/Makefile | 0 core/src/.ccls | 8 + core/src/Makefile | 74 +++ core/src/asset_manager.c | 234 +++++++++ core/src/asset_manager.h | 48 ++ core/src/camera.c | 64 +++ core/src/camera.h | 16 + core/src/display.c | 188 +++++++ core/src/display.h | 35 ++ core/src/ecs.c | 222 ++++++++ core/src/ecs.h | 71 +++ core/src/errors.h | 57 ++ core/src/event_bus.c | 140 +++++ core/src/event_bus.h | 38 ++ core/src/game.h | 45 ++ core/src/inputs.c | 14 + core/src/inputs.h | 22 + core/src/keycodes.h | 15 + core/src/linked_list.c | 429 ++++++++++++++++ core/src/linked_list.h | 283 ++++++++++ core/src/main.c | 38 ++ core/src/map.c | 485 ++++++++++++++++++ core/src/map.h | 44 ++ core/src/memory_alloc.h | 6 + core/src/texture.c | 67 +++ core/src/texture.h | 13 + core/src/vector2d.c | 27 + core/src/vector2d.h | 153 ++++++ shell.nix | 1 + src/.ccls | 4 +- src/Makefile | 2 +- .../{headers => }/animation_system.h | 0 src/components/{headers => }/components.def | 0 src/components/{headers => }/components.h | 0 src/components/{headers => }/door_component.h | 0 .../{headers => }/hitbox_component.h | 0 .../{headers => }/interact_component.h | 0 .../{headers => }/lever_component.h | 0 src/components/lua_component.h | 0 src/components/{headers => }/physics_system.h | 0 src/components/{headers => }/player_system.h | 0 .../{headers => }/sprite_component.h | 0 .../{headers => }/transform_component.h | 0 60 files changed, 3012 insertions(+), 21 deletions(-) delete mode 100644 .gitmodules rename LICENSE => LICENSE.txt (100%) delete mode 160000 SDL3_Core rename assets/asset_builder/src/{headers => }/errors.h (100%) rename assets/asset_builder/src/{headers => }/image.h (100%) rename assets/asset_builder/src/{headers => }/map.h (100%) rename assets/asset_builder/src/{headers => }/object.h (100%) rename assets/asset_builder/src/{headers => }/utils.h (100%) create mode 100755 configure create mode 100644 core/README.md rename src/components/headers/lua_component.h => core/host/generic/display.c (100%) create mode 100644 core/host/generic/display.h create mode 100644 core/host/linux/Makefile create mode 100644 core/src/.ccls create mode 100644 core/src/Makefile create mode 100644 core/src/asset_manager.c create mode 100644 core/src/asset_manager.h create mode 100644 core/src/camera.c create mode 100644 core/src/camera.h create mode 100644 core/src/display.c create mode 100644 core/src/display.h create mode 100644 core/src/ecs.c create mode 100644 core/src/ecs.h create mode 100644 core/src/errors.h create mode 100644 core/src/event_bus.c create mode 100644 core/src/event_bus.h create mode 100644 core/src/game.h create mode 100644 core/src/inputs.c create mode 100644 core/src/inputs.h create mode 100644 core/src/keycodes.h create mode 100644 core/src/linked_list.c create mode 100644 core/src/linked_list.h create mode 100644 core/src/main.c create mode 100644 core/src/map.c create mode 100644 core/src/map.h create mode 100644 core/src/memory_alloc.h create mode 100644 core/src/texture.c create mode 100644 core/src/texture.h create mode 100644 core/src/vector2d.c create mode 100644 core/src/vector2d.h rename src/components/{headers => }/animation_system.h (100%) rename src/components/{headers => }/components.def (100%) rename src/components/{headers => }/components.h (100%) rename src/components/{headers => }/door_component.h (100%) rename src/components/{headers => }/hitbox_component.h (100%) rename src/components/{headers => }/interact_component.h (100%) rename src/components/{headers => }/lever_component.h (100%) create mode 100644 src/components/lua_component.h rename src/components/{headers => }/physics_system.h (100%) rename src/components/{headers => }/player_system.h (100%) rename src/components/{headers => }/sprite_component.h (100%) rename src/components/{headers => }/transform_component.h (100%) diff --git a/.gitignore b/.gitignore index 005bc75..0c38e9d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ .vscode/ccls-cache +.cache +.config build diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 76cc0f3..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "SDL3_Core"] - path = SDL3_Core - url = https://gitea.skadubpc.net/ulysse/2D_Engine_SDL3_Core.git diff --git a/.vscode/settings.json b/.vscode/settings.json index c6b1ff1..3ab738a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,11 @@ { "nixEnvSelector.suggestion": false, "nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix", - "nixEnvSelector.useFlakes": false + "nixEnvSelector.useFlakes": false, + + "files.associations": { + "*.tsx": "xml", + "*.map": "json", + "configure": "shellscript" + } } \ No newline at end of file diff --git a/LICENSE b/LICENSE.txt similarity index 100% rename from LICENSE rename to LICENSE.txt diff --git a/Makefile b/Makefile index 0a5ede0..ea2d679 100644 --- a/Makefile +++ b/Makefile @@ -3,13 +3,9 @@ SHELL = /usr/bin/env bash # Build folder BUILD_DIR = build -# Source output target name +# Outputs target name and path SOURCE_OUTPUT = $(BUILD_DIR)/2D_Engine - -# Core output target name CORE_OUTPUT = $(BUILD_DIR)/libcore.a - -# Assets output ASSET_OUTPUT = $(BUILD_DIR)/game.data # Verbosity @@ -19,20 +15,20 @@ Q := endif # Colors -GREEN := \033[32m -YELLOW := \033[33m -RESET := \033[m +export GREEN := \033[32m +export YELLOW := \033[33m +export RESET := \033[m # Default targets -all: build_core build_src build_assets +all: $(SOURCE_OUTPUT) # Sub Makefiles SOURCE_DIR = src -CORE_DIR = SDL3_Core/src +CORE_DIR = core/src ASSETS_DIR = assets -include $(CORE_DIR)/Makefile include $(SOURCE_DIR)/Makefile +include $(CORE_DIR)/Makefile include $(ASSETS_DIR)/Makefile # Clean diff --git a/README.md b/README.md index f22b014..63b22f0 100644 --- a/README.md +++ b/README.md @@ -6,4 +6,4 @@ A multi-platform 2D_Engine made in C. ## Licences - This program is open-source : you can redistribute and/or modify it under the term of the **GNU GPLv3**. - Copyright (C) 2025 - 2026 Ulysse Cura. See [LICENSE](LICENSE) or [gnu.org/licenses/gpl-3.0.html](https://www.gnu.org/licenses/gpl-3.0.html). + Copyright (C) 2025 - 2026 Ulysse Cura. See [LICENSE](LICENSE.txt) or [gnu.org/licenses/gpl-3.0.html](https://www.gnu.org/licenses/gpl-3.0.html). diff --git a/SDL3_Core b/SDL3_Core deleted file mode 160000 index ae74832..0000000 --- a/SDL3_Core +++ /dev/null @@ -1 +0,0 @@ -Subproject commit ae74832227aaef43455e034bf3415991ec01205e diff --git a/assets/asset_builder/src/Makefile b/assets/asset_builder/src/Makefile index 7d71f70..ce36c4e 100644 --- a/assets/asset_builder/src/Makefile +++ b/assets/asset_builder/src/Makefile @@ -25,7 +25,7 @@ ASSET_BUILDER_CFLAGS = --std=c17 --pedantic -O1 -DDEBUG=1 -g $(shell pkg-config ASSET_BUILDER_LDFLAGS = -O1 $(shell pkg-config --libs libpng json-c) endif -ASSET_BUILDER_INCLUDE_DIRS = $(ASSET_BUILDER_DIR)/headers $(SOURCE_DIR)/components/headers +ASSET_BUILDER_INCLUDE_DIRS = $(SOURCE_DIR)/components $(ASSET_BUILDER_DIR) ASSET_BUILDER_INCLUDE_DIRS := $(addprefix -I, $(ASSET_BUILDER_INCLUDE_DIRS)) # Deduce objects diff --git a/assets/asset_builder/src/headers/errors.h b/assets/asset_builder/src/errors.h similarity index 100% rename from assets/asset_builder/src/headers/errors.h rename to assets/asset_builder/src/errors.h diff --git a/assets/asset_builder/src/headers/image.h b/assets/asset_builder/src/image.h similarity index 100% rename from assets/asset_builder/src/headers/image.h rename to assets/asset_builder/src/image.h diff --git a/assets/asset_builder/src/headers/map.h b/assets/asset_builder/src/map.h similarity index 100% rename from assets/asset_builder/src/headers/map.h rename to assets/asset_builder/src/map.h diff --git a/assets/asset_builder/src/headers/object.h b/assets/asset_builder/src/object.h similarity index 100% rename from assets/asset_builder/src/headers/object.h rename to assets/asset_builder/src/object.h diff --git a/assets/asset_builder/src/headers/utils.h b/assets/asset_builder/src/utils.h similarity index 100% rename from assets/asset_builder/src/headers/utils.h rename to assets/asset_builder/src/utils.h diff --git a/configure b/configure new file mode 100755 index 0000000..16cd580 --- /dev/null +++ b/configure @@ -0,0 +1,145 @@ +#!/usr/bin/env bash + +# +# Configuration script to build the 2D_Engine for different platforms. +# +# Creates makefile configuration to build for target host. +# + +# +# Project settings no matter current and target hosts +# + +#CACHE_DIR=".cache" +#LIB_DIR="lib" +#CONFIG_FILE=".config" + +#LUA_VERSION="5.5.1" +#LUA_CHECKSUM="1c4b4068d67061f2a2231ad2b5422e77acea1487ea9890f6320af614f4373dce" + +# +# Main +# + +### Setup dirs and logs +# +## Cache dir +#mkdir -p "${CACHE_DIR}" + +print_error() +{ + echo -e "\033[31merror\033[m: $1" + exit 0 +} + +## Parse args +TARGET_HOST="guess" + +for i in "$@"; do + case $i in + --target-host=*) + TARGET_HOST="${i#*=}" + shift # past argument=value + ;; + --clean) + CLEAN=1 + EXIT_AFTER_CLEAN=1 + shift # past argument=value + ;; + --reconfigure) + CLEAN=1 + shift # past argument=value + ;; + -h|--help) + echo "Usage : ./configure [OPTION]..." + echo "Add submodules depending on target host platform and" + echo "create makefile configuration to build for target host" + echo + echo -e "\033[1m --target-host=\033[mHOST" + echo -e "\tselect target host platform, default is \"guess\" and" + echo -e "\twill try to configure for your current OS" + echo -e "\033[1m --clean\033[m" + echo -e "\tclean build, config, cache, etc, and exit" + echo -e "\033[1m --reconfigure\033[m" + echo -e "\tcall clean, and configure" + echo -e "\033[1m -h, --help\033[m" + echo -e "\tshow help and exit" + exit 0 + ;; + -*) + print_error "Unknown option $i" + ;; + *) + ;; + esac +done + +## Clean +if [ -n "${CLEAN}" ]; then + make clean + rm -rf .config .cache lib + echo "Cleaned project." +fi + +if [ -n "${EXIT_AFTER_CLEAN}" ]; then + exit 0 +fi + +## Deduce current and target hosts +case "${OSTYPE}" in + linux*) + CURRENT_HOST="linux" + ;; +# msys*|cygwin*) +# CURRENT_HOST="windows" +# ;; +# darwin*) +# CURRENT_HOST="macos" +# ;; + *) + print_error "Current detected os is unsuppoted to build from: ${OSTYPE}\nUse --help for more informations." + ;; +esac + +echo "Detected current host: ${CURRENT_HOST}" + +if [ "${TARGET_HOST}" = "guess" ]; then + TARGET_HOST=${CURRENT_HOST} +fi + +case "${TARGET_HOST}" in + linux|fxcg50) + echo "Configuring for target: ${TARGET_HOST}" + ;; + *) + print_error "Unsupported target host: ${TARGET_HOST}" + ;; +esac + +echo + +# +### Download libs +#echo "===== downloading lua =====" +# +#LUA_TAR_GZ="${CACHE_DIR}/lua-${LUA_VERSION}.tar.gz" +#if [ ! -e "${LUA_TAR_GZ}" ]; then +# echo "Downloading lua source..." +# if ! curl --output "${LUA_TAR_GZ}" "https://www.lua.org/ftp/lua-${LUA_VERSION}.tar.gz"; then +# print_error "Failed to download lua source." +# fi +#fi +# +#echo "Checking lua source sum..." +#if ! echo "${LUA_CHECKSUM} ${LUA_TAR_GZ}" | sha256sum -c; then +# CHECKSUM="$(sha256sum "${LUA_TAR_GZ}" | cut -d " " -f 1)" +# rm "${LUA_TAR_GZ}" +# print_error "Lua zip checksum not valid.\nExpected: \"${LUA_CHECKSUM}\"\nGot: \"${CHECKSUM}\"\nPlease rerun command to retry downloading." +#fi +# +#echo "Extracting lua source" +#if ! tar -xzf "${LUA_TAR_GZ}" --directory "${LIB_DIR}"; then +# print_error "Failed to extract lua source." +#fi +# + diff --git a/core/README.md b/core/README.md new file mode 100644 index 0000000..db5b5ed --- /dev/null +++ b/core/README.md @@ -0,0 +1,9 @@ +[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0) +# 2D_Engine_C core + +## Description +The core for the multi-platform 2D_Engine_C. + +## Licences +- This program is open-source : you can redistribute and/or modify it under the term of the **GNU GPLv3**. + Copyright (C) 2025 - 2026 Ulysse Cura. See [LICENSE](../LICENSE.txt) or [gnu.org/licenses/gpl-3.0.html](https://www.gnu.org/licenses/gpl-3.0.html). diff --git a/src/components/headers/lua_component.h b/core/host/generic/display.c similarity index 100% rename from src/components/headers/lua_component.h rename to core/host/generic/display.c diff --git a/core/host/generic/display.h b/core/host/generic/display.h new file mode 100644 index 0000000..e69de29 diff --git a/core/host/linux/Makefile b/core/host/linux/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/core/src/.ccls b/core/src/.ccls new file mode 100644 index 0000000..478d903 --- /dev/null +++ b/core/src/.ccls @@ -0,0 +1,8 @@ +gcc +# Headers +-Icore/src +-Isrc/components + +# Macros +-DDEBUG=2 +-DASSET_FILE_NAME="$(make print-ASSET_OUTPUT)" diff --git a/core/src/Makefile b/core/src/Makefile new file mode 100644 index 0000000..58849c0 --- /dev/null +++ b/core/src/Makefile @@ -0,0 +1,74 @@ +# Source files +CORE_SOURCES := \ + linked_list.c \ + vector2d.c \ + inputs.c \ + asset_manager.c \ + texture.c \ + map.c \ + camera.c \ + event_bus.c \ + ecs.c \ + display.c \ + main.c + +# Compiler and flags +CORE_CC = gcc +ifeq ($(RELEASE), 1) +CORE_CFLAGS = --std=c17 --pedantic -O3 -DASSET_FILE_NAME=\"$(notdir $(ASSET_OUTPUT))\" -D_GNU_SOURCE=1 $(shell pkg-config --cflags sdl3) # RELEASE +else +CORE_CFLAGS = --std=c17 --pedantic -O1 -g -DDEBUG=2 -DASSET_FILE_NAME=\"$(notdir $(ASSET_OUTPUT))\" -D_GNU_SOURCE=1 $(shell pkg-config --cflags sdl3) \ + -Wall -Wno-missing-braces -Wextra -Wno-missing-field-initializers \ + -Wformat=2 -Wswitch-default -Wswitch -Wcast-align \ + -Wpointer-arith -Wbad-function-cast -Wstrict-overflow=5 \ + -Wstrict-prototypes -Winline -Wundef -Wnested-externs \ + -Wcast-qual -Wshadow -Wunreachable-code -Wlogical-op \ + -Wfloat-equal -Wstrict-aliasing=2 -Wredundant-decls \ + -Wold-style-definition # DEVELOPEMENT +endif + +CORE_INCLUDE_DIRS = $(SOURCE_DIR)/components $(CORE_DIR) +CORE_INCLUDE_DIRS := $(addprefix -I, $(CORE_INCLUDE_DIRS)) + +CORE_AR = ar +CORE_ARFLAGS = + +# Used in final linking. +CORE_DEPS_FLAGS = $(shell pkg-config --libs sdl3) -lm + +# Deduce objects +CORE_OBJECTS = $(CORE_SOURCES:%.c=$(BUILD_DIR)/$(CORE_DIR)/%.o) + +# Current file nb to process +CURRENT_CORE_FILE := 0 + +# Build core target +build_core: core_setup count_core_build core_end + +# Core build directories +core_setup: + @echo "Building $(notdir $(CORE_OUTPUT))" + $(Q)mkdir -p $(dir $(CORE_OBJECTS)) + +# Count nb of files to build +count_core_build: + $(eval export TOTAL_CORE_FILES := $(shell echo $$(($$(make -n $(CORE_OBJECTS) 2>/dev/null | grep -c "Building") + 1)))) + +# Link core target +$(CORE_OUTPUT): $(CORE_OBJECTS) + @echo -e "[100%] $(YELLOW)Linking $(notdir $(CORE_OUTPUT))$(RESET)" + $(Q)$(CORE_AR) rcs $(CORE_ARFLAGS) $@ $^ + +# Build .o files +$(BUILD_DIR)/$(CORE_DIR)/%.o: $(CORE_DIR)/%.c + $(eval CURRENT_CORE_FILE := $(shell echo $$(($(CURRENT_CORE_FILE)+1)))) + $(eval PERCENTAGE := $(shell echo $$(($(CURRENT_CORE_FILE)*100/$(TOTAL_CORE_FILES))))) + @echo -e "[$(PERCENTAGE)%] $(GREEN)Building C object $@$(RESET)" + $(Q)$(CORE_CC) $(CORE_CFLAGS) $(CORE_INCLUDE_DIRS) -MMD -MP -c $< -o $@ + +# Print ending message +core_end: $(CORE_OUTPUT) + @echo "Built target $(notdir $(CORE_OUTPUT))" + +# Source files dependencies +-include $(CORE_OBJECTS:.o=.d) diff --git a/core/src/asset_manager.c b/core/src/asset_manager.c new file mode 100644 index 0000000..b6e0083 --- /dev/null +++ b/core/src/asset_manager.c @@ -0,0 +1,234 @@ +#include "asset_manager.h" + +#include +#include +#include "game.h" +#include "linked_list.h" +#include "texture.h" +#include "map.h" +#include "memory_alloc.h" +#include "errors.h" + +// Args : asset_type_t asset_type, const char *asset_name +int create_asset(asset_t *asset, va_list args) +{ + asset->name = va_arg(args, const char *); + asset->type = ASSET_NULL; + asset->nb_refs = 0; + + return EXIT_SUCCESS; +} + +int destroy_asset(asset_t *asset) +{ + switch(asset->type) + { + case ASSET_TEXTURE: + destroy_texture(asset->data); + break; + + case ASSET_MAP: + if(destroy_map(asset->data)) return_failure_int; + break; + + case ASSET_NULL: + break; + + default: + error_printf("Asset type not valid : %d", asset->type); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int destroy_asset_header_def(asset_header_def_t *asset_header_def) +{ + free(asset_header_def->name); + + return EXIT_SUCCESS; +} + +int asset_manager_init(void) +{ + linked_list_init(&game.asset_manager.assets, sizeof(asset_t), (allocator_t)create_asset, (deleter_t)destroy_asset); + linked_list_init(&game.asset_manager.assets_header_defs, sizeof(asset_header_def_t), NULL, (deleter_t)destroy_asset_header_def); + + game.asset_manager.asset_file = fopen(ASSET_FILE_NAME, "rb"); + if(!game.asset_manager.asset_file) + { + error_printf("Failed to open asset file : %d", errno); + return EXIT_FAILURE; + } + + uint32_t nb_assets; + if(fread(&nb_assets, sizeof(nb_assets), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read asset file."); + return EXIT_FAILURE; + } + + if(linked_list_reserve(&game.asset_manager.assets_header_defs, nb_assets)) return_failure_int; + + for(size_t i = 0; i < nb_assets; i++) + { + elem_t *asset_header_def_elem = create_elem(&game.asset_manager.assets_header_defs); + if(!asset_header_def_elem) return_failure_int; + asset_header_def_t *asset_header_def = asset_header_def_elem->data; + + size_t cap = 0; + + if(getdelim(&asset_header_def->name, &cap, '\0', game.asset_manager.asset_file) == -1) + { + error_printf("Failed to read asset file."); + return EXIT_FAILURE; + } + + if(fread(&asset_header_def->start, sizeof(asset_header_def->start), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read asset file."); + return EXIT_FAILURE; + } + + linked_list_push_back(&game.asset_manager.assets_header_defs, asset_header_def_elem); + } + + debug_printf("Initialized asset manager."); + return EXIT_SUCCESS; +} + +int asset_manager_exit(void) +{ + if(linked_list_exit(&game.asset_manager.assets_header_defs)) return_failure_int; + if(linked_list_exit(&game.asset_manager.assets)) return_failure_int; + + if(fclose(game.asset_manager.asset_file)) + { + error_printf("Failed to close asset file : %d", errno); + return EXIT_FAILURE; + } + + debug_printf("Exited asset manager."); + return EXIT_SUCCESS; +} + +// Only for this file +// No args +static inline bool condition_is_asset_unused(elem_t *elem, void *arg __attribute__((unused))) +{ + return !((asset_t *)elem->data)->nb_refs; +} + +inline int asset_manager_collect_garbage(void) +{ + if(linked_list_remove_if(&game.asset_manager.assets, condition_is_asset_unused, NULL)) return_failure_int; + + return EXIT_SUCCESS; +} + +// Only for this file +// Arg : const char *asset_name +static inline bool condition_is_asset_name(elem_t *elem, void *arg) +{ + return !strcmp(((asset_t *)elem->data)->name, (const char *)arg); +} + +//Only for this file +// Arg : const char *asset_name +static inline bool condition_is_asset_header_def_name(elem_t *elem, void *arg) +{ + return !strcmp(((asset_header_def_t *)elem->data)->name, (const char *)arg); +} + +asset_t *asset_manager_load_asset(char *asset_name, asset_type_t asset_type) +{ + // Check if asset has alread been loaded. + elem_t *asset_elem = linked_list_get_if(&game.asset_manager.assets, condition_is_asset_name, (void *)asset_name); + if(asset_elem) + { + asset_t *asset = asset_elem->data; + asset->nb_refs++; + + debug_printf("Asset \"%s\" has already been loaded, nb refs : %d", asset->name, asset->nb_refs); + } + else + { + // If it didn't, load it + elem_t *asset_header_def_elem = linked_list_get_if(&game.asset_manager.assets_header_defs, condition_is_asset_header_def_name, (void *)asset_name); + if(!asset_header_def_elem) + { + error_printf("Asset doesn't exist in asset file : %s", asset_name); + return NULL; + } + asset_header_def_t *asset_header_def = asset_header_def_elem->data; + + asset_elem = create_elem(&game.asset_manager.assets, asset_name); + if(!asset_elem) return_failure_ptr; + asset_t *asset = asset_elem->data; + + if(fseek(game.asset_manager.asset_file, asset_header_def->start, SEEK_SET)) + { + error_printf("Failed to seek in asset file : %d", errno); + return NULL; + } + + switch(asset_type) + { + case ASSET_TEXTURE: + asset->data = load_texture(); + break; + + case ASSET_MAP: + asset->data = load_map(); + break; + + default: + error_printf("Asset type doesn't exists : %d", asset_type); + break; + } + + if(!asset->data) + { + destroy_elem(&game.asset_manager.assets, asset_elem); // returns failure anyway + return_failure_ptr; + } + + asset->type = asset_type; + asset->nb_refs++; + + linked_list_push_back(&game.asset_manager.assets, asset_elem); + + debug_printf("Asset \"%s\" has been loaded.", asset->name); + } + + return asset_elem->data; +} + +int asset_manager_let_go_asset(char *asset_name) +{ + elem_t *asset_elem = linked_list_get_if(&game.asset_manager.assets, condition_is_asset_name, (void *)asset_name); + if(!asset_elem) + { + error_printf("Asset doesn't exists : %s", asset_name); + return EXIT_FAILURE; + } + + asset_t *asset = asset_elem->data; + asset->nb_refs--; + + debug_printf("Asset \"%s\" has been let go, nb refs : %d", asset->name, asset->nb_refs); + + return EXIT_SUCCESS; +} + +asset_t *asset_manager_get_asset(char *asset_name) +{ + elem_t *asset_elem = linked_list_get_if(&game.asset_manager.assets, condition_is_asset_name, (void *)asset_name); + if(!asset_elem) + { + error_printf("Asset \"%s\" hasn't been loaded yet.", asset_name); + return NULL; + } + + return asset_elem->data; +} diff --git a/core/src/asset_manager.h b/core/src/asset_manager.h new file mode 100644 index 0000000..385900a --- /dev/null +++ b/core/src/asset_manager.h @@ -0,0 +1,48 @@ +#ifndef ASSET_MANAGER_H +#define ASSET_MANAGER_H + +#include +#include +#include "linked_list.h" + +typedef enum asset_type_t { + ASSET_NULL, + ASSET_TEXTURE, + ASSET_MAP +} asset_type_t; + +typedef struct asset_t { + const char *name; + + void *data; + + uint32_t nb_refs; + + asset_type_t type; +} asset_t; + +int create_asset(asset_t *asset, va_list args); +int destroy_asset(asset_t *asset); + +typedef struct asset_header_def_t { + char *name; + uint32_t start; +} asset_header_def_t; + +int destroy_asset_header_def(asset_header_def_t *asset_header_def); + +typedef struct asset_manager_t { + linked_list_t assets_header_defs; + linked_list_t assets; + FILE *asset_file; +} asset_manager_t; + +int asset_manager_init(void); +int asset_manager_exit(void); +int asset_manager_collect_garbage(void); + +asset_t *asset_manager_load_asset(char *asset_name, asset_type_t asset_type); +int asset_manager_let_go_asset(char *asset_name); +asset_t *asset_manager_get_asset(char *asset_name); + +#endif // ASSET_MANAGER_H \ No newline at end of file diff --git a/core/src/camera.c b/core/src/camera.c new file mode 100644 index 0000000..723272a --- /dev/null +++ b/core/src/camera.c @@ -0,0 +1,64 @@ +#include "camera.h" + +#include "game.h" +#include "display.h" + +void camera_init(void) +{ + game.camera.view_rect = (rect_t) { + .x = 0, + .y = 0, + .w = DISPLAY_WIDTH / 2, + .h = DISPLAY_HEIGHT / 2 + }; + + game.camera.tracking_pos = NULL; + game.camera.tracking_center_offset = (vector2d_t) { + .x = 0, + .y = 0 + }; +} + +void camera_update(void) +{ + if(game.camera.tracking_pos) + { + game.camera.view_rect.x = game.camera.tracking_pos->x + game.camera.tracking_center_offset.x - game.camera.view_rect.w / 2; + game.camera.view_rect.y = game.camera.tracking_pos->y + game.camera.tracking_center_offset.y - game.camera.view_rect.h / 2; + } + + if(game.map) + { + if(game.camera.view_rect.w > game.map->width * TILE_SIZE) + { + game.camera.view_rect.x = game.map->width * TILE_SIZE / 2 - game.camera.view_rect.w / 2; + } + else + { + if(game.camera.view_rect.x < 0) + { + game.camera.view_rect.x = 0; + } + else if(game.camera.view_rect.x + game.camera.view_rect.w > game.map->width * TILE_SIZE) + { + game.camera.view_rect.x = game.map->width * TILE_SIZE - game.camera.view_rect.w; + } + } + + if(game.camera.view_rect.h > game.map->height * TILE_SIZE) + { + game.camera.view_rect.y = game.map->height * TILE_SIZE / 2 - game.camera.view_rect.h / 2; + } + else + { + if(game.camera.view_rect.y < 0) + { + game.camera.view_rect.y = 0; + } + else if(game.camera.view_rect.y + game.camera.view_rect.h > game.map->height * TILE_SIZE) + { + game.camera.view_rect.y = game.map->height * TILE_SIZE - game.camera.view_rect.h; + } + } + } +} diff --git a/core/src/camera.h b/core/src/camera.h new file mode 100644 index 0000000..b401c08 --- /dev/null +++ b/core/src/camera.h @@ -0,0 +1,16 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include "vector2d.h" + +typedef struct camera_t { + rect_t view_rect; + fvector2d_t *tracking_pos; + vector2d_t tracking_center_offset; +} camera_t; + +void camera_init(void); + +void camera_update(void); + +#endif // CAMERA_H \ No newline at end of file diff --git a/core/src/display.c b/core/src/display.c new file mode 100644 index 0000000..433de1c --- /dev/null +++ b/core/src/display.c @@ -0,0 +1,188 @@ +#include "display.h" + +#include +#include +#include "asset_manager.h" +#include "game.h" +#include "texture.h" +#include "errors.h" + +inline int display_init(void) +{ + if(!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) + { + error_printf("Failed to initialise SDL3 : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + if(!SDL_SetAppMetadata("2D_Engine_SDL3_Core", "1.0", "2D_Engine")) + { + error_printf("Failed to set app metadata : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + game.display.window = SDL_CreateWindow("2D_Engine", DISPLAY_WIDTH, DISPLAY_HEIGHT, 0); + if(!game.display.window) + { + error_printf("Failed to create window : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + debug_printf("Listing available render drivers."); + const int NB_DRIVERS = SDL_GetNumRenderDrivers(); + for(int i = 0; i < NB_DRIVERS; i++) + debug_printf("%d : %s", i, SDL_GetRenderDriver(i)); + + if(DRIVERS) warning_printf("This build of 2D_Engine_C only support the following drivers : %s", DRIVERS); + + game.display.renderer = SDL_CreateRenderer(game.display.window, DRIVERS); + if(!game.display.renderer) + { + error_printf("Failed to create renderer : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + if(!SDL_SetRenderVSync(game.display.renderer, SDL_RENDERER_VSYNC_ADAPTIVE)) + { + error_printf("Failed to activate adaptative vsync : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + if(!SDL_SetRenderDrawBlendMode(game.display.renderer, SDL_BLENDMODE_BLEND)) + { + error_printf("Failed to set renderer draw blend mode : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + if(!SDL_SetDefaultTextureScaleMode(game.display.renderer, SDL_SCALEMODE_NEAREST)) + { + error_printf("Failed to set default texture scale mode : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + debug_printf("Initialized display."); + + return EXIT_SUCCESS; +} + +inline void display_exit(void) +{ + if(game.display.renderer) SDL_DestroyRenderer(game.display.renderer); + if(game.display.window) SDL_DestroyWindow(game.display.window); + SDL_Quit(); + + debug_printf("Exited display."); +} + +inline int display_clear(void) +{ + if(!SDL_SetRenderDrawColor(game.display.renderer, C_WHITE, 255)) + { + error_printf("Failed to change renderer draw color : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + if(!SDL_RenderClear(game.display.renderer)) + { + error_printf("Failed to clear renderer : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +inline int display_update(void) +{ + if(!SDL_RenderPresent(game.display.renderer)) + { + error_printf("Failed to present renderer : %s", SDL_GetError()); + return EXIT_FAILURE; + } + +#if DEBUG >= 1 + float fps = 1000.0f / game.delta_time_ms; + static float max_fps_10s = 0.0f; + static float low_fps_10s = 10000000.0f; + + if(fps > max_fps_10s) max_fps_10s = fps; + if(fps < low_fps_10s) low_fps_10s = fps; + + static float fps_update_delta_time = 0.0f; + fps_update_delta_time += game.delta_time_ms; + + if(fps_update_delta_time >= 100.0f) + { + fps_update_delta_time = 0.0f; + char title[100]; + if(sprintf(title, "2D_Engine | cur: %.2ffps | max: %.2ffps | low: %.2ffps", fps, max_fps_10s, low_fps_10s) == -1) + { + error_printf("Sprintf failed : %d", errno); + return EXIT_FAILURE; + } + if(!SDL_SetWindowTitle(game.display.window, title)) + { + error_printf("Failed to set window title : %s", SDL_GetError()); + return EXIT_FAILURE; + } + } + + static float fps_max_low_update_delta_time = 0.0f; + fps_max_low_update_delta_time += game.delta_time_ms; + + if(fps_max_low_update_delta_time > 10000.0f) + { + fps_max_low_update_delta_time = 0.0f; + max_fps_10s = 0.0f; + low_fps_10s = 10000000.0f; + } +#endif // DEBUG >= 1 + + return EXIT_SUCCESS; +} + +int display_draw_texture(texture_t *texture, const rect_t *src_rect, const rect_t *dst_rect, bool flip) +{ + frect_t src_frect; + if(src_rect) rect_to_frect(src_rect, &src_frect); + + frect_t dst_frect; + if(dst_rect) + dst_frect = (frect_t) { + .x = (dst_rect->x - game.camera.view_rect.x) * (DISPLAY_WIDTH / game.camera.view_rect.w), + .y = (dst_rect->y - game.camera.view_rect.y) * (DISPLAY_HEIGHT / game.camera.view_rect.h), + .w = dst_rect->w * (DISPLAY_WIDTH / game.camera.view_rect.w), + .h = dst_rect->h * (DISPLAY_HEIGHT / game.camera.view_rect.h) + }; + + if(!SDL_RenderTextureRotated(game.display.renderer, texture, src_rect ? &src_frect : NULL, dst_rect ? &dst_frect : NULL, 0, NULL, flip)) + { + error_printf("Failed to copy texture to renderer : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +int display_draw_frect(const frect_t *frect, unsigned int r, unsigned int g, unsigned int b, unsigned int a) +{ + if(!SDL_SetRenderDrawColor(game.display.renderer, r, g, b, a)) + { + error_printf("Failed to change renderer draw color : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + frect_t display_frect = { + .x = (frect->x - game.camera.view_rect.x) * (DISPLAY_WIDTH / game.camera.view_rect.w), + .y = (frect->y - game.camera.view_rect.y) * (DISPLAY_HEIGHT / game.camera.view_rect.h), + .w = frect->w * (DISPLAY_WIDTH / game.camera.view_rect.w), + .h = frect->h * (DISPLAY_HEIGHT / game.camera.view_rect.h) + }; + + if(!SDL_RenderRect(game.display.renderer, &display_frect)) + { + error_printf("Failed to draw rectangle to renderer : %s", SDL_GetError()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/display.h b/core/src/display.h new file mode 100644 index 0000000..f1ed137 --- /dev/null +++ b/core/src/display.h @@ -0,0 +1,35 @@ +#ifndef DISPLAY_H +#define DISPLAY_H + +#include +#include "asset_manager.h" +#include "texture.h" +#include "vector2d.h" + +#define C_BLACK 0, 0, 0 +#define C_RED 255, 0, 0 +#define C_GREEN 0, 255, 0 +#define C_BLUE 0, 0, 255 +#define C_WHITE 255, 255, 255 + +#define DISPLAY_WIDTH 720 +#define DISPLAY_HEIGHT 480 + +//#define DRIVERS NULL +#define DRIVERS "vulkan,gpu,software" + +typedef struct display_t { + SDL_Window *window; + SDL_Renderer *renderer; +} display_t; + +int display_init(void); +void display_exit(void); + +int display_clear(void); +int display_update(void); + +int display_draw_texture(texture_t *texture, const rect_t *src_rect, const rect_t *dst_rect, bool flip); +int display_draw_frect(const frect_t *frect, unsigned int r, unsigned int g, unsigned int b, unsigned int a); + +#endif // DISPLAY_H \ No newline at end of file diff --git a/core/src/ecs.c b/core/src/ecs.c new file mode 100644 index 0000000..7bf87f4 --- /dev/null +++ b/core/src/ecs.c @@ -0,0 +1,222 @@ +#include "ecs.h" + +#include +#include "game.h" +#include "components.h" +#include "memory_alloc.h" +#include "errors.h" + +const char *component_type_to_name(component_type_t component_type) +{ + switch(component_type) + { +#define COMPONENT(NAME, ...) \ + case NAME: \ + return #NAME; +#include "components.def" + + default: + return "INVALID"; + } +} + +// Arg : component_type_t component_type +int create_component(component_t *component, va_list args) +{ + component->type = va_arg(args, component_type_t); + + switch(component->type) + { +#define COMPONENT(NAME, PREFIX, DRAW) \ + case NAME: \ + component->init = PREFIX##_init; \ + component->update = PREFIX##_update; \ + component->draw = DRAW(PREFIX); \ + component->data = malloc(sizeof(PREFIX##_data_t)); \ + if(!component->data) \ + { \ + error_printf("Failed to allocate memory : %d", errno); \ + return EXIT_FAILURE; \ + } \ + component->deleter = PREFIX##_destroy; \ + break; +#include "components.def" + + default: + error_printf("Component type doesn't exists : %d", component->type); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +inline int destroy_component(component_t *component) +{ + if(component->deleter(component)) return_failure_int; + + return EXIT_SUCCESS; +} + +int create_entity(entity_t *entity, va_list args) +{ + entity->id = va_arg(args, size_t); + entity->draw_priority = 0; + + linked_list_init(&entity->components, sizeof(component_t), (allocator_t)create_component, (deleter_t)destroy_component); + + return EXIT_SUCCESS; +} + +inline int destroy_entity(entity_t *entity) +{ + if(linked_list_exit(&entity->components)) return_failure_int; + + return EXIT_SUCCESS; +} + +component_t *entity_new_component(entity_t *entity, component_type_t component_type) +{ + elem_t *component_elem = create_elem(&entity->components, component_type); + if(!component_elem) return_failure_ptr; + + component_t *component = component_elem->data; + + component->entity = entity; + + if(component->init(component)) return_failure_ptr; + + linked_list_push_front(&entity->components, component_elem); + + return component; +} + +// Only for this file +// Arg : component_type_t component_type +static inline bool condition_is_component_type(elem_t *elem, void *arg) +{ + return ((component_t *)elem->data)->type == *(component_type_t *)arg; +} + +inline component_t *entity_get_component(const entity_t *entity, component_type_t component_type) +{ + elem_t *component_elem = linked_list_get_if(&entity->components, condition_is_component_type, &component_type); + if(!component_elem) return NULL; + + component_t *component = component_elem->data; + + return component; +} + +// Only for this file +// No args +static inline int action_update_component(elem_t *elem, void *arg __attribute__((unused))) +{ + component_t *component = elem->data; + + if(component->update(component)) return_failure_int; + + return EXIT_SUCCESS; +} + +inline int update_entity(entity_t *entity) +{ + if(linked_list_for_each(&entity->components, action_update_component, NULL)) return_failure_int; + + return EXIT_SUCCESS; +} + +// No args +static inline int action_draw_component(elem_t *elem, void *arg __attribute__((unused))) +{ + component_t *component = elem->data; + + if(component->draw) + if(component->draw(component)) return_failure_int; + + return EXIT_SUCCESS; +} + +inline int draw_entity(entity_t *entity) +{ + if(linked_list_for_each(&entity->components, action_draw_component, NULL)) return_failure_int; + + return EXIT_SUCCESS; +} + +inline void entity_manager_init(void) +{ + linked_list_init(&game.entity_manager.entities, sizeof(entity_t), (allocator_t)create_entity, (deleter_t)destroy_entity); + + debug_printf("Initialized entity manager."); +} + +inline entity_t *entity_manager_new_entity(size_t id) +{ + elem_t *entity_elem = create_elem(&game.entity_manager.entities, id); + if(!entity_elem) return_failure_ptr; + + linked_list_push_back(&game.entity_manager.entities, entity_elem); + + debug_printf("Added entity %lu to entity manager.", id); + + return entity_elem->data; +} + +// No args +static inline int action_update_entity(elem_t *elem, void *arg __attribute__((unused))) +{ + return update_entity((entity_t *)elem->data); +} + +inline int entity_manager_update(void) +{ + if(linked_list_for_each(&game.entity_manager.entities, action_update_entity, NULL)) return_failure_int; + + return EXIT_SUCCESS; +} + +// No args +static inline bool condition_is_draw_priority_higher(elem_t *elem, void *arg __attribute__((unused))) +{ + return ((entity_t *)elem->data)->draw_priority > ((entity_t *)elem->next->data)->draw_priority; +} + +// No args +static inline int action_draw_entity(elem_t *elem, void *arg __attribute__((unused))) +{ + return draw_entity((entity_t *)elem->data); +} + +inline int entity_manager_draw(void) +{ + linked_list_insertion_sort(&game.entity_manager.entities, condition_is_draw_priority_higher, NULL); + + if(linked_list_for_each(&game.entity_manager.entities, action_draw_entity, NULL)) return_failure_int; + + return EXIT_SUCCESS; +} + +// Only for this file +// Arg : size_t id +static inline bool condition_is_entity_name(elem_t *elem, void *arg) +{ + return ((entity_t *)elem->data)->id == *(size_t *)arg; +} + +inline int entity_manager_remove_entity(size_t id) +{ + if(linked_list_remove_if(&game.entity_manager.entities, condition_is_entity_name, &id)) return_failure_int; + + debug_printf("Removed entity %lu from entity manager.", id); + + return EXIT_SUCCESS; +} + +inline int entity_manager_exit(void) +{ + if(linked_list_exit(&game.entity_manager.entities)) return_failure_int; + + debug_printf("Exited entity manager."); + + return EXIT_SUCCESS; +} diff --git a/core/src/ecs.h b/core/src/ecs.h new file mode 100644 index 0000000..fdb3031 --- /dev/null +++ b/core/src/ecs.h @@ -0,0 +1,71 @@ +#ifndef ECS_H +#define ECS_H + +#include +#include +#include "linked_list.h" + +typedef enum component_type_t { +#define COMPONENT(NAME, ...) NAME, +#include "components.def" +} component_type_t; + +const char *component_type_to_name(component_type_t component_type); + +// Component forwarding +typedef struct component_t component_t; + +// Component init function. It is called when component added to entity. This function is necessary. +typedef int (*component_init_t)(component_t *component); +// Component update function. It is called in the main loop to update the component. This function is necessary. +typedef int (*component_update_t)(component_t *component); +// Component draw function. It is called in the main loop to draw the component on screen. This function is not necessary. +typedef int (*component_draw_t)(const component_t *component); +// Component deleter function. It is called when the component is removed. It should free the data in the component data but not the component itself. +typedef int (*component_deleter_t)(component_t *component); + +typedef struct component_t { + component_init_t init; + component_update_t update; + component_draw_t draw; + + void *data; + + component_deleter_t deleter; + + struct entity_t *entity; + + component_type_t type; + +} component_t; + +int create_component(component_t *component, va_list args); +int destroy_component(component_t *component); + +typedef struct entity_t { + size_t id; + size_t draw_priority; + linked_list_t components; +} entity_t; + +int create_entity(entity_t *entity, va_list args); +int destroy_entity(entity_t *entity); + +component_t *entity_new_component(entity_t *entity, component_type_t component_type); +int update_entity(entity_t *entity); +int draw_entity(entity_t *entity); +component_t *entity_get_component(const entity_t *entity, component_type_t component_type); + +typedef struct entity_manager_t { + linked_list_t entities; +} entity_manager_t; + +void entity_manager_init(void); +int entity_manager_exit(void); + +entity_t *entity_manager_new_entity(size_t id); +int entity_manager_update(void); +int entity_manager_draw(void); +int entity_manager_remove_entity(size_t id); + +#endif // ECS_H \ No newline at end of file diff --git a/core/src/errors.h b/core/src/errors.h new file mode 100644 index 0000000..9b5805b --- /dev/null +++ b/core/src/errors.h @@ -0,0 +1,57 @@ +#ifndef ERRORS_H +#define ERRORS_H + +#include +#include +#include + +#ifndef DEBUG +#define DEBUG 0 +#endif + +#if DEBUG > 0 +#define debug_printf(...) \ + do { \ + fprintf(stderr, "\033[32mINFO\033[m: " __VA_ARGS__); \ + fputc('\n', stderr); \ + } while (0) + +#define return_failure_int \ + do { \ + fprintf(stderr, "\tin %s:%d:%s()\n", __FILE__, __LINE__, __func__); \ + return EXIT_FAILURE; \ + } while (0); + +#define return_failure_ptr \ + do { \ + fprintf(stderr, "\tin %s:%d:%s()\n", __FILE__, __LINE__, __func__); \ + return NULL; \ + } while (0); +#define goto_failure \ + do { \ + fprintf(stderr, "\tin %s:%d:%s()\n", __FILE__, __LINE__, __func__); \ + goto failure; \ + } while (0); + +#else +#define debug_printf(...) + +#define return_failure_int return EXIT_FAILURE; +#define return_failure_ptr return NULL; +#define goto_failure goto failure; +#endif + +#define warning_printf(...) \ + do { \ + fprintf(stderr, "\033[35mWARNING\033[m: " __VA_ARGS__); \ + fputc('\n', stderr); \ + } while (0) + +#define error_printf(...) \ + do { \ + fprintf(stderr, "\033[31mERROR\033[m: %s:%d:%s(): ", __FILE__, __LINE__, __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fputc('\n', stderr); \ + } while (0) + +#endif // ERRORS_H \ No newline at end of file diff --git a/core/src/event_bus.c b/core/src/event_bus.c new file mode 100644 index 0000000..72a133f --- /dev/null +++ b/core/src/event_bus.c @@ -0,0 +1,140 @@ +#include "event_bus.h" + +#include +#include "game.h" +#include "linked_list.h" +#include "memory_alloc.h" +#include "errors.h" + +// Arg : callback_t callback +inline int create_subscription(subscription_t *subscription, va_list args) +{ + subscription->callback = va_arg(args, callback_t); + subscription->data = va_arg(args, void *); + + return EXIT_SUCCESS; +} + +// Arg : size_t id +inline int create_topic(topic_t *topic, va_list args) +{ + topic->id = va_arg(args, size_t); + + linked_list_init(&topic->subscriptions, sizeof(subscription_t), (allocator_t)create_subscription, NULL); + + return EXIT_SUCCESS; +} + +inline int destroy_topic(topic_t *topic) +{ + if(linked_list_exit(&topic->subscriptions)) return_failure_int; + + return EXIT_SUCCESS; +} + +inline void event_bus_init(void) +{ + linked_list_init(&game.event_bus.topics, sizeof(topic_t), (allocator_t)create_topic, (deleter_t)destroy_topic); + + debug_printf("Initialized event bus."); +} + +inline int event_bus_exit(void) +{ + if(linked_list_exit(&game.event_bus.topics)) return_failure_int; + + debug_printf("Exited event bus."); + return EXIT_SUCCESS; +} + +// Arg : size_t id +static inline bool condition_is_topic_id(elem_t *elem, void *arg) +{ + return ((topic_t *)elem->data)->id == *(size_t *)arg; +} + +int event_bus_new_topic(size_t id) +{ + if(linked_list_get_if(&game.event_bus.topics, condition_is_topic_id, &id)) return EXIT_SUCCESS; + + elem_t *topic_elem = create_elem(&game.event_bus.topics, id); + if(!topic_elem) return_failure_int; + + linked_list_push_back(&game.event_bus.topics, topic_elem); + + debug_printf("Created new topic with id : %lu", id); + + return EXIT_SUCCESS; +} + +inline int event_bus_remove_topic(size_t id) +{ + if(linked_list_remove_if(&game.event_bus.topics, condition_is_topic_id, &id)) return_failure_int; + + debug_printf("Removed topic with id : %lu", id); + + return EXIT_SUCCESS; +} + +// Args : va_list args +static int action_execute_callback(elem_t *elem, void *arg) +{ + subscription_t *subscription = elem->data; + + if(subscription->callback(arg, subscription->data)) return_failure_int; + + return EXIT_SUCCESS; +} + +int event_bus_publish(size_t id, void *arg) +{ + elem_t *topic_elem = linked_list_get_if(&game.event_bus.topics, condition_is_topic_id, &id); + if(!topic_elem) return_failure_int; + + topic_t *topic = topic_elem->data; + + if(linked_list_for_each(&topic->subscriptions, action_execute_callback, arg)) return_failure_int; + + debug_printf("Published event on topic with id : %lu", id); + + return EXIT_SUCCESS; +} + +int event_bus_subscribe(size_t id, callback_t callback, void *data) +{ + elem_t *topic_elem = linked_list_get_if(&game.event_bus.topics, condition_is_topic_id, &id); + if(!topic_elem) + { + error_printf("Topic with id : %lu doesn't exists.", id); + return EXIT_FAILURE; + } + + topic_t *topic = topic_elem->data; + + elem_t *subscription_elem = create_elem(&topic->subscriptions, callback, data); + if(!subscription_elem) return_failure_int; + + linked_list_push_back(&topic->subscriptions, subscription_elem); + + debug_printf("Subscribed to topic with id : %lu", id); + + return EXIT_SUCCESS; +} + +// Arg : callback_t callback +static inline bool condition_is_callback(elem_t *elem, void *arg) +{ + return ((subscription_t *)elem->data)->callback == *(callback_t *)arg; +} + +int event_bus_unsubscribe(size_t id, callback_t callback) +{ + elem_t *topic_elem = linked_list_get_if(&game.event_bus.topics, condition_is_topic_id, &id); + if(!topic_elem) return_failure_int; + + topic_t *topic = topic_elem->data; + + if(linked_list_remove_if(&topic->subscriptions, condition_is_callback, &callback)) return_failure_int; + + return EXIT_SUCCESS; +} diff --git a/core/src/event_bus.h b/core/src/event_bus.h new file mode 100644 index 0000000..5a15a69 --- /dev/null +++ b/core/src/event_bus.h @@ -0,0 +1,38 @@ +#ifndef EVENT_BUS_H +#define EVENT_BUS_H + +#include +#include "linked_list.h" + +typedef int (*callback_t)(void *event_arg, void *subscribtion_arg); + +typedef struct subscription_t { + callback_t callback; + void *data; +} subscription_t; + +int create_subscription(subscription_t *subscription, va_list args); + +typedef struct topic_t { + size_t id; + linked_list_t subscriptions; +} topic_t; + +int create_topic(topic_t *topic, va_list args); +int destroy_topic(topic_t *topic); + +typedef struct event_bus_t { + linked_list_t topics; +} event_bus_t; + +void event_bus_init(void); +int event_bus_exit(void); + +int event_bus_new_topic(size_t id); +int event_bus_remove_topic(size_t id); + +int event_bus_publish(size_t id, void *arg); +int event_bus_subscribe(size_t id, callback_t callback, void *data); +int event_bus_unsubscribe(size_t id, callback_t callback); + +#endif // EVENT_BUS_H \ No newline at end of file diff --git a/core/src/game.h b/core/src/game.h new file mode 100644 index 0000000..ff8d6d7 --- /dev/null +++ b/core/src/game.h @@ -0,0 +1,45 @@ +#ifndef GAME_H +#define GAME_H + +#include +#include "display.h" +#include "asset_manager.h" +#include "camera.h" +#include "event_bus.h" +#include "ecs.h" +#include "map.h" +#include "inputs.h" + +/** + * @brief Game data. + * There should be only one instance of this struct. + * + * @param event Events data + * @param texture_manager Texture manager instance + * @param entity_manager Entity manager instance + * @param is_running Game running state + * @param delta_time_ms Frame time +*/ +typedef struct game_t { + display_t display; + camera_t camera; + asset_manager_t asset_manager; + event_bus_t event_bus; + entity_manager_t entity_manager; + inputs_t inputs; + map_t *map; + + float delta_time_ms; + bool is_running; +} game_t; + +extern game_t game; + +int game_init(void); +int game_exit(void); + +void game_handle_event(void); +int game_update(void); +int game_render(void); + +#endif // GAME_H \ No newline at end of file diff --git a/core/src/inputs.c b/core/src/inputs.c new file mode 100644 index 0000000..5b58a31 --- /dev/null +++ b/core/src/inputs.c @@ -0,0 +1,14 @@ +#include "inputs.h" + +#include + +inline int poll_event(input_event_t *event) +{ + SDL_Event sdl_event; + int ret = SDL_PollEvent(&sdl_event); + + event->type = sdl_event.type; + event->key = sdl_event.key.scancode; + + return ret; +} diff --git a/core/src/inputs.h b/core/src/inputs.h new file mode 100644 index 0000000..ef2c7c7 --- /dev/null +++ b/core/src/inputs.h @@ -0,0 +1,22 @@ +#ifndef KEYBOARD_H +#define KEYBOARD_H + +#include +#include "keycodes.h" + +#define INPUT_EVENT_KEY_UP SDL_EVENT_KEY_UP +#define INPUT_EVENT_KEY_DOWN SDL_EVENT_KEY_DOWN +#define INPUT_EVENT_QUIT SDL_EVENT_QUIT + +typedef struct input_event_t { + uint32_t type; + SDL_Scancode key; +} input_event_t; + +int poll_event(input_event_t *event); + +typedef struct inputs_t { + bool keys[MAX_KEYCODES]; +} inputs_t; + +#endif // KEYBOARD_H \ No newline at end of file diff --git a/core/src/keycodes.h b/core/src/keycodes.h new file mode 100644 index 0000000..9783ac5 --- /dev/null +++ b/core/src/keycodes.h @@ -0,0 +1,15 @@ +#ifndef KEYCODES_H +#define KEYCODES_H + +#include + +#define MAX_KEYCODES SDL_SCANCODE_COUNT + +#define KEY_UP SDL_SCANCODE_W +#define KEY_DOWN SDL_SCANCODE_S +#define KEY_LEFT SDL_SCANCODE_A +#define KEY_RIGHT SDL_SCANCODE_D +#define KEY_MOD SDL_SCANCODE_LCTRL +#define KEY_INTERACT SDL_SCANCODE_E + +#endif // KEYCODES_H \ No newline at end of file diff --git a/core/src/linked_list.c b/core/src/linked_list.c new file mode 100644 index 0000000..ff117c9 --- /dev/null +++ b/core/src/linked_list.c @@ -0,0 +1,429 @@ +#include +#include "memory_alloc.h" +#include "linked_list.h" +#include "errors.h" + +elem_t *create_elem(linked_list_t *linked_list, ...) +{ + assert("Linked list cannot be NULL" && linked_list); + + elem_t *elem; + + if(linked_list->reserved) + { + elem = linked_list->reserved; + linked_list->reserved = elem->next; + } + else + { + elem = malloc(sizeof(elem_t)); + if(!elem) + { + error_printf("Failed to allocate memory : %d", errno); + return NULL; + } + + elem->data = malloc(linked_list->data_size); + if(!elem->data) + { + error_printf("Failed to allocate memory : %d", errno); + free(elem); + return NULL; + } + } + + if(linked_list->allocator) + { + va_list args, args_copy; + va_start(args, linked_list); + va_copy(args_copy, args); + + if(linked_list->allocator(elem->data, args_copy)) return_failure_ptr; + + va_end(args_copy); + va_end(args); + } + + return elem; +} + +inline int destroy_elem(linked_list_t *linked_list, elem_t *elem) +{ + assert("Linked list cannot be NULL" && linked_list); + + if(linked_list->deleter) + if(linked_list->deleter(elem->data)) return_failure_int; + + if(linked_list->size < linked_list->target_max_size) + { + elem->next = linked_list->reserved; + linked_list->reserved = elem; + } + else + { + free(elem->data); + free(elem); + } + + return EXIT_SUCCESS; +} + +void linked_list_init(linked_list_t *linked_list, size_t data_size, const allocator_t allocator, const deleter_t elem_deleter) +{ + assert("Linked list cannot be NULL" && linked_list); + + linked_list->data_size = data_size; + linked_list->allocator = allocator; + linked_list->deleter = elem_deleter; + + linked_list->first = NULL; + linked_list->last = NULL; + linked_list->size = 0; + + linked_list->reserved = NULL; + linked_list->target_max_size = 0; +} + +int linked_list_exit(linked_list_t *linked_list) +{ + assert("Linked list cannot be NULL" && linked_list); + + linked_list->target_max_size = 0; + + elem_t *current_elem = linked_list->first; + elem_t *tmp; + + while(current_elem) + { + tmp = current_elem; + + current_elem = current_elem->next; + + if(destroy_elem(linked_list, tmp)) return_failure_int; + } + + current_elem = linked_list->reserved; + + while(current_elem) + { + tmp = current_elem; + + current_elem = current_elem->next; + + free(tmp->data); + free(tmp); + } + + return EXIT_SUCCESS; +} + +int linked_list_clear(linked_list_t *linked_list) +{ + assert("Linked list cannot be NULL" && linked_list); + + elem_t *current_elem = linked_list->first; + elem_t *tmp; + + while(current_elem) + { + tmp = current_elem; + + current_elem = current_elem->next; + + if(destroy_elem(linked_list, tmp)) return_failure_int; + } + + linked_list->first = NULL; + linked_list->last = NULL; + + linked_list->size = 0; + + return EXIT_SUCCESS; +} + +int linked_list_reserve(linked_list_t *linked_list, size_t target_max_size) +{ + assert("Linked list cannot be NULL" && linked_list); + + linked_list->target_max_size = target_max_size; + + for(size_t i = linked_list->size; i < target_max_size; i++) + { + elem_t *elem = malloc(sizeof(elem_t)); + if(!elem) + { + error_printf("Failed to allocate memory : %d", errno); + return EXIT_FAILURE; + } + + elem->data = malloc(linked_list->data_size); + if(!elem->data) + { + free(elem); + error_printf("Failed to allocate memory : %d", errno); + return EXIT_FAILURE; + } + + elem->next = linked_list->reserved; + linked_list->reserved = elem; + } + + return EXIT_SUCCESS; +} + +void linked_list_push_back(linked_list_t *linked_list, elem_t *elem) +{ + assert("Linked list cannot be NULL" && linked_list); + + elem->prev = linked_list->last; + elem->next = NULL; + + if(linked_list->last) + linked_list->last->next = elem; + else + linked_list->first = elem; + + linked_list->last = elem; + + linked_list->size++; +} + +void linked_list_push_front(linked_list_t *linked_list, elem_t *elem) +{ + assert("Linked list cannot be NULL" && linked_list); + + elem->next = linked_list->first; + elem->prev = NULL; + + if(linked_list->first) + linked_list->first->prev = elem; + else + linked_list->last = elem; + + linked_list->first = elem; + + linked_list->size++; +} + +elem_t *linked_list_pop_back(linked_list_t *linked_list) +{ + assert("Linked list cannot be NULL" && linked_list); + + elem_t *elem = linked_list->last; + if(!elem) + { + error_printf("No elem to pop back."); + return NULL; + } + + linked_list->last = elem->prev; + + if(linked_list->last) + linked_list->last->next = NULL; + else + linked_list->first = NULL; + + linked_list->size--; + + return elem; +} + +elem_t *linked_list_pop_front(linked_list_t *linked_list) +{ + assert("Linked list cannot be NULL" && linked_list); + + elem_t *elem = linked_list->first; + if(!elem) + { + error_printf("No elem to pop front."); + return NULL; + } + + linked_list->first = elem->next; + + if(linked_list->first) + linked_list->first->prev = NULL; + else + linked_list->last = NULL; + + linked_list->size--; + + return elem; +} + +elem_t *linked_list_get(const linked_list_t *linked_list, size_t index) +{ + assert("Linked list cannot be NULL" && linked_list); + + if(index >= linked_list->size) + { + error_printf("List index out of range."); + return NULL; + } + + if(index == 0) + return linked_list->first; + + if(index == linked_list->size - 1) + return linked_list->last; + + elem_t *current_elem = linked_list->first; + if(!current_elem) + { + error_printf("Failed to get element : linked list is empty."); + return NULL; + } + + for (size_t i = 0; i < index; i++) + { + current_elem = current_elem->next; + } + + return current_elem; +} + +int linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index) // XXX TODO SIMPLIFY INSERT FUNC XXX // +{ + assert("Linked list cannot be NULL" && linked_list); + + if(index == 0) + { + linked_list_push_front(linked_list, elem); + return EXIT_SUCCESS; + } + else if(index == linked_list->size) + { + linked_list_push_back(linked_list, elem); + return EXIT_SUCCESS; + } + + elem_t *next_insert_elem = linked_list_get(linked_list, index); + if(!next_insert_elem) return_failure_int; + elem_t *prev_insert_elem = next_insert_elem->prev; + + elem->prev = prev_insert_elem; + elem->next = next_insert_elem; + + prev_insert_elem->next = elem; + next_insert_elem->prev = elem; + + linked_list->size++; + + return EXIT_SUCCESS; +} + +int linked_list_remove(linked_list_t *linked_list, elem_t *elem) +{ + assert("Linked list cannot be NULL" && linked_list); + + elem_t *prev_elem = elem->prev; + elem_t *next_elem = elem->next; + + if(prev_elem) prev_elem->next = next_elem; + else linked_list->first = next_elem; + if(next_elem) next_elem->prev = prev_elem; + else linked_list->last = prev_elem; + + if(destroy_elem(linked_list, elem)) return_failure_int; + + linked_list->size--; + + return EXIT_SUCCESS; +} + +elem_t *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, void *arg) +{ + assert("Linked list cannot be NULL" && linked_list); + assert("Condition cannot be NULL" && condition); + + elem_t *current_elem = linked_list->first; + elem_t *next_elem; + + while(current_elem) + { + next_elem = current_elem->next; + + if(condition(current_elem, arg)) + { + return current_elem; + } + + current_elem = next_elem; + } + + return NULL; +} + +int linked_list_remove_if(linked_list_t *linked_list, const condition_t condition, void *arg) +{ + assert("Linked list cannot be NULL" && linked_list); + assert("Condition cannot be NULL" && condition); + + elem_t *actual_elem = linked_list->first; + elem_t *next_elem; + + while(actual_elem) + { + next_elem = actual_elem->next; + + if(condition(actual_elem, arg)) + { + if(linked_list_remove(linked_list, actual_elem)) + { + return_failure_int; + } + } + + actual_elem = next_elem; + } + + return EXIT_SUCCESS; +} + +int linked_list_for_each(const linked_list_t *linked_list, const action_t action, void *arg) +{ + assert("Linked list cannot be NULL" && linked_list); + assert("Action cannot be NULL" && action); + + elem_t *current_elem = linked_list->first; + + while(current_elem) + { + if(action(current_elem, arg)) + { + return_failure_int; + } + + current_elem = current_elem->next; + } + + return EXIT_SUCCESS; +} + +static inline void swap_elems_data(elem_t *elem_a, elem_t *elem_b) +{ + void *tmp_data = elem_a->data; + elem_a->data = elem_b->data; + elem_b->data = tmp_data; +} + +void linked_list_insertion_sort(linked_list_t *linked_list, const condition_t condition, void *arg) +{ + assert("Linked list cannot be NULL" && linked_list); + assert("Condition cannot be NULL" && condition); + + elem_t *actual_elem = linked_list->first; + elem_t *next_elem; + + while(actual_elem->next) + { + next_elem = actual_elem->next; + + if(condition(actual_elem, arg)) + { + swap_elems_data(actual_elem, next_elem); + } + + actual_elem = next_elem; + } +} diff --git a/core/src/linked_list.h b/core/src/linked_list.h new file mode 100644 index 0000000..1aee598 --- /dev/null +++ b/core/src/linked_list.h @@ -0,0 +1,283 @@ +#ifndef LINKED_LIST_H +#define LINKED_LIST_H + +#include +#include +#include + +/** + * @brief Element struct for linked lists. + * This struct is the base for storing data in a linked list. + * + * @param data Raw pointer to any type of data + * @param prev Pointer to the prev element in the linked list + * @param next Pointer to the next element in the linked list +*/ +typedef struct elem_t { + void *data; + struct elem_t *prev; + struct elem_t *next; +} elem_t; + +/** + * @brief A type for allocators used during the creation of data stored in elements' data. + * + * During the initialisation of linked lists you can pass in argument an allocator. + * You can pass NULL to the initialisation to not use an allocator. + * Your allocator_t function declaration must look like this : + * + * int name_of_your_allocator(void* data, va_list args); + * + * Then do what you need to fill your data. + * + * @param data Data to fill. + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +typedef int (*allocator_t)(void *data, va_list args); + +/** + * @brief A type for deleters used during the destruction of data stored in elements' data. + * + * During the initialisation of linked lists you can pass in argument a deleter. + * You can pass NULL to the initialisation to not use a deleter. + * Your deleter_t function declaration must look like this : + * + * void name_of_your_deleter(void *data); + * + * Then do what you need to destroy your data (don't free the data itself). + * + * @param data Data to free. +*/ +typedef int (*deleter_t)(void *data); + +/** + * @brief A type for condition used for function like linked_list_remove_if. + * + * Your condition_t function declaration must look like this : + * + * bool name_of_your_condition(elem_t *elem, va_list); + * + * @param elem Processed element + * @param arg Argument to pass to the function + * + * @return False, true for the element to be removed. +*/ +typedef bool (*condition_t)(elem_t *elem, void *arg); + +/** + * @brief A type for action used for function like linked_list_for_each + * + * Your condition_t function declaration must look like this : + * + * int name_of_your_condition(elem_t *elem, va_list); + * + * @param elem Processed element + * @param arg Argument to pass to the function + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +typedef int (*action_t)(elem_t *elem, void *arg); + +/** + * @brief Base of linked lists. + * + * @param data_size Size of the data stored in elements + * @param allocator Allocator of data when creating new elements + * @param deleter Deleter of data when removing elements + * @param first Pointer to the first element in the list + * @param last Pointer to the last element in the list + * @param size Size of the linked list + * @param reserved Pointer to the first reserved element + * @param target_max_size Total target number of elements in the list +*/ +typedef struct linked_list_t { + size_t data_size; + allocator_t allocator; + deleter_t deleter; + elem_t *first; + elem_t *last; + size_t size; + elem_t *reserved; + size_t target_max_size; +} linked_list_t; + +/** + * @brief Create an elem to insert in a linked list. The data pointer is allocated. + * If there is an element available in reserved list then it will be used. + * The element returned is filled with garbage memory. + * + * @param linked_list Pointer to an linked list + * @param ... Arguments to pass to the allocator + * + * @return pointer to initialised elem, NULL on error. +*/ +elem_t *create_elem(linked_list_t *linked_list, ...); + +/** + * @brief Destroy the given element and its data. + * May move the element into the reserved list for future use depending on target size of the list. + * This function makes the given element unsafe to use. + * + * @param linked_list Pointer to a linked list + * @param elem Pointer to an element + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +int destroy_elem(linked_list_t *linked_list, elem_t *elem); + +/** + * @brief Init a linked list. + * + * @param linked_list Pointer to a linked list + * @param data_size Data size for elements data in the linked list + * @param deleter The deleter for elem +*/ +void linked_list_init(linked_list_t *linked_list, size_t data_size, const allocator_t allocator, const deleter_t deleter); + +/** + * @brief Clear the given linked list and free reserved elements, do nothing on error. + * This function makes the given linked list unsafe to use. + * + * @brief linked_list Pointer to a linked list + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +int linked_list_exit(linked_list_t *linked_list); + +/** + * @brief Pre-allocate elements for a target size. + * If you want n more elements in your list, then you want linked_list.size + n target_size. + * + * @param linked_list Pointer to a linked list + * @param target_size Target size of linked list + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. + */ +int linked_list_reserve(linked_list_t *linked_list, size_t target_size); + +/** + * @brief Clear the given linked list, do nothing on error. + * May move the elements into the reserved list for future use depending on target size of the list. + * + * @brief linked_list Pointer to a linked list + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +int linked_list_clear(linked_list_t *linked_list); + +/** + * @brief Insert an element from the back in a linked list, do nothing on error. + * + * @param linked_list Pointer to a linked list + * @param elem Pointer to an element +*/ +void linked_list_push_back(linked_list_t *linked_list, elem_t *elem); + +/** + * @brief Insert an element from the front in a linked list, do nothing on error. + * + * @param linked_list Pointer to a linked list + * @param elem Pointer to an element +*/ +void linked_list_push_front(linked_list_t *linked_list, elem_t *elem); + +/** + * @brief Remove and return the last element in the given linked list, do nothing on error. + * The element returned have unsafe `next` and `prev` pointers. + * + * @param linked_list Pointer to a linked list + * + * @return Pointer to element, NULL on error. +*/ +elem_t *linked_list_pop_back(linked_list_t *linked_list); + +/** + * @brief Remove and return the first element in the given linked list, do nothing on error. + * The element returned have unsafe `next` and `prev` pointers. + * + * @param linked_list Pointer to a linked list + * + * @return Pointer to element, NULL on error. +*/ +elem_t *linked_list_pop_front(linked_list_t *linked_list); + +/** + * @brief Insert element at the given index in the linked list, do nothing on error. + * + * @param linked_list Pointer to a linked list + * @param elem Pointer to an element + * @param index Index to insert element + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +int linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index); + +/** + * @brief Get element at the given index in the linked list. + * + * @param linked_list Pointer to a linked list + * @param index Index of the element + * + * @return Pointer to element, NULL on error. +*/ +elem_t *linked_list_get(const linked_list_t *linked_list, size_t index); + +/** + * @brief Remove the given elem in the linked list, do nothing on error. + * May move the elements into the reserved list for future use depending on target size of the list. + * This function makes the given element unsafe to use. + * + * @param linked_list Pointer to a linked list + * @param elem Element to remove + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +int linked_list_remove(linked_list_t *linked_list, elem_t *elem); + +/** + * @brief Return first element that the condition verify. + * + * @param linked_list Pointer to a linked list + * @param condition Condition to verify + * @param ... Argument to pass to the condition + * + * @return Pointer to element, NULL if no element verify the condition or if an error occurred. +*/ +elem_t *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, void *arg); + +/** + * @brief Remove every elements that the condition verify, do nothing on error. + * + * @param linked_list Pointer to an linked list + * @param condition Condition to verify + * @param ... Argument to pass to the condition + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +int linked_list_remove_if(linked_list_t *linked_list, const condition_t condition, void *arg); + +/** + * @brief Apply an action to every elements in the list. + * The action can be anything that doesn't destroy the element. + * + * @param linked_list Pointer to an linked list + * @param action Action to apply + * @param ... Argument to pass to the action + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +int linked_list_for_each(const linked_list_t *linked_list, const action_t action, void *arg); + +/** + * @brief Do an insertion sort data of the given linked list. + * The condition return true to swap element's data with next one. + * + * @param linked_list Pointer to an linked list + * @param action Action to apply + * + * @return EXIT_SUCCESS, EXIT_FAILURE on error. +*/ +void linked_list_insertion_sort(linked_list_t *linked_list, const condition_t condition, void *arg); + +#endif // LINKED_LIST_H diff --git a/core/src/main.c b/core/src/main.c new file mode 100644 index 0000000..09cb5b6 --- /dev/null +++ b/core/src/main.c @@ -0,0 +1,38 @@ +#include "game.h" + +#include +#include +#include "errors.h" + +game_t game; + +static inline void update_time(void) +{ + static uint64_t last_clock_state = 0; + uint64_t start_clock = SDL_GetTicksNS(); + game.delta_time_ms = SDL_NS_TO_MS((float)(start_clock - last_clock_state)); + if(game.delta_time_ms > 100.0f) game.delta_time_ms = 100.0f; + last_clock_state = start_clock; +} + +int main(void) +{ + if(game_init()) goto_failure; + + while(game.is_running) + { + update_time(); + game_handle_event(); + if(game_update()) goto_failure; + if(game_render()) goto_failure; + } + + if(game_exit()) return_failure_int; + + return EXIT_SUCCESS; + +failure: + game_exit(); // return failure anyway + + return EXIT_FAILURE; +} diff --git a/core/src/map.c b/core/src/map.c new file mode 100644 index 0000000..cb8b8c9 --- /dev/null +++ b/core/src/map.c @@ -0,0 +1,485 @@ +#include "map.h" + +#include "asset_manager.h" +#include "game.h" +#include "ecs.h" +#include "components.h" +#include "vector2d.h" +#include "display.h" +#include "memory_alloc.h" +#include "errors.h" + +map_t *load_map(void) +{ + map_t *map = malloc(sizeof(map_t)); + + if(fread(&map->width, sizeof(map->width), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + if(fread(&map->height, sizeof(map->height), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + if(fread(&map->backgroundlayernb, sizeof(map->backgroundlayernb), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + linked_list_init(&map->backgroundlayers, map->width * map->height * sizeof(uint16_t), NULL, NULL); + if(linked_list_reserve(&map->backgroundlayers, map->backgroundlayernb)) return_failure_ptr; + + for(uint8_t i = 0; i < map->backgroundlayernb; i++) + { + elem_t *backgroundlayer_elem = create_elem(&map->backgroundlayers); + if(!backgroundlayer_elem) return_failure_ptr; + + uint16_t *backgroundlayer = backgroundlayer_elem->data; + if(fread(backgroundlayer, sizeof(*backgroundlayer), map->width * map->height, game.asset_manager.asset_file) != (size_t)map->width * (size_t)map->height) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + linked_list_push_back(&map->backgroundlayers, backgroundlayer_elem); + } + + map->foregroundlayer = malloc(map->width * map->height * sizeof(*map->foregroundlayer)); + if(fread(map->foregroundlayer, sizeof(*map->foregroundlayer), map->width * map->height, game.asset_manager.asset_file) != (size_t)map->width * (size_t)map->height) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + map->hitboxes = malloc(map->width * map->height * sizeof(*map->hitboxes)); + if(fread(map->hitboxes, sizeof(*map->hitboxes), map->width * map->height, game.asset_manager.asset_file) != (size_t)map->width * (size_t)map->height) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + if(fread(&map->entities_nb, sizeof(map->entities_nb), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + map->entities_defs = calloc(map->entities_nb, sizeof(map_entity_def_t)); + + for(uint32_t i = 0; i < map->entities_nb; i++) + { + map_entity_def_t *entity_def = &map->entities_defs[i]; + + if(fread(&entity_def->id, sizeof(entity_def->id), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + if(fread(&entity_def->components_nb, sizeof(entity_def->components_nb), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + entity_def->components_defs = calloc(entity_def->components_nb, sizeof(map_entity_component_def_t)); + + for(uint32_t j = 0; j < entity_def->components_nb; j++) + { + map_entity_component_def_t *component_def = &entity_def->components_defs[j]; + + if(fread(&component_def->type, sizeof(component_def->type), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + + switch(component_def->type) + { + size_t data_size; + + case TRANSFORM_COMPONENT: + case HITBOX_COMPONENT: + data_size = sizeof(fvector2d_t) * 2; + component_def->attributes = malloc(data_size); + if(fread(component_def->attributes, data_size, 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + break; + + case SPRITE_COMPONENT: + { + size_t cap = 0; + if(getdelim((char **)&component_def->attributes, &cap, '\0', game.asset_manager.asset_file) == -1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + break; + } + + case ANIMATION_SYSTEM: + data_size = sizeof(int) * 2 + sizeof(float) + sizeof(bool) * 3; + component_def->attributes = malloc(data_size); + if(fread(component_def->attributes, data_size, 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + break; + + case INTERACT_COMPONENT: + data_size = sizeof(fvector2d_t) * 2 + sizeof(int) * 3; + component_def->attributes = malloc(data_size); + if(fread(component_def->attributes, data_size, 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + break; + + case DOOR_COMPONENT: + data_size = sizeof(int) + sizeof(bool); + component_def->attributes = malloc(data_size); + if(fread(component_def->attributes, data_size, 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + break; + + case LEVER_COMPONENT: + data_size = sizeof(int) + sizeof(bool); + component_def->attributes = malloc(data_size); + if(fread(component_def->attributes, data_size, 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file : %d", errno); + return NULL; + } + break; + + default: + error_printf("Component type not supported for loading : %s (%d)", component_type_to_name(component_def->type), component_def->type); + return NULL; + } + } + } + + return map; +} + +int destroy_map(map_t *map) +{ + if(map->entities_defs) + { + for(uint32_t i = 0; i < map->entities_nb; i++) + { + map_entity_def_t *entity_def = &map->entities_defs[i]; + + if(entity_def->components_defs) + { + for(uint32_t j = 0; j < entity_def->components_nb; j++) + { + map_entity_component_def_t *component_def = &entity_def->components_defs[j]; + if(component_def->attributes) free(component_def->attributes); + } + + free(entity_def->components_defs); + } + } + + free(map->entities_defs); + } + + if(map->hitboxes) free(map->hitboxes); + + if(map->foregroundlayer) free(map->foregroundlayer); + + if(linked_list_exit(&map->backgroundlayers)) return_failure_int; + + free(map); + + return EXIT_SUCCESS; +} + +int map_load_entities(map_t *map) +{ + for(uint32_t i = 0; i < map->entities_nb; i++) + { + map_entity_def_t *entity_def = &map->entities_defs[i]; + + entity_t *entity = entity_manager_new_entity(entity_def->id); + if(!entity) return_failure_int; + + for(uint32_t j = 0; j < entity_def->components_nb; j++) + { + map_entity_component_def_t *component_def = &entity_def->components_defs[j]; + + component_t *component = entity_new_component(entity, component_def->type); + if(!entity) return_failure_int; + + switch(component_def->type) + { + case TRANSFORM_COMPONENT: + { + struct { + frect_t bounds; + } *data = component_def->attributes; + + transform_component_data_t *component_data = component->data; + + component_data->bounds = data->bounds; + + break; + } + + case SPRITE_COMPONENT: + { + sprite_component_data_t *component_data = component->data; + + asset_t *texture_asset = asset_manager_load_asset((char *)component_def->attributes, ASSET_TEXTURE); + if(!texture_asset) return_failure_int; + + component_data->texture = texture_asset->data; + + break; + } + + case ANIMATION_SYSTEM: + { + struct { + int nb_frames; + int current_frame_nb; + float frame_delay_ms; + bool play; + bool loop; + bool reverse; + } *data = component_def->attributes; + + animation_system_data_t *system_data = component->data; + + system_data->nb_frames = data->nb_frames; + system_data->current_frame_nb = data->current_frame_nb; + system_data->frame_delay_ms = data->frame_delay_ms; + system_data->play = data->play; + system_data->loop = data->loop; + system_data->reverse = data->reverse; + + if(animation_system_apply_changes(component)) return_failure_int; + + break; + } + + case HITBOX_COMPONENT: + { + struct { + fvector2d_t position; + fvector2d_t scale; + } *data = component_def->attributes; + + hitbox_component_data_t *component_data = component->data; + + component_data->position = data->position; + component_data->scale = data->scale; + + break; + } + + case DOOR_COMPONENT: + { + struct { + int topic_id; + bool state; + } *data = component_def->attributes; + + door_component_data_t *component_data = component->data; + + component_data->topic_id = data->topic_id; + component_data->state = data->state; + + if(door_component_subscribe(component)) return_failure_int; + + break; + } + + case INTERACT_COMPONENT: + { + struct { + fvector2d_t position; + fvector2d_t scale; + int topic_id; + int type; + int state; + } *data = component_def->attributes; + + interact_component_data_t *component_data = component->data; + + component_data->position = data->position; + component_data->scale = data->scale; + component_data->type = data->type; + component_data->state = data->state; + + if(event_bus_new_topic(data->topic_id)) return_failure_int; + + break; + } + + case LEVER_COMPONENT: + { + struct { + int topic_id; + bool state; + } *data = component_def->attributes; + + lever_component_data_t *component_data = component->data; + + component_data->topic_id = data->topic_id; + component_data->state = data->state; + + if(lever_component_subscribe(component)) return_failure_int; + + break; + } + + default: + error_printf("Component type not supported for loading : %s (%d)", component_type_to_name(component_def->type), component_def->type); + return EXIT_FAILURE; + } + } + } + + return EXIT_SUCCESS; +} + +int map_remove_entities(map_t *map) +{ + for(uint32_t i = 0; i < map->entities_nb; i++) + { + map_entity_def_t *entity_def = &map->entities_defs[i]; + + if(entity_manager_remove_entity(entity_def->id)) return_failure_int; + + for(uint32_t j = 0; j < entity_def->components_nb; j++) + { + map_entity_component_def_t *component_def = &entity_def->components_defs[j]; + + switch(component_def->type) + { + case SPRITE_COMPONENT: + if(asset_manager_let_go_asset((char *)component_def->attributes)) return_failure_int; + break; + + case INTERACT_COMPONENT: + { + struct { + fvector2d_t position; + fvector2d_t scale; + int topic_id; + int type; + int state; + } *data = component_def->attributes; + + if(event_bus_remove_topic(data->topic_id)) return_failure_int; + + break; + } + + default: + break; + } + } + } + + return EXIT_SUCCESS; +} + + +static inline int draw_tile(uint16_t tile_x, uint16_t tile_y, uint16_t tile_id) +{ + if(!tile_id) return EXIT_SUCCESS; + + rect_t src_frect = { + .x = tile_id * TILE_SIZE % game.map->tileset->w, + .y = tile_id * TILE_SIZE / game.map->tileset->w * TILE_SIZE, + .w = TILE_SIZE, + .h = TILE_SIZE + }; + + rect_t dst_frect = { + .x = tile_x * TILE_SIZE, + .y = tile_y * TILE_SIZE, + .w = TILE_SIZE, + .h = TILE_SIZE + }; + + if(display_draw_texture(game.map->tileset, &src_frect, &dst_frect, false)) return_failure_int; + + return EXIT_SUCCESS; +} + +int map_display_background(void) +{ + uint16_t left_tile = 0; + if(game.camera.view_rect.x / TILE_SIZE > 0) + left_tile = game.camera.view_rect.x / TILE_SIZE; + + uint16_t right_tile = game.map->width; + if((game.camera.view_rect.x + game.camera.view_rect.w) / TILE_SIZE + 1 < game.map->width) + right_tile = (game.camera.view_rect.x + game.camera.view_rect.w) / TILE_SIZE + 1; + + uint16_t top_tile = 0; + if(game.camera.view_rect.y / TILE_SIZE > 0) + top_tile = game.camera.view_rect.y / TILE_SIZE; + + uint16_t bottom_tile = game.map->height; + if((game.camera.view_rect.y + game.camera.view_rect.h) / TILE_SIZE + 1 < game.map->height) + bottom_tile = (game.camera.view_rect.y + game.camera.view_rect.h) / TILE_SIZE + 1; + + for(uint16_t tile_y = top_tile; tile_y < bottom_tile; tile_y++) + for(uint16_t tile_x = left_tile; tile_x < right_tile; tile_x++) + { + elem_t *backgroundlayer_elem = game.map->backgroundlayers.first; + + while(backgroundlayer_elem) + { + if(draw_tile(tile_x, tile_y, ((uint16_t *)backgroundlayer_elem->data)[tile_y * game.map->width + tile_x])) return_failure_int; + backgroundlayer_elem = backgroundlayer_elem->next; + } + } + + return EXIT_SUCCESS; +} + +int map_display_foreground(void) +{ + uint32_t left_tile = 0; + if(game.camera.view_rect.x / TILE_SIZE > 0) + left_tile = game.camera.view_rect.x / TILE_SIZE; + + uint32_t right_tile = game.map->width; + if((game.camera.view_rect.x + game.camera.view_rect.w) / TILE_SIZE + 1 < (int)game.map->width) + right_tile = (game.camera.view_rect.x + game.camera.view_rect.w) / TILE_SIZE + 1; + + uint32_t top_tile = 0; + if(game.camera.view_rect.y / TILE_SIZE > 0) + top_tile = game.camera.view_rect.y / TILE_SIZE; + + uint32_t bottom_tile = game.map->height; + if((game.camera.view_rect.y + game.camera.view_rect.h) / TILE_SIZE + 1 < (int)game.map->height) + bottom_tile = (game.camera.view_rect.y + game.camera.view_rect.h) / TILE_SIZE + 1; + + for(uint32_t tile_y = top_tile; tile_y < bottom_tile; tile_y++) + for(uint32_t tile_x = left_tile; tile_x < right_tile; tile_x++) + { + if(draw_tile(tile_x, tile_y, game.map->foregroundlayer[tile_y * game.map->width + tile_x])) return_failure_int; + } + + return EXIT_SUCCESS; +} diff --git a/core/src/map.h b/core/src/map.h new file mode 100644 index 0000000..f8579fa --- /dev/null +++ b/core/src/map.h @@ -0,0 +1,44 @@ +#ifndef MAP_H +#define MAP_H + +#include +#include "linked_list.h" +#include "texture.h" + +#define TILE_SIZE 16 + +typedef struct map_entity_component_def_t { + uint16_t type; + void *attributes; +} map_entity_component_def_t; + +typedef struct map_entity_def_t { + uint32_t id; + uint16_t components_nb; + map_entity_component_def_t *components_defs; +} map_entity_def_t; + +typedef struct map_t { + uint16_t width, height; + uint8_t backgroundlayernb; + linked_list_t backgroundlayers; + uint16_t *foregroundlayer; + texture_t *tileset; + uint8_t *hitboxes; + uint16_t entities_nb; + map_entity_def_t *entities_defs; +} map_t; + +map_t *load_map(void); + +int destroy_map(map_t *map); + +int map_load_entities(map_t *map); + +int map_remove_entities(map_t *map); + +int map_display_background(void); + +int map_display_foreground(void); + +#endif // MAP_H \ No newline at end of file diff --git a/core/src/memory_alloc.h b/core/src/memory_alloc.h new file mode 100644 index 0000000..ef8e8b6 --- /dev/null +++ b/core/src/memory_alloc.h @@ -0,0 +1,6 @@ +#ifndef MEMORY_ALLOC_H +#define MEMORY_ALLOC_H + +#include + +#endif // MEMORY_ALLOC_H \ No newline at end of file diff --git a/core/src/texture.c b/core/src/texture.c new file mode 100644 index 0000000..b159a19 --- /dev/null +++ b/core/src/texture.c @@ -0,0 +1,67 @@ +#include "texture.h" + +#include "asset_manager.h" +#include "game.h" +#include "display.h" +#include "errors.h" + +texture_t *load_texture(void) +{ + uint16_t width, height; + + if(fread(&width, sizeof(width), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file."); + return NULL; + } + + if(fread(&height, sizeof(height), 1, game.asset_manager.asset_file) != 1) + { + error_printf("Failed to read in asset file."); + return NULL; + } + + SDL_Surface *tmp_surface = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGB565); + if(!tmp_surface) + { + error_printf("Failed to create temporary surface : %s", SDL_GetError()); + return NULL; + } + + if(!SDL_LockSurface(tmp_surface)) + { + error_printf("Failed to lock temporary surface : %s", SDL_GetError()); + goto_failure; + } + + if(fread(tmp_surface->pixels, sizeof(uint16_t), width * height, game.asset_manager.asset_file) != (size_t)width * (size_t)height) + { + error_printf("Failed to read asset file."); + goto_failure; + } + + if(!SDL_SetSurfaceColorKey(tmp_surface, true, TEXTURE_TRANSPARENT_COLOR)) + { + error_printf("Failed to set color key of temporary surface : %s", SDL_GetError()); + goto_failure; + } + + texture_t *texture = SDL_CreateTextureFromSurface(game.display.renderer, tmp_surface); + if(!texture) + { + error_printf("Failed to create texture from temporary surface : %s", SDL_GetError()); + goto_failure; + } + + SDL_DestroySurface(tmp_surface); + return texture; + +failure: + SDL_DestroySurface(tmp_surface); + return NULL; +} + +void destroy_texture(texture_t *texture) +{ + SDL_DestroyTexture(texture); +} diff --git a/core/src/texture.h b/core/src/texture.h new file mode 100644 index 0000000..bcd641e --- /dev/null +++ b/core/src/texture.h @@ -0,0 +1,13 @@ +#ifndef TEXTURE_H +#define TEXTURE_H + +#include + +#define TEXTURE_TRANSPARENT_COLOR 0x0001 + +typedef SDL_Texture texture_t; + +texture_t *load_texture(void); +void destroy_texture(texture_t *texture); + +#endif // TEXTURE_H \ No newline at end of file diff --git a/core/src/vector2d.c b/core/src/vector2d.c new file mode 100644 index 0000000..d52ae03 --- /dev/null +++ b/core/src/vector2d.c @@ -0,0 +1,27 @@ +#include "vector2d.h" + +void rect_to_frect(const rect_t *rect, frect_t *frect) +{ + frect->x = (float)rect->x; + frect->y = (float)rect->y; + frect->w = (float)rect->w; + frect->h = (float)rect->h; +} + +void frect_to_rect(const frect_t *frect, rect_t *rect) +{ + rect->x = (int)frect->x; + rect->y = (int)frect->y; + rect->w = (int)frect->w; + rect->h = (int)frect->h; +} + +inline float lerp(float a, float b, float s) +{ + return a * (1 - s) + b * s; +} + +inline float lerp_time(float a, float b, float s, float t) +{ + return lerp(a, b, 1 - powf(1 - s, t * 60.0f)); +} \ No newline at end of file diff --git a/core/src/vector2d.h b/core/src/vector2d.h new file mode 100644 index 0000000..ab511b8 --- /dev/null +++ b/core/src/vector2d.h @@ -0,0 +1,153 @@ +#ifndef VECTOR2D_H +#define VECTOR2D_H + +#include +#include + +/** + * @brief Point struct. (int) + * + * @param x X pos + * @param y Y pos +*/ +typedef SDL_Point vector2d_t; + +/** + * @brief Point struct. (float) + * + * @param x X pos + * @param y Y pos +*/ +typedef SDL_FPoint fvector2d_t; + +/** + * @brief Rectangle struct. (int) + * + * @param x X pos + * @param y Y pos + * @param w Width + * @param h Height +*/ +typedef SDL_Rect rect_t; + +/** + * @brief Rectangle struct. (float) + * + * @param x X pos + * @param y Y pos + * @param w Width + * @param h Height +*/ +typedef SDL_FRect frect_t; + +#define EPSILON 0.000001f + +#define f_is_zero(X) (fabsf(X) <= EPSILON) + +#define f_is_not_zero(X) (fabsf(X) > EPSILON) + +void rect_to_frect(const rect_t *rect, frect_t *frect); + +void frect_to_rect(const frect_t *frect, rect_t *rect); + +/** + * @brief Verify if a point is in a rectangle. (int) + * + * @param P Vector2d + * @param R Rectangle + * + * @return True if the point is in the rectangle, else false. +*/ +#define point_in_rect(P, R) SDL_PointInRect(P, R) + +/** + * @brief Verify if a point is in a rectangle. (float) + * + * @param P Vector2d + * @param R Rectangle + * + * @return True if the point is in the rectangle, else false. +*/ +#define fpoint_in_frect(P, R) SDL_PointInRectF(P, R) + +/** + * @brief Verify if a rectangle is empty + * + * @param R Rectangle + * + * @return True if the rectangle is empty, else false. +*/ +#define rect_empty(R) SDL_RectEmpty(R) + +/** + * @brief Verify if a rectangle is empty + * + * @param R Rectangle + * + * @return True if the rectangle is empty, else false. +*/ +#define frect_empty(R) SDL_FRectEmpty(R) + +/** + * @brief Verify if there is a intersction between two rectangles. (int) + * + * @param A Rectangle A + * @param B Rectangle B + * + * @return True if there is an intersection, else false. +*/ +#define has_intersection(A, B) SDL_HasRectIntersection(A, B) + +/** + * @brief Verify if there is a intersction between two rectangles. (float) + * + * @param A Rectangle A + * @param B Rectangle B + * + * @return True if there is an intersection, else false. +*/ +#define fhas_intersection(A, B) SDL_HasRectIntersectionFloat(A, B) + +/** + * @brief Verify if there is an intersection between two rectangles and get the intersection rectangle. (int) + * + * @param A Rectangle A + * @param B Rectangle B + * @param result The intersection rectangle + * + * @return True if there is an intersection, else false. +*/ +#define intersect_rect(A, B, result) SDL_GetRectIntersection(A, B, result) + +/** + * @brief Verify if there is an intersection between two rectangles and get the intersection rectangle. (float) + * + * @param A Rectangle A + * @param B Rectangle B + * @param result The intersection rectangle + * + * @return True if there is an intersection, else false. +*/ +#define intersect_frect(A, B, result) SDL_GetRectIntersectionFloat(A, B, result) + +/** + * @brief Lerp a to b with smoothing factor s. + * + * @param a Current value + * @param b Target value + * @param s Smoothing factor + */ +float lerp(float a, float b, float s); + +/** + * @brief Lerp a to b with smoothing factor s and time basis t. + * Smoothing factor is for 60 fps call time. + * + * @param a Current value + * @param b Target value + * @param s Smoothing factor + * @param t Delta time + */ +float lerp_time(float a, float b, float s, float t); + +#endif // VECTOR2D_H \ No newline at end of file diff --git a/shell.nix b/shell.nix index 853ba2c..6175e17 100644 --- a/shell.nix +++ b/shell.nix @@ -12,6 +12,7 @@ pkgs.mkShell { libpng json_c sdl3 + lua ncurses ]; diff --git a/src/.ccls b/src/.ccls index 699750e..0603b1e 100644 --- a/src/.ccls +++ b/src/.ccls @@ -1,7 +1,7 @@ gcc # Headers --Isrc/components/headers --ISDL3_Core/src/headers +-Isrc/components +-Icore/src # Macros -DDEBUG=2 diff --git a/src/Makefile b/src/Makefile index 920c46b..38999f5 100644 --- a/src/Makefile +++ b/src/Makefile @@ -31,7 +31,7 @@ SRC_CFLAGS = --std=c17 --pedantic -O1 -g -DDEBUG=2 \ SRC_LDFLAGS = -O1 endif -SRC_INCLUDE_DIRS = $(SOURCE_DIR)/components/headers $(CORE_DIR)/headers +SRC_INCLUDE_DIRS = $(SOURCE_DIR)/components $(CORE_DIR) SRC_INCLUDE_DIRS := $(addprefix -I, $(SRC_INCLUDE_DIRS)) # Deduce objects diff --git a/src/components/headers/animation_system.h b/src/components/animation_system.h similarity index 100% rename from src/components/headers/animation_system.h rename to src/components/animation_system.h diff --git a/src/components/headers/components.def b/src/components/components.def similarity index 100% rename from src/components/headers/components.def rename to src/components/components.def diff --git a/src/components/headers/components.h b/src/components/components.h similarity index 100% rename from src/components/headers/components.h rename to src/components/components.h diff --git a/src/components/headers/door_component.h b/src/components/door_component.h similarity index 100% rename from src/components/headers/door_component.h rename to src/components/door_component.h diff --git a/src/components/headers/hitbox_component.h b/src/components/hitbox_component.h similarity index 100% rename from src/components/headers/hitbox_component.h rename to src/components/hitbox_component.h diff --git a/src/components/headers/interact_component.h b/src/components/interact_component.h similarity index 100% rename from src/components/headers/interact_component.h rename to src/components/interact_component.h diff --git a/src/components/headers/lever_component.h b/src/components/lever_component.h similarity index 100% rename from src/components/headers/lever_component.h rename to src/components/lever_component.h diff --git a/src/components/lua_component.h b/src/components/lua_component.h new file mode 100644 index 0000000..e69de29 diff --git a/src/components/headers/physics_system.h b/src/components/physics_system.h similarity index 100% rename from src/components/headers/physics_system.h rename to src/components/physics_system.h diff --git a/src/components/headers/player_system.h b/src/components/player_system.h similarity index 100% rename from src/components/headers/player_system.h rename to src/components/player_system.h diff --git a/src/components/headers/sprite_component.h b/src/components/sprite_component.h similarity index 100% rename from src/components/headers/sprite_component.h rename to src/components/sprite_component.h diff --git a/src/components/headers/transform_component.h b/src/components/transform_component.h similarity index 100% rename from src/components/headers/transform_component.h rename to src/components/transform_component.h