Compare commits
No commits in common. "d0dda33a7ab46a45c535120537e958057ee5a2e7" and "2e1e28b1913e0b3a1e40ebe9f22ba30176abc735" have entirely different histories.
d0dda33a7a
...
2e1e28b191
|
|
@ -1,4 +1,2 @@
|
||||||
.vscode/ccls-cache
|
.vscode/ccls-cache
|
||||||
.cache
|
|
||||||
.config
|
|
||||||
build
|
build
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "SDL3_Core"]
|
||||||
|
path = SDL3_Core
|
||||||
|
url = https://gitea.skadubpc.net/ulysse/2D_Engine_SDL3_Core.git
|
||||||
|
|
@ -1,11 +1,5 @@
|
||||||
{
|
{
|
||||||
"nixEnvSelector.suggestion": false,
|
"nixEnvSelector.suggestion": false,
|
||||||
"nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix",
|
"nixEnvSelector.nixFile": "${workspaceFolder}/shell.nix",
|
||||||
"nixEnvSelector.useFlakes": false,
|
"nixEnvSelector.useFlakes": false
|
||||||
|
|
||||||
"files.associations": {
|
|
||||||
"*.tsx": "xml",
|
|
||||||
"*.map": "json",
|
|
||||||
"configure": "shellscript"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
18
Makefile
18
Makefile
|
|
@ -3,9 +3,13 @@ SHELL = /usr/bin/env bash
|
||||||
# Build folder
|
# Build folder
|
||||||
BUILD_DIR = build
|
BUILD_DIR = build
|
||||||
|
|
||||||
# Outputs target name and path
|
# Source output target name
|
||||||
SOURCE_OUTPUT = $(BUILD_DIR)/2D_Engine
|
SOURCE_OUTPUT = $(BUILD_DIR)/2D_Engine
|
||||||
|
|
||||||
|
# Core output target name
|
||||||
CORE_OUTPUT = $(BUILD_DIR)/libcore.a
|
CORE_OUTPUT = $(BUILD_DIR)/libcore.a
|
||||||
|
|
||||||
|
# Assets output
|
||||||
ASSET_OUTPUT = $(BUILD_DIR)/game.data
|
ASSET_OUTPUT = $(BUILD_DIR)/game.data
|
||||||
|
|
||||||
# Verbosity
|
# Verbosity
|
||||||
|
|
@ -15,20 +19,20 @@ Q :=
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Colors
|
# Colors
|
||||||
export GREEN := \033[32m
|
GREEN := \033[32m
|
||||||
export YELLOW := \033[33m
|
YELLOW := \033[33m
|
||||||
export RESET := \033[m
|
RESET := \033[m
|
||||||
|
|
||||||
# Default targets
|
# Default targets
|
||||||
all: $(SOURCE_OUTPUT)
|
all: build_core build_src build_assets
|
||||||
|
|
||||||
# Sub Makefiles
|
# Sub Makefiles
|
||||||
SOURCE_DIR = src
|
SOURCE_DIR = src
|
||||||
CORE_DIR = core/src
|
CORE_DIR = SDL3_Core/src
|
||||||
ASSETS_DIR = assets
|
ASSETS_DIR = assets
|
||||||
|
|
||||||
include $(SOURCE_DIR)/Makefile
|
|
||||||
include $(CORE_DIR)/Makefile
|
include $(CORE_DIR)/Makefile
|
||||||
|
include $(SOURCE_DIR)/Makefile
|
||||||
include $(ASSETS_DIR)/Makefile
|
include $(ASSETS_DIR)/Makefile
|
||||||
|
|
||||||
# Clean
|
# Clean
|
||||||
|
|
|
||||||
|
|
@ -6,4 +6,4 @@ A multi-platform 2D_Engine made in C.
|
||||||
|
|
||||||
## Licences
|
## Licences
|
||||||
- This program is open-source : you can redistribute and/or modify it under the term of the **GNU GPLv3**.
|
- 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).
|
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).
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit bc3f9b4726b7a5cb9522bc959f6086095d5f4301
|
||||||
2
TODO.md
2
TODO.md
|
|
@ -28,8 +28,6 @@
|
||||||
|
|
||||||
- [ ] Create lua component
|
- [ ] Create lua component
|
||||||
|
|
||||||
- [ ] Rethink makefile structure
|
|
||||||
|
|
||||||
### Done
|
### Done
|
||||||
|
|
||||||
- [x] Make camera center on map
|
- [x] Make camera center on map
|
||||||
|
|
|
||||||
|
|
@ -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)
|
ASSET_BUILDER_LDFLAGS = -O1 $(shell pkg-config --libs libpng json-c)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ASSET_BUILDER_INCLUDE_DIRS = $(SOURCE_DIR)/components $(ASSET_BUILDER_DIR)
|
ASSET_BUILDER_INCLUDE_DIRS = $(ASSET_BUILDER_DIR)/headers $(SOURCE_DIR)/components/headers
|
||||||
ASSET_BUILDER_INCLUDE_DIRS := $(addprefix -I, $(ASSET_BUILDER_INCLUDE_DIRS))
|
ASSET_BUILDER_INCLUDE_DIRS := $(addprefix -I, $(ASSET_BUILDER_INCLUDE_DIRS))
|
||||||
|
|
||||||
# Deduce objects
|
# Deduce objects
|
||||||
|
|
|
||||||
|
|
@ -1,145 +0,0 @@
|
||||||
#!/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
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
[](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).
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
gcc
|
|
||||||
# Headers
|
|
||||||
-Icore/src
|
|
||||||
-Isrc/components
|
|
||||||
|
|
||||||
# Macros
|
|
||||||
-DDEBUG=2
|
|
||||||
-DASSET_FILE_NAME="$(make print-ASSET_OUTPUT)"
|
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
# 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)
|
|
||||||
|
|
@ -1,234 +0,0 @@
|
||||||
#include "asset_manager.h"
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
#ifndef ASSET_MANAGER_H
|
|
||||||
#define ASSET_MANAGER_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#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
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
#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
|
|
||||||
|
|
@ -1,188 +0,0 @@
|
||||||
#include "display.h"
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
#ifndef DISPLAY_H
|
|
||||||
#define DISPLAY_H
|
|
||||||
|
|
||||||
#include <SDL3/SDL_render.h>
|
|
||||||
#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
|
|
||||||
222
core/src/ecs.c
222
core/src/ecs.c
|
|
@ -1,222 +0,0 @@
|
||||||
#include "ecs.h"
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
#ifndef ECS_H
|
|
||||||
#define ECS_H
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#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
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
#ifndef ERRORS_H
|
|
||||||
#define ERRORS_H
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <assert.h>
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
@ -1,140 +0,0 @@
|
||||||
#include "event_bus.h"
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
#ifndef EVENT_BUS_H
|
|
||||||
#define EVENT_BUS_H
|
|
||||||
|
|
||||||
#include <stdarg.h>
|
|
||||||
#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
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
#ifndef GAME_H
|
|
||||||
#define GAME_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#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
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
#include "inputs.h"
|
|
||||||
|
|
||||||
#include <SDL3/SDL_events.h>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
#ifndef KEYBOARD_H
|
|
||||||
#define KEYBOARD_H
|
|
||||||
|
|
||||||
#include <SDL3/SDL_events.h>
|
|
||||||
#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
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
#ifndef KEYCODES_H
|
|
||||||
#define KEYCODES_H
|
|
||||||
|
|
||||||
#include <SDL3/SDL_events.h>
|
|
||||||
|
|
||||||
#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
|
|
||||||
|
|
@ -1,429 +0,0 @@
|
||||||
#include <stdarg.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,283 +0,0 @@
|
||||||
#ifndef LINKED_LIST_H
|
|
||||||
#define LINKED_LIST_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
#include "game.h"
|
|
||||||
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
485
core/src/map.c
485
core/src/map.c
|
|
@ -1,485 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
#ifndef MAP_H
|
|
||||||
#define MAP_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#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
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
#ifndef MEMORY_ALLOC_H
|
|
||||||
#define MEMORY_ALLOC_H
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#endif // MEMORY_ALLOC_H
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
#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);
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
#ifndef TEXTURE_H
|
|
||||||
#define TEXTURE_H
|
|
||||||
|
|
||||||
#include <SDL3/SDL_render.h>
|
|
||||||
|
|
||||||
#define TEXTURE_TRANSPARENT_COLOR 0x0001
|
|
||||||
|
|
||||||
typedef SDL_Texture texture_t;
|
|
||||||
|
|
||||||
texture_t *load_texture(void);
|
|
||||||
void destroy_texture(texture_t *texture);
|
|
||||||
|
|
||||||
#endif // TEXTURE_H
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
#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));
|
|
||||||
}
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
#ifndef VECTOR2D_H
|
|
||||||
#define VECTOR2D_H
|
|
||||||
|
|
||||||
#include <SDL3/SDL_rect.h>
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
|
|
@ -12,7 +12,6 @@ pkgs.mkShell {
|
||||||
libpng
|
libpng
|
||||||
json_c
|
json_c
|
||||||
sdl3
|
sdl3
|
||||||
lua
|
|
||||||
ncurses
|
ncurses
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
gcc
|
gcc
|
||||||
# Headers
|
# Headers
|
||||||
-Isrc/components
|
-Isrc/components/headers
|
||||||
-Icore/src
|
-ISDL3_Core/src/headers
|
||||||
|
|
||||||
# Macros
|
# Macros
|
||||||
-DDEBUG=2
|
-DDEBUG=2
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ SRC_CFLAGS = --std=c17 --pedantic -O1 -g -DDEBUG=2 \
|
||||||
SRC_LDFLAGS = -O1
|
SRC_LDFLAGS = -O1
|
||||||
endif
|
endif
|
||||||
|
|
||||||
SRC_INCLUDE_DIRS = $(SOURCE_DIR)/components $(CORE_DIR)
|
SRC_INCLUDE_DIRS = $(SOURCE_DIR)/components/headers $(CORE_DIR)/headers
|
||||||
SRC_INCLUDE_DIRS := $(addprefix -I, $(SRC_INCLUDE_DIRS))
|
SRC_INCLUDE_DIRS := $(addprefix -I, $(SRC_INCLUDE_DIRS))
|
||||||
|
|
||||||
# Deduce objects
|
# Deduce objects
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ COMPONENT(ANIMATION_SYSTEM, animation_system, NO_DRAW)
|
||||||
COMPONENT(PLAYER_SYSTEM, player_system, NO_DRAW)
|
COMPONENT(PLAYER_SYSTEM, player_system, NO_DRAW)
|
||||||
COMPONENT(LEVER_COMPONENT, lever_component, NO_DRAW)
|
COMPONENT(LEVER_COMPONENT, lever_component, NO_DRAW)
|
||||||
COMPONENT(DOOR_COMPONENT, door_component, NO_DRAW)
|
COMPONENT(DOOR_COMPONENT, door_component, NO_DRAW)
|
||||||
// COMPONENT(LUA_COMPONENT, lua_component, NO_DRAW)
|
COMPONENT(LUA_COMPONENT, lua_component, NO_DRAW)
|
||||||
// Add new components definition here
|
// Add new components definition here
|
||||||
|
|
||||||
#undef COMPONENT
|
#undef COMPONENT
|
||||||
Loading…
Reference in New Issue