From c56b46220378c228a2bb0350e3fb67bc3c2affc1 Mon Sep 17 00:00:00 2001 From: Ulysse Cura Date: Fri, 22 Aug 2025 09:22:36 +0200 Subject: [PATCH] Added verbose task and extended Makefile for personnalised fxconv converters. Changed assets and started map loading converter and cc --- .vscode/settings.json | 5 +- .vscode/tasks.json | 22 +- 3rd_party/gint/image.h | 102 +++ .../json => 3rd_party/nlohmann}/LICENSE.MIT | 0 {src => 3rd_party}/nlohmann/json/json.hpp | 0 Makefile | 19 +- README.md | 8 +- assets/maps/dungeon_entry.example | 24 - assets/maps/example.json | 92 ++ assets/maps/fxconv-metadata.txt | 3 + assets/maps/map_converter.py | 53 ++ .../install_extension.sh | 10 + .../{example.py => json_export_tool.py} | 16 +- .../PenzillaDesign_StandardLicense.pdf | Bin 0 -> 88141 bytes assets/player-sheets/player_attack_sheet.png | Bin 0 -> 3120 bytes assets/player-sheets/player_death_sheet.png | Bin 0 -> 1552 bytes assets/player-sheets/player_hit_sheet.png | Bin 0 -> 832 bytes assets/player-sheets/player_idle_sheet.png | Bin 4273 -> 719 bytes assets/player-sheets/player_run_sheet.png | Bin 0 -> 1275 bytes assets/player-sheets/player_walk_sheet.png | Bin 5322 -> 947 bytes assets/{ => tileset}/Terms.pdf | Bin gint/config.h | 83 -- gint/defs/attributes.h | 50 -- gint/defs/types.h | 68 -- gint/display-cg.h | 143 --- gint/image.h | 846 ------------------ src/game_data.cpp | 23 - src/game_data.hpp | 31 - src/game_data/ecs/animation_system.hpp | 16 + src/game_data/ecs/components.hpp | 9 + src/game_data/ecs/ecs.hpp | 31 + src/game_data/ecs/sprite_component.hpp | 8 + src/game_data/ecs/transform_component.hpp | 10 + src/game_data/game_data.cpp | 11 + src/game_data/game_data.hpp | 21 + src/game_data/maps.hpp | 29 + src/game_data/textures.hpp | 25 + src/main.cpp | 14 +- src/test.cpp | 14 - 39 files changed, 473 insertions(+), 1313 deletions(-) create mode 100644 3rd_party/gint/image.h rename {src/nlohmann/json => 3rd_party/nlohmann}/LICENSE.MIT (100%) rename {src => 3rd_party}/nlohmann/json/json.hpp (100%) delete mode 100644 assets/maps/dungeon_entry.example create mode 100644 assets/maps/example.json create mode 100644 assets/maps/fxconv-metadata.txt create mode 100644 assets/maps/map_converter.py create mode 100755 assets/maps/tiled-python-extension/install_extension.sh rename assets/maps/tiled-python-extension/{example.py => json_export_tool.py} (74%) create mode 100644 assets/player-sheets/PenzillaDesign_StandardLicense.pdf create mode 100644 assets/player-sheets/player_attack_sheet.png create mode 100644 assets/player-sheets/player_death_sheet.png create mode 100644 assets/player-sheets/player_hit_sheet.png create mode 100644 assets/player-sheets/player_run_sheet.png rename assets/{ => tileset}/Terms.pdf (100%) delete mode 100644 gint/config.h delete mode 100644 gint/defs/attributes.h delete mode 100644 gint/defs/types.h delete mode 100644 gint/display-cg.h delete mode 100644 gint/image.h delete mode 100644 src/game_data.cpp delete mode 100644 src/game_data.hpp create mode 100644 src/game_data/ecs/animation_system.hpp create mode 100644 src/game_data/ecs/components.hpp create mode 100644 src/game_data/ecs/ecs.hpp create mode 100644 src/game_data/ecs/sprite_component.hpp create mode 100644 src/game_data/ecs/transform_component.hpp create mode 100644 src/game_data/game_data.cpp create mode 100644 src/game_data/game_data.hpp create mode 100644 src/game_data/maps.hpp create mode 100644 src/game_data/textures.hpp delete mode 100644 src/test.cpp diff --git a/.vscode/settings.json b/.vscode/settings.json index c53f23a..5140f25 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,7 @@ { "files.associations": { + "fxconv": "python", + "*.MIT": "markdown", "complex": "cpp", "string": "cpp", "iterator": "cpp", @@ -15,6 +17,7 @@ "system_error": "cpp", "stdexcept": "cpp", "iostream": "cpp", - "ios": "cpp" + "ios": "cpp", + "vector2d.hpp": "c" } } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index a0c33ac..7dfce39 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -33,9 +33,27 @@ "reveal": "never", "focus": false, "panel": "shared", + "showReuseMessage": false, + "clear": true + } + }, + { + "label": "Build Verbose", + "detail": "Build project with verbosity on", + "type": "shell", + "command": "make", + "args": [ + "VERBOSE=1" + ], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "shared", "showReuseMessage": true, - "clear": false + "clear": true } } - ] + ] } \ No newline at end of file diff --git a/3rd_party/gint/image.h b/3rd_party/gint/image.h new file mode 100644 index 0000000..d4a9989 --- /dev/null +++ b/3rd_party/gint/image.h @@ -0,0 +1,102 @@ +//--- +// gint:image - Image manipulation +// +// Note: this module is currently only available on fx-CG. +// +// This module supports 3 bit depths: full-color 16-bit (RGB565), indexed 8-bit +// (P8) and indexed 4-bit (P4). All three have an "alpha" variation where one +// color is treated as transparent, leading to 6 total formats. +//--- + +#ifndef GINT_IMAGE +#define GINT_IMAGE + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +//--- +// Image structures +//--- + +/* Image formats. Note that transparency really only indicates the default + rendering method, as a transparent background can always be added or removed + by a dynamic effect on any image. */ +enum { + IMAGE_RGB565 = 0, /* RGB565 without alpha */ + IMAGE_RGB565A = 1, /* RGB565 with one transparent color */ + IMAGE_P8_RGB565 = 4, /* 8-bit palette, all opaque colors */ + IMAGE_P8_RGB565A = 5, /* 8-bit with one transparent color */ + IMAGE_P4_RGB565 = 6, /* 4-bit palette, all opaque colors */ + IMAGE_P4_RGB565A = 3, /* 4-bit with one transparent color */ + + IMAGE_DEPRECATED_P8 = 2, +}; + +/* Quick macros to compare formats by storage size */ +#define IMAGE_IS_RGB16(format) \ + ((format) == IMAGE_RGB565 || (format) == IMAGE_RGB565A) +#define IMAGE_IS_P8(format) \ + ((format) == IMAGE_P8_RGB565 || (format) == IMAGE_P8_RGB565A) +#define IMAGE_IS_P4(format) \ + ((format) == IMAGE_P4_RGB565 || (format) == IMAGE_P4_RGB565A) +/* Check whether image format has an alpha color */ +#define IMAGE_IS_ALPHA(format) \ + ((format) == IMAGE_RGB565A || \ + (format) == IMAGE_P8_RGB565A || \ + (format) == IMAGE_P4_RGB565A) +/* Check whether image format uses a palette */ +#define IMAGE_IS_INDEXED(format) \ + (IMAGE_IS_P8(format) || IMAGE_IS_P4(format)) + +/* Image flags. These are used for memory management, mostly. */ +enum { + IMAGE_FLAGS_DATA_RO = 0x01, /* Data is read-only */ + IMAGE_FLAGS_PALETTE_RO = 0x02, /* Palette is read-only */ + IMAGE_FLAGS_DATA_ALLOC = 0x04, /* Data is malloc()'d */ + IMAGE_FLAGS_PALETTE_ALLOC = 0x08, /* Palette is malloc()'d */ +}; + +/* image_t: gint's native bitmap image format + Images of this format can be created through this header's API but also by + using the fxSDK's built-in image converters with fxconv. */ +typedef struct +{ + /* Color format, one of the IMAGE_* values defined above */ + uint8_t format; + /* Additional flags, a combination of IMAGE_FLAGS_* values */ + uint8_t flags; + /* Number of colors in the palette; this includes alpha for transparent + images, as alpha is always the first entry. + RGB16: 0 + P8: Ranges between 1 and 256 + P4: 16 */ + int16_t color_count; + /* Full width and height, in pixels */ + uint16_t width; + uint16_t height; + /* Byte stride between lines */ + uint32_t stride; + + /* Pixel data in row-major order, left to right. + - RGB16: 2 bytes per entry, each row padded to 4 bytes for alignment. + Each 2-byte value is an RGB565 color. + - P8: 1 signed byte per entry. Each byte is a palette index shifted by + 128 (to access the color, use palette[+128]). + - P4: 4 bits per entry, each row padded to a full byte. Each entry is a + direct palette index between 0 and 15. */ + void *data; + + /* For P8 and P4, color palette. The number of entries allocated in the + array is equal to the color_count attribute. */ + uint16_t *palette; + +} __attribute__((packed, aligned(4))) bopti_image_t; + +#ifdef __cplusplus +} +#endif + +#endif // GINT_IMAGE \ No newline at end of file diff --git a/src/nlohmann/json/LICENSE.MIT b/3rd_party/nlohmann/LICENSE.MIT similarity index 100% rename from src/nlohmann/json/LICENSE.MIT rename to 3rd_party/nlohmann/LICENSE.MIT diff --git a/src/nlohmann/json/json.hpp b/3rd_party/nlohmann/json/json.hpp similarity index 100% rename from src/nlohmann/json/json.hpp rename to 3rd_party/nlohmann/json/json.hpp diff --git a/Makefile b/Makefile index b5d0f3e..24ee99a 100644 --- a/Makefile +++ b/Makefile @@ -3,26 +3,29 @@ BUILD_DIR = build # Source files SOURCES := \ - src/test.cpp -# src/main.cpp \ -# src/game_data.cpp + src/main.cpp \ + src/game_data/game_data.cpp # Assets files ASSETS := \ assets/player-sheets/player_idle_sheet.png \ assets/player-sheets/player_walk_sheet.png \ - assets/tileset/tileset.png + assets/player-sheets/player_run_sheet.png \ + assets/tileset/tileset.png \ + assets/maps/example.json # Output target name OUTPUT := 2D_Engine_Casio_Tool # Compiler and flags CXX = ccache g++ -CXXFLAGS = -Wall -Wextra -std=c++17 -O2 -I. -no-pie +CXXFLAGS = -Wall -Wextra -std=c++17 -g -no-pie +INCLUDE_DIRS = 3rd_party LDFLAGS = -no-pie # Converter flags -FXCONVFLAGS = --cg --toolchain= --arch=x86-64 --outputtarget=elf64-x86-64 +FXCONV_FLAGS = --cg --toolchain= --arch=x86-64 --outputtarget=elf64-x86-64 +FXCONV_CONVERTERS = assets/maps/map_converter.py # Change output location OUTPUT := $(BUILD_DIR)/$(OUTPUT) @@ -63,14 +66,14 @@ $(BUILD_DIR)/%.o: %.cpp $(eval PERCENTAGE := $(shell echo $$(($(CURRENT_FILE)*100/$(TOTAL_FILES))))) @echo "[$(PERCENTAGE)%] $(GREEN)Building CXX object $@$(RESET)" $(Q)mkdir -p $(dir $@) - $(Q)$(CXX) $(CXXFLAGS) -MMD -MP -c $< -o $@ + $(Q)$(CXX) $(CXXFLAGS) $(INCLUDE_DIRS:%=-I%) -MMD -MP -c $< -o $@ # Convert .*.o from .* (png files for example) $(BUILD_DIR)/%.o: % $(eval CURRENT_FILE := $(shell echo $$(($(CURRENT_FILE)+1)))) $(eval PERCENTAGE := $(shell echo $$(($(CURRENT_FILE)*100/$(TOTAL_FILES))))) @echo "[$(PERCENTAGE)%] $(GREEN)Building FXCONV object $@$(RESET)" - $(Q)fxconv $(FXCONVFLAGS) $< -o $@ + $(Q)fxconv $(FXCONV_FLAGS) --converter=$(FXCONV_CONVERTERS) $< -o $@ $(Q)objcopy --add-section .note.GNU-stack=/dev/null $@ # Source files dependencies diff --git a/README.md b/README.md index bc730c1..30a68ca 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,15 @@ This tool is used to make game data for the 2D_Engine_Casio [Gitea](https://gite ## Licences and Credits - This program is open-source : you can redistribute and/or modify it under the term of the **GNU GPLv3**. - Copyright (C) 2025 Ulysse Cura. See [LICENSE](LICENSE) or [gnu.org/licenses/gpl-3.0.html](https://www.gnu.org/licenses/gpl-3.0.html). + Copyright (c) 2025 Ulysse Cura. + See [LICENSE](LICENSE) or [gnu.org/licenses/gpl-3.0.html](https://www.gnu.org/licenses/gpl-3.0.html). -- Files from the gint project are used in directory [gint](gint). +- Files from the gint project are used and modified in directory [gint](gint). [Git](https://git.planet-casio.com/Lephenixnoir/gint) - Folder [src/nlohmann/json](src/nlohmann/json) contains code under **MIT license** : - Copyright (c) 2013-2025 Niels Lohmann. See [LICENSE.MIT](src/nlohmann/json/LICENSE.MIT). + Copyright (c) 2013-2025 Niels Lohmann. + See [LICENSE.MIT](src/nlohmann/json/LICENSE.MIT). [GitHub](https://github.com/nlohmann/json) - Assets are taken from the free pack offered by [Anokolisa](https://anokolisa.itch.io/). diff --git a/assets/maps/dungeon_entry.example b/assets/maps/dungeon_entry.example deleted file mode 100644 index 5ae8e96..0000000 --- a/assets/maps/dungeon_entry.example +++ /dev/null @@ -1,24 +0,0 @@ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,1483,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,1532,0,0,0,794,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,1581,0,904,905,1046,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,2176,2177,2178,2179,2180,2181,2182,0,1543,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,2225,2226,2227,2228,2229,2230,2231,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,1729,2326,2327,2274,2275,2276,2277,2278,2279,2280,2176,2177,2178,2179,2180,2181,2182,0,0,0,0,0,0, -0,0,0,0,2176,2177,2178,2180,2181,1778,2375,2376,0,0,0,0,0,0,0,2225,2226,2227,2228,2229,2230,2231,0,0,0,0,0,0, -0,0,0,0,2225,2226,2227,2229,2230,2231,0,0,0,0,0,0,0,0,0,2274,2275,2276,2277,2278,2279,2280,0,0,0,0,0,0, -0,0,0,0,2274,2275,2276,2278,2279,2280,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0; diff --git a/assets/maps/example.json b/assets/maps/example.json new file mode 100644 index 0000000..6fe0a1c --- /dev/null +++ b/assets/maps/example.json @@ -0,0 +1,92 @@ +{ + "MapWidth": 2, + "MapHeight": 2, + + "BackgroundLayer1": [ + 1,0, + 0,0 + ], + "BackgroundLayer2": [ + 0,2, + 0,0 + ], + "BackgroundLayer3": [ + 0,0, + 3,0 + ], + "Foreground": [ + 0,0, + 0,4 + ], + + "Entities": [ + { + "ID": 2034, + "Components": [ + { + "Type": "TransformComponent", + "x": 128, + "y": 96, + "w": 32, + "h": 48, + "Speed": 0 + }, + { + "Type": "SpriteComponent", + "TextureName": "dungeon_door_sheet" + }, + { + "Type": "AnimationSystem", + "NbFrames": 15, + "ActualFrame": 8, + "FrameDelayMs": 100, + "Play": false, + "Loop": false, + "Reverse": false + }, + { + "Type": "DoorSystem", + "States": [ + { + "Channel": 0, + "State": true + } + ] + } + ] + }, + { + "ID": 542, + "StoreInteraction": true, + "Components": [ + { + "Type": "TransformComponent", + "Bounds": { + "x": 256, + "y": 384, + "w": 48, + "h": 32 + }, + "Speed": 0 + }, + { + "Type": "SpriteComponent", + "TextureName": "lever_sheet" + }, + { + "Type": "AnimationSystem", + "NbFrames": 3, + "ActualFrame": 0, + "FrameDelayMs": 300, + "Play": false, + "Loop": false, + "Reverse": false + }, + { + "Type": "LeverSystem", + "Channel": 0 + } + ] + } + ] +} \ No newline at end of file diff --git a/assets/maps/fxconv-metadata.txt b/assets/maps/fxconv-metadata.txt new file mode 100644 index 0000000..6e290ce --- /dev/null +++ b/assets/maps/fxconv-metadata.txt @@ -0,0 +1,3 @@ +*.json: + custom-type: map + name_regex: (.*)\.json map_\1 \ No newline at end of file diff --git a/assets/maps/map_converter.py b/assets/maps/map_converter.py new file mode 100644 index 0000000..90c80b0 --- /dev/null +++ b/assets/maps/map_converter.py @@ -0,0 +1,53 @@ +import fxconv +from fxconv import u16, u32, ref +import json + +def convert(input, output, params, target): + if params["custom-type"] == "map": + convert_map(input, output, params, target) + return 0 + else: + return 1 + +def convert_map(input, output, params, target): + with open(input, "r") as fp: + map = json.load(fp) + + w = map["MapWidth"] + h = map["MapHeight"] + + background_layer1 = bytes(map["BackgroundLayer1"]) + background_layer2 = bytes(map["BackgroundLayer2"]) + background_layer3 = bytes(map["BackgroundLayer3"]) + foreground = bytes(map["Foreground"]) + + entities = fxconv.Structure() + + for entity in map["Entities"]: + e = fxconv.Structure() + e += u16(entity["ID"]) + e += u32(entity["Components"].size()) + + for component in entity["Components"]: + c = fxconv.Structure() + match component["Type"]: + case "TransformComponent": + c += u32(component["x"]) + c += u32(component["y"]) + c += u32(component["w"]) + c += u32(component["h"]) + c += u32(component["Speed"]) + case _: + raise fxconv.FxconvError(f"unknown component type {component["Type"]}") + e += ref(c) + + o = fxconv.ObjectData() + o += u32(w) + u32(h) + o += ref(background_layer1) + o += ref(background_layer2) + o += ref(background_layer3) + o += ref(foreground) + o += u32(map["Entities"].size()) + o += ref(entities) + + fxconv.elf(o, output, params["name"], **target) diff --git a/assets/maps/tiled-python-extension/install_extension.sh b/assets/maps/tiled-python-extension/install_extension.sh new file mode 100755 index 0000000..a1d130a --- /dev/null +++ b/assets/maps/tiled-python-extension/install_extension.sh @@ -0,0 +1,10 @@ +#!/usr/bin/bash + +echo "Creating \"~/.tiled\" directory" +mkdir -p $HOME/.tiled/ + +echo "Copying extension to tiled directory" +cp "json_export_tool.py" "$HOME/.tiled/" + +echo "" +echo "Don't forget to activate python in tiled !" \ No newline at end of file diff --git a/assets/maps/tiled-python-extension/example.py b/assets/maps/tiled-python-extension/json_export_tool.py similarity index 74% rename from assets/maps/tiled-python-extension/example.py rename to assets/maps/tiled-python-extension/json_export_tool.py index bbc1c67..4dfb4a7 100644 --- a/assets/maps/tiled-python-extension/example.py +++ b/assets/maps/tiled-python-extension/json_export_tool.py @@ -1,13 +1,14 @@ from tiled import * +import json -class Example(Plugin): +class Json_Export_Tool(Plugin): @classmethod def nameFilter(cls): - return "Example files (*.example)" + return "Json files (*.json)" @classmethod def shortName(cls): - return "example" + return "json" @classmethod def write(cls, tileMap, fileName): @@ -28,6 +29,11 @@ class Example(Plugin): else: line += ',' print(line, file=fileHandle) - - return True + + def write(cls, tileMap, fileName): + map = {} + with open(fileName, 'w') as fileHandle: + for i in tileMap.layerCount(): + tileLayer = tileLayerAt(tileMap, i) + print("caca", file=fileHandle) diff --git a/assets/player-sheets/PenzillaDesign_StandardLicense.pdf b/assets/player-sheets/PenzillaDesign_StandardLicense.pdf new file mode 100644 index 0000000000000000000000000000000000000000..afade334c2e397e788997483fc03fce65763a61a GIT binary patch literal 88141 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 I>hHz{05XQTjsO4v literal 0 HcmV?d00001 diff --git a/assets/player-sheets/player_attack_sheet.png b/assets/player-sheets/player_attack_sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..a4115ce7b00d6efcda741f52b1d86df3dcb47ea3 GIT binary patch literal 3120 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 KMNUMnLSTXxLiAMt literal 0 HcmV?d00001 diff --git a/assets/player-sheets/player_death_sheet.png b/assets/player-sheets/player_death_sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..e8ebc90d8de617aa757a35b610b4b63e2a3673ec GIT binary patch literal 1552 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 diff --git a/assets/player-sheets/player_run_sheet.png b/assets/player-sheets/player_run_sheet.png new file mode 100644 index 0000000000000000000000000000000000000000..c57eddabbbc1dd444465da867cd3b9b46a3b1746 GIT binary patch literal 1275 zcmVPx(wMj%lRCt{2ok5P`Fc3w{qmf#W6=>MAnnN@P$Wb`Q9D}290Qwx+Bc)fN#mciF z_Ea3(F@wua-1ViFI*|6S_?0UTacBS*i^XEGSS%Kc#bU8o-$BClhLkdGBs0`uy|umU z>zF}*UT$slm{{qwbpAp(hqu75>N9=Wwrf6&>SkT_8q|oc)UiF1anA0YaCe2e|h|$DFDd>F?ZBKGQ^1GenLyUnPA4G1un!0lkog-bjep2(K+!jv4M4^LfMvZ0el)i0 zN0N{&1j&$q%>SVx`3J27P^RbZ3b_H~sK8STU=m3Cn+ca90hxcf{6iN4=>XK?j|l*= zm308Hn187XDFA~{g8O^C|F-P_q6Ih?g;xLlTLlpJ_@6raQ28q{|A74##6S2hz*7Ol z)$<)d;Q!r~yZ>|hm#V1(u-Jo7^(?&Y6YsvylB`N0_GkVRS~~xr8Gx^c)m z-odGD1~CxFGx9%oS4w~H08HQy!2F#mfxoi=gggb6DgkZnn?6L~bsw0%iTp?Hr}Ah1 z0N;Us&19N0PPd~JL&rM;9#sx7kv!obT8^sSOAa;s?A@0;)(!8eGtTWD$Y5z#r}u&_N8e! z^B=UeNd6)6{$Bvqh*}G-9?C$_#rtXlA77tRJ)NZB_tzmoLAYc)2m~9)E&%}k{Q9jc zCe>{qA%xRkN=dT%%oqq}96;qgNB);v3qlAfr4&L4kW%WtVE&_6C)*DC#~_FGcCgIT zG6*F+)`IKyhymE*mQ(=10N*EFQh!T4fbR7Q$}hv16MsNCppMzxrWVSnG*0jB(; z6#y`*P=5xHMgj=i-^CI-7+V1#AAGnoa})rJKTbmO1T@b=raz92LJt0eLPXgI2JcZ0 zQun`uKj4{=?{A##y52Awoag}Z0^o=vnSV$Dpd5%Ef9>l^1R{UiR5%5H?}I)mj^9-P l68Ar-lMcER8u*74fWKhk@=mR4AkY8+002ovPDHLkV1l9xS?&M; literal 0 HcmV?d00001 diff --git a/assets/player-sheets/player_walk_sheet.png b/assets/player-sheets/player_walk_sheet.png index 2314abd3e9259f8f43cc6c5cc204562098ddebb9..1af84b7fc18593381b3608e5eda402ff149c0505 100644 GIT binary patch delta 938 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 diff --git a/assets/Terms.pdf b/assets/tileset/Terms.pdf similarity index 100% rename from assets/Terms.pdf rename to assets/tileset/Terms.pdf diff --git a/gint/config.h b/gint/config.h deleted file mode 100644 index e89114a..0000000 --- a/gint/config.h +++ /dev/null @@ -1,83 +0,0 @@ -//--- -// config - Compile-time generate configuration -//--- - -#ifndef GINT_CONFIG -#define GINT_CONFIG - -/* GINT_VERSION: Latest tag and number of additional commits - "2.1.0" = Release 2.1.0 - "2.1.1-5" = 5 commits after release 2.1.1 */ -#define GINT_VERSION "2.11.0" - -/* GINT_HASH: Commit hash with 7 digits - 0x03f7c0a0 = Commit 3f7c0a0 */ -#define GINT_HASH 0xbadbd0f - -/* GINT_HW_{FX,CG}: Identifies the type of hardware running the program. */ -#if defined(FX9860G) -# define GINT_HW_FX 1 -# define GINT_HW_CG 0 -# define GINT_HW_CP 0 -# define GINT_HW_SWITCH(FX,CG,CP) (FX) -#elif defined(FXCG50) -# define GINT_HW_FX 0 -# define GINT_HW_CG 1 -# define GINT_HW_CP 0 -# define GINT_HW_SWITCH(FX,CG,CP) (CG) -#elif defined(FXCP) -# define GINT_HW_FX 0 -# define GINT_HW_CG 0 -# define GINT_HW_CP 1 -# define GINT_HW_SWITCH(FX,CG,CP) (CP) -#endif - -/* Shorthand to simplify definitions below. Won't be needed for long. */ -#if defined(FX9860G_G3A) -# define GINT_FX9860G_G3A 1 -#else -# define GINT_FX9860G_G3A 0 -#endif - -/* GINT_OS_{FX,CG}: Identifies the type of OS API we're assuming. Currently I - see no reason this would be different from hardware, but who knows. */ -#define GINT_OS_FX GINT_HW_FX -#define GINT_OS_CG GINT_HW_CG -#define GINT_OS_CP GINT_HW_CP -#define GINT_OS_SWITCH GINT_HW_SWITCH - -/* GINT_NO_OS_STACK: Disables using a chunk of the OS stack as a heap. The top - section covering 355/512 ko is otherwise used. (fx-CG 50) */ -/* #undef GINT_NO_OS_STACK */ - -/* GINT_USER_VRAM: Selects whether to store VRAMs in the user stack or in the - OS stack. Deprecated, now controlled by GINT_NO_OS_STACK. (fx-CG 50) */ -/* #undef GINT_USER_VRAM */ - -#ifdef GINT_USER_VRAM -# define GINT_NO_OS_STACK -#endif - -/* GINT_STATIC_GRAY: Selects whether additional gray VRAMs are allocated - statically or in the system heap (fx-9860G) */ -/* #undef GINT_STATIC_GRAY */ - -/* GINT_KMALLOC_DEBUG: Selects whether kmalloc debug functions are enabled - (these are mainly data structure integrity checks and information that make - sense for a developer). This is independent from statistics, which can be - enabled or disabled at runtime. */ -/* #undef GINT_KMALLOC_DEBUG */ - -/* GINT_USB_DEBUG: Selects whether USB debug functions are enabled */ -/* #undef GINT_USB_DEBUG */ - -/* GINT_RENDER_DMODE: Selects whether the dmode override is available on - rendering functions. */ -#define GINT_RENDER_DMODE (GINT_HW_FX || GINT_FX9860G_G3A) - -/* GINT_RENDER_{MONO,RGB}: Enable the mono/rgb rendering API. - Currently these are exclusive. */ -#define GINT_RENDER_MONO (GINT_HW_FX || GINT_FX9860G_G3A) -#define GINT_RENDER_RGB ((GINT_HW_CG || GINT_HW_CP) && !GINT_FX9860G_G3A) - -#endif /* GINT_CONFIG */ diff --git a/gint/defs/attributes.h b/gint/defs/attributes.h deleted file mode 100644 index 9470f0a..0000000 --- a/gint/defs/attributes.h +++ /dev/null @@ -1,50 +0,0 @@ -//--- -// gint:defs:attributes - Macros for compiler-specific attributes -//--- - -#ifndef GINT_DEFS_ATTRIBUTES -#define GINT_DEFS_ATTRIBUTES - -/* Objects from specific sections */ -#define GSECTION(x) __attribute__((section(x))) -/* Objects from the gint's uninitialized BSS section */ -#define GBSS __attribute__((section(".gint.bss"))) -/* Additional sections that are only needed on SH3 */ -#define GRODATA3 __attribute__((section(".gint.rodata.sh3"))) -#define GDATA3 __attribute__((section(".gint.data.sh3"))) -#define GBSS3 __attribute__((section(".gint.bss.sh3"))) -/* Objects for the ILRAM, XRAM and YRAM regions */ -#define GILRAM __attribute__((section(".ilram"))) -#define GXRAM __attribute__((section(".xyram"))) -#define GYRAM __attribute__((section(".xyram"))) - -/* Unused parameters or variables */ -#define GUNUSED __attribute__((unused)) -/* Functions that *must* be inlined */ -#define GINLINE __attribute__((always_inline)) inline - -/* Aligned variables */ -#define GALIGNED(x) __attribute__((aligned(x))) -/* Packed structures. I require explicit alignment because if it's unspecified, - GCC cannot optimize access size, and reads to memory-mapped I/O with invalid - access sizes silently fail - honestly you don't want this to happen */ -#define GPACKED(x) __attribute__((packed, aligned(x))) -/* Packed enumerations */ -#define GPACKEDENUM __attribute__((packed)) -/* Transparent unions */ -#define GTRANSPARENT __attribute__((transparent_union)) - -/* Functions and globals that are visible through whole-program optimization */ -#define GVISIBLE __attribute__((externally_visible)) - -/* Weak symbols */ -#define GWEAK __attribute__((weak)) - -/* Constructors */ -#define GCONSTRUCTOR __attribute__((constructor)) -#define GDESTRUCTOR __attribute__((destructor)) - -/* Functions that do not return */ -#define GNORETURN __attribute__((noreturn)) - -#endif /* GINT_DEFS_ATTRIBUTES */ diff --git a/gint/defs/types.h b/gint/defs/types.h deleted file mode 100644 index df99c45..0000000 --- a/gint/defs/types.h +++ /dev/null @@ -1,68 +0,0 @@ -//--- -// gint:defs:types - Type definitions -//--- - -#ifndef GINT_DEFS_TYPES -#define GINT_DEFS_TYPES - -#include "attributes.h" - -/* For size_t, mainly */ -#include -/* For all fixed-width integer types */ -#include -/* For human-readable boolean types */ -#include -/* Common system types: ssize_t, off_t, etc. */ -#include -/* For va_list */ -#include - -/* Fixed-width types for bit fields are quite meaningless */ -typedef unsigned int uint; - -//--- -// Short types -//--- - -typedef unsigned int uint; -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; -typedef int8_t i8; -typedef int16_t i16; -typedef int32_t i32; -typedef int64_t i64; - -//--- -// Structure elements -//---- - -/* Giving a type to padding bytes is misguiding, let's hide it in a macro */ -#define pad_nam2(c) _ ## c -#define pad_name(c) pad_nam2(c) -#define pad(bytes) uint8_t pad_name(__COUNTER__)[bytes] - -/* byte_union() - union between an uint8_t 'byte' element and a bit field */ -#define byte_union(name, fields) \ - union { \ - uint8_t byte; \ - struct { fields } GPACKED(1); \ - } GPACKED(1) name - -/* word_union() - union between an uint16_t 'word' element and a bit field */ -#define word_union(name, fields) \ - union { \ - uint16_t word; \ - struct { fields } GPACKED(2); \ - } GPACKED(2) name - -/* lword_union() - union between an uint32_t 'lword' element and a bit field */ -#define lword_union(name, fields) \ - union { \ - uint32_t lword; \ - struct { fields } GPACKED(4); \ - } GPACKED(4) name - -#endif /* GINT_DEFS_TYPES */ diff --git a/gint/display-cg.h b/gint/display-cg.h deleted file mode 100644 index 08b752b..0000000 --- a/gint/display-cg.h +++ /dev/null @@ -1,143 +0,0 @@ -//--- -// gint:display-cg - fx-CG 50 rendering functions -// -// This module covers rendering functions specific to the fx-CG 50. In addition -// to triple-buffering management, this mainly includes image manipulation -// tools as well as the very versatile dimage_effect() and dsubimage_effect() -// functions that support high-performance image rendering with a number of -// geometric and color effects. -// -// The fx-CG OS restricts the display to a 384x216 rectangle rougly around the -// center, leaving margins on three sides. However, gint configures the display -// to use the full 396x224 surface! -//--- - -#ifndef GINT_DISPLAY_CG -#define GINT_DISPLAY_CG - -#ifdef __cplusplus -extern "C" { -#endif - -#include "defs/types.h" -#include "image.h" - -/* Dimensions of the VRAM */ -#if GINT_HW_CG -#define DWIDTH 396 -#define DHEIGHT 224 -#elif GINT_HW_CP -#define DWIDTH 320 -#define DHEIGHT 528 -#endif - -/* gint VRAM address. This value must always point to a 32-aligned buffer of - size 177408. Any function can use it freely to perform rendering or store - data when not drawing. Triple buffering is already implemented in gint, see - the dvram() function below. - - In this module, colors are in the 16-bit big-endian R5G6B5 format, as it is - the format used by the display controller. */ -extern uint16_t *gint_vram; - -/* Provide a platform-agnostic definition of color_t. - Some functions also support transparency, in which case they take an [int] - as argument and recognize negative values as transparent. */ -typedef uint16_t color_t; - -enum { - /* Compatibility with fx9860g color names */ - C_WHITE = 0xffff, - C_LIGHT = 0xad55, - C_DARK = 0x528a, - C_BLACK = 0x0000, - - /* Other colors */ - C_RED = 0xf800, - C_GREEN = 0x07e0, - C_BLUE = 0x001f, - - C_NONE = -1, - C_INVERT = -2, -}; - -/* RGB color maker. Takes three channels of value 0..31 each (the extra bit of - green is not used). */ -#define C_RGB(r,g,b) (((r) << 11) | ((g) << 6) | (b)) - -/* See for the details on image manipulation. */ -typedef image_t bopti_image_t; - - -//--- -// Video RAM management -//--- - -/* dsetvram(): Control video RAM address and triple buffering - - Normal rendering under gint uses double-buffering: there is one image - displayed on the screen and one in memory, in a region called the video RAM - (VRAM). The application draws frames in the VRAM then sends them to the - screen only when they are finished, using dupdate(). - - On fx-CG, sending frames with dupdate() is a common bottleneck because it - takes about 11 ms. Fortunately, while the DMA is sending the frame to the - display, the CPU is available to do work in parallel. This function sets up - triple buffering (ie. a second VRAM) so that the CPU can start working on - the next frame while the DMA is sending the current one. - - However, experience shows minimal performance improvements, because writing - to main RAM does not parallelize with DMA transfers. Since gint 2.8, this - is no longer the default, and the memory for the extra VRAM is instead - available via malloc(). - - VRAMs must be contiguous, 32-aligned, (2*396*224)-byte buffers with 32 bytes - of extra data on each side (ie. 32 bytes into a 32-aligned buffer of size - 177472). - - @main Main VRAM area, used alone if [secondary] is NULL - @secondary Additional VRAM area, enables triple buffering if non-NULL */ -// TODO: In gint 3 the triple buffering mechanism will be removed. Applications -// that want to change VRAMs in-between every frame will be able to do so by -// talking directly to the video interface to set VRAM, and wrapping dupdate. -// Basically it will just no longer be handled by gint itself. -void dsetvram(uint16_t *main, uint16_t *secondary); - -/* dgetvram() - Get VRAM addresses - Returns the VRAM buffer addresses used to render on fx-CG 50. */ -void dgetvram(uint16_t **main, uint16_t **secondary); - - -//--- -// VRAM backup -// On the fx-CP gint backs up the VRAM when loading and restores it when -// leaving. While this is a transparent mechanism, the following parts of the -// implementation are exposed at the internal API level. -//--- - -/* Encode the VRAM contents between [in_start] and [in_end] at [output]. While - [*in_end] is excluded from the encoding, it will be modified temporarily to - serve as bounds check, so it must not be accessed asynchronously during the - encoding. The size of the output is not known but is at most the distance - between in_end and in_start in bytes. Setting output = in_start to compress - in-place is supported. Returns the end pointer after encoding. */ -uint8_t *gint_vrambackup_encode( - uint8_t *output, uint16_t *in_start, uint16_t *in_end); - -/* Predefine palette based on the GUI at the Hollyhock loading screen. Contains - 109 entries plus a 110th dummy entry used internally as bounds check. */ -extern uint16_t gint_vrambackup_palette[110]; - -/* Get the pointer to the encoded VRAM backup created at load time. If [size] - is not NULL, sets the size in [*size]. The pointer is heap allocated and - remains owned by gint. */ -void *gint_vrambackup_get(int *size); - -/* Decode the load-time VRAM backup back to VRAM. */ -void gint_vrambackup_show(void); - -#ifdef __cplusplus -} -#endif - -#endif /* GINT_DISPLAY_CG */ diff --git a/gint/image.h b/gint/image.h deleted file mode 100644 index dcd0657..0000000 --- a/gint/image.h +++ /dev/null @@ -1,846 +0,0 @@ -//--- -// gint:image - Image manipulation and rendering -// -// Note: this module is currently only available on fx-CG. -// -// This header provides image manipulation functions. This mainly consists of a -// reference-based image format, various access and modification functions, and -// a number of high-performance transformations and rendering effects. If you -// find yourself limited by rendering time, note that RAM writing speed is -// often the bottleneck, and image rendering is much faster in Azur (which is -// what the renderer was initially designed for). -// -// This module supports 3 bit depths: full-color 16-bit (RGB565), indexed 8-bit -// (P8) and indexed 4-bit (P4). All three have an "alpha" variation where one -// color is treated as transparent, leading to 6 total formats. -// -// The image renderers support so-called *dynamic effects*, which are image -// transformations performed on-the-fly while rendering, without generating an -// intermediate image. They comprise straightforward transformations that -// achieve similar performance to straight rendering and can be combined to -// some extent, which makes them reliable whenever applicable. -// -// For images of the RGB16 and P8 bit depths, the module supports a rich API -// with image subsurfaces and a fairly large sets of geometric and color -// transforms, including some in-place. P4 is not supported in most of these -// functions because the dense bit packing is both impractical and slower for -// these applications. -//--- - -#ifndef GINT_IMAGE -#define GINT_IMAGE - -#ifdef __cplusplus -extern "C" { -#endif - -#include "config.h" -#include "defs/attributes.h" -#include - -struct dwindow; - -//--- -// Image structures -//--- - -/* Image formats. Note that transparency really only indicates the default - rendering method, as a transparent background can always be added or removed - by a dynamic effect on any image. */ -enum { - IMAGE_RGB565 = 0, /* RGB565 without alpha */ - IMAGE_RGB565A = 1, /* RGB565 with one transparent color */ - IMAGE_P8_RGB565 = 4, /* 8-bit palette, all opaque colors */ - IMAGE_P8_RGB565A = 5, /* 8-bit with one transparent color */ - IMAGE_P4_RGB565 = 6, /* 4-bit palette, all opaque colors */ - IMAGE_P4_RGB565A = 3, /* 4-bit with one transparent color */ - - IMAGE_DEPRECATED_P8 = 2, -}; - -/* Quick macros to compare formats by storage size */ -#define IMAGE_IS_RGB16(format) \ - ((format) == IMAGE_RGB565 || (format) == IMAGE_RGB565A) -#define IMAGE_IS_P8(format) \ - ((format) == IMAGE_P8_RGB565 || (format) == IMAGE_P8_RGB565A) -#define IMAGE_IS_P4(format) \ - ((format) == IMAGE_P4_RGB565 || (format) == IMAGE_P4_RGB565A) -/* Check whether image format has an alpha color */ -#define IMAGE_IS_ALPHA(format) \ - ((format) == IMAGE_RGB565A || \ - (format) == IMAGE_P8_RGB565A || \ - (format) == IMAGE_P4_RGB565A) -/* Check whether image format uses a palette */ -#define IMAGE_IS_INDEXED(format) \ - (IMAGE_IS_P8(format) || IMAGE_IS_P4(format)) - -/* Image flags. These are used for memory management, mostly. */ -enum { - IMAGE_FLAGS_DATA_RO = 0x01, /* Data is read-only */ - IMAGE_FLAGS_PALETTE_RO = 0x02, /* Palette is read-only */ - IMAGE_FLAGS_DATA_ALLOC = 0x04, /* Data is malloc()'d */ - IMAGE_FLAGS_PALETTE_ALLOC = 0x08, /* Palette is malloc()'d */ -}; - -/* image_t: gint's native bitmap image format - Images of this format can be created through this header's API but also by - using the fxSDK's built-in image converters with fxconv. */ -typedef struct -{ - /* Color format, one of the IMAGE_* values defined above */ - uint8_t format; - /* Additional flags, a combination of IMAGE_FLAGS_* values */ - uint8_t flags; - /* Number of colors in the palette; this includes alpha for transparent - images, as alpha is always the first entry. - RGB16: 0 - P8: Ranges between 1 and 256 - P4: 16 */ - int16_t color_count; - /* Full width and height, in pixels */ - uint16_t width; - uint16_t height; - /* Byte stride between lines */ - int stride; - - /* Pixel data in row-major order, left to right. - - RGB16: 2 bytes per entry, each row padded to 4 bytes for alignment. - Each 2-byte value is an RGB565 color. - - P8: 1 signed byte per entry. Each byte is a palette index shifted by - 128 (to access the color, use palette[+128]). - - P4: 4 bits per entry, each row padded to a full byte. Each entry is a - direct palette index between 0 and 15. */ - void *data; - - /* For P8 and P4, color palette. The number of entries allocated in the - array is equal to the color_count attribute. */ - uint16_t *palette; - -} GPACKED(4) image_t; - -/* Dynamic effects: these transformations can be applied on images while - rendering. Not all effects can be combined; unless specified otherwise: - - HFLIP and VFLIP can both be added regardless of any other effect - - At most one color effect can be applied */ -enum { - /* Value 0x01 is reserved, because it is DIMAGE_NOCLIP, which although - part of the old API still needs to be supported. */ - - /* [Any]: Skip clipping the command against the source image */ - IMAGE_NOCLIP_INPUT = 0x04, - /* [Any]: Skip clipping the command against the output VRAM */ - IMAGE_NOCLIP_OUTPUT = 0x08, - /* [Any]: Skip clipping both */ - IMAGE_NOCLIP = IMAGE_NOCLIP_INPUT | IMAGE_NOCLIP_OUTPUT, - - // Geometric effects. These values should remain at exactly bit 8 and - // following, or change gint_image_mkcmd() along with it. - - /* [Any]: Flip image vertically */ - IMAGE_VFLIP = 0x0100, - /* [Any]: Flip image horizontally */ - IMAGE_HFLIP = 0x0200, - - // Color effects - - /* [RGB565, P8_RGB565, P4_RGB565]: Make a color transparent - Adds one argument: - * Color to clear (RGB16: 16-bit value; P8/P4: palette index) */ - IMAGE_CLEARBG = 0x10, - /* [RGB565, P8_RGB565, P4_RGB565]: Turn a color into another - Adds two arguments: - * Color to replace (RGB16: 16-bit value; P8/P4: palette index) - * Replacement color (16-bit value) */ - IMAGE_SWAPCOLOR = 0x20, - /* [RGB565A, P8_RGB565A, P4_RGB565A]: Add a background - Adds one argument: - * Background color (16-bit value) */ - IMAGE_ADDBG = 0x40, - /* [RGB565A, P8_RGB565A, P4_RGB565A]: Dye all non-transparent pixels - Adds one argument: - * Dye color (16-bit value) */ - IMAGE_DYE = 0x80, -}; - -//--- -// Image creation and destruction -//--- - -#if GINT_RENDER_RGB - -/* image_alloc(): Create a new (uninitialized) image - - This function allocates a new image of the specified dimensions and format. - It always allocates a new data array; if you need to reuse a data array, use - the lower-level image_create() or image_create_sub(). - - The first parameters [width] and [height] specify the dimensions of the new - image in pixels. The [format] should be one of the IMAGE_* formats, for - example IMAGE_RGB565A or IMAGE_P4_RGB565. - - This function does not specify or initialize the palette of the new image; - use image_set_palette(), image_alloc_palette() or image_copy_palette() - after calling this function. - - The returned image structure must be freed with image_free() after use. - - @width Width of the new image - @height Height of the new image - @format Pixel format; one of the IMAGE_* formats defined above */ -image_t *image_alloc(int width, int height, int format); - -/* image_set_palette(): Specify an external palette for an image - - This function sets the image's palette to the provided address. The number - of entries allocated must be specified in size. It is also the caller's - responsibility to ensure that the palette covers all the indices used in the - image data. - - The old palette, if owned by the image, is freed. If [owns=true] the - palette's ownership is given to the image, otherwise it is kept external. */ -void image_set_palette(image_t *img, uint16_t *palette, int size, bool owns); - -/* image_alloc_palette(): Allocate a new palette for an image - - This function allocates a new palette for an image. The number of entries is - specified in size; for P8 it can vary between 1 and 256, for P4 it is - ignored (P4 images always have 16 colors). - - The old palette, if owned by the image, is freed. The entries of the new - palette are all initialized to 0. If size is -1, the format's default - palette size is used. Returns true on success. */ -bool image_alloc_palette(image_t *img, int size); - -/* image_copy_palette(): Copy another image's palette - - This function allocates a new palette for an image, and initializes it with - a copy of another image's palette. For P8 the palette can be resized by - specifying a value other than -1 as the size; by default, the source image's - palette size is used (within the limits of the new format). Retuns true on - success. */ -bool image_copy_palette(image_t const *src, image_t *dst, int size); - -/* image_create(): Create a bare image with no data/palette - - This function allocates a new image structure but without data or palette. - The [data] and [palette] members are NULL, [color_count] and [stride] are 0. - - This function is useful to create images that reuse externally-provided - information. It is intended that the user of this function sets the [data] - and [stride] fields themselves, along with the IMAGE_FLAGS_DATA_ALLOC flag - if the image should own its data. - - The [palette] and [color_count] members can be set with image_set_palette(), - image_alloc_palette(), image_copy_palette(), or manually. - - The returned image structure must be freed with image_free() after use. */ -image_t *image_create(int width, int height, int format); - -/* image_create_vram(): Create a reference to gint_vram - - This function creates a new RGB565 image that references gint_vram. Using - this image as target for transformation functions can effectively render - transformed images to VRAM. - - The value of gint_vram is captured when this function is called, and does - not update after dupdate() when triple-buffering is used. The user should - account for this option. (Using this function twice then replacing one of - the [data] pointers is allowed.) - - The VRAM image owns no data but it does own its own structure so it must - still be freed with image_free() after use. */ -image_t *image_create_vram(void); - -/* image_free(): Free and image and the data it owns - - This function frees the provided image structure and the data that it owns. - Images converted by fxconv should not be freed; nonetheless, this functions - distinguishes them and should work. Images are not expected to be created on - the stack. - - If the image has the IMAGE_FLAGS_DATA_ALLOC flag, the data pointer is also - freed. Similarly, the image has the IMAGE_FLAGS_PALETTE_ALLOC flag, the - palette is freed. Make sure to not free images when references to them still - exist, as this could cause the reference's pointers to become dangling. */ -void image_free(image_t *img); - -//--- -// Basic image access and information -//--- - -/* image_valid(): Check if an image is valid - An image is considered valid if it has a valid profile, a non-NULL data - pointer, and for palette formats a valid palette pointer. */ -bool image_valid(image_t const *img); - -/* image_alpha(): Get the alpha value for an image format - - This function returns the alpha value for any specific image format: - * RGB16: 0x0001 - * P8: -128 (0x80) - * P4: 0 - For non-transparent formats, it returns a value that is different from all - valid pixel values of the format, which means it is always safe to compare a - pixel value to the image_alpha() of the format. */ -int image_alpha(int format); - -/* image_get_pixel(): Read a pixel from the data array - - This function reads a pixel from the image's data array at position (x,y). - It returns the pixel's value, which is either a full-color value (RGB16) or - a possibly-negative palette index (P8/P4). See the description of the [data] - field of image_t for more details. The value of the pixel can be decoded - into a 16-bit color either manually or by using the image_decode_pixel() - function. - - Note that reading large amounts of image data with this function will be - slow; if you need reasonable performance, consider iterating on the data - array manually. */ -int image_get_pixel(image_t const *img, int x, int y); - -/* image_decode_pixel(): Decode a pixel value - - This function decodes a pixel's value obtained from the data array (for - instance with image_get_pixel()). For RGB16 formats this does nothing, but - for palette formats this accesses the palette at a suitable position. - - Note that reading large amounts of data with this function will be slow; if - you need reasonable performance, consider inlining the format-specific - method or iterating on the data array manually. */ -int image_decode_pixel(image_t const *img, int pixel); - -/* image_data_size(): Compute the size of the [data] array - This function returns the size of the data array, in bytes. This can be used - to duplicate it. Note that for sub-images this is a subsection of another - image's data array, and might be much larger than the sub-image. */ -int image_data_size(image_t const *img); - -//--- -// Basic image modifications -//--- - -/* image_set_pixel(): Set a pixel in the data array - - This function writes a pixel into the image's data array at position (x,y). - The pixel value must be of the proper format, as specified in the definition - of the [data] field of image_t. - - Formats: RGB16, P8, P4 */ -void image_set_pixel(image_t const *img, int x, int y, int value); - -/* image_copy(): Convert and copy an image - - This function copies an image into another image while converting certain - formats. Unlike transforms, this function does clip, so there are no - conditions on the size of the target. - - If [copy_alpha] is true, transparent pixels are copied verbatim, which - effectively replaces the top-left corner of [dst] with [src]. If it's false, - transparent pixels of [src] are skipped, effectively rendering [src] over - the top-left corner of [src]. - - This function converts between all formats except from RGB16 to P8/P4, since - this requires generating a palette (which is a complex endeavour). - Conversions from P8/P4 to RGB16 simply decode the palette. Conversions - between P8/P4 preserve the contents but renumber the palette entries. From - P4 to P8, the image is always preserved. From P8 to P4, the image is only - preserved if it has less than 16 colors (this is intended to allow P4 images - to be converted to P8 for edition by this library, and then back to P4). The - following table summarizes the conversions: - - Source format → RGB16 P8 P4 - Target format ↓ +-----------+----------------+------------------+ - RGB16 | Copy Decode palette Decode palette | - P8 | - Copy Enlarge palette | - P4 | - Narrow palette Copy | - +-----------+----------------+------------------+ - - Note that conversions to RGB16 are not lossless because RGB565, P8 and P4 - can represent any color; if a color equal to image_alpha(IMAGE_RGB565A) is - found during conversion, this function transforms it slightly to look - similar instead of erroneously generating a transparent pixel. - - Formats: RGB16 → RGB16, P8 → Anything, P4 → Anything - Size requirement: none (clipping is performed) - Supports in-place: No (useless) */ -void image_copy(image_t const *src, image_t *dst, bool copy_alpha); - -/* image_copy_alloc(): Convert and copy into a new image - This function is similar to image_copy(), but it allocates a target image of - the desired format before copying. */ -image_t *image_copy_alloc(image_t const *src, int new_format); - -/* image_fill(): Fill an image with a single pixel value */ -void image_fill(image_t *img, int value); - -/* image_clear(): Fill a transparent image with its transparent value */ -void image_clear(image_t *img); - -//--- -// Sub-image extraction -//--- - -/* image_sub(): Build a reference to a sub-image - - This function is used to create references to sub-images of RGB16 and P8 - images. The [data] pointer of the sub-image points somewhere within the data - array of the source, and its [palette] pointer is identical to the source's. - - The last parameter is a pointer to a preallocated image_t structure (usually - on the stack) that gets filled with the data. Doing this instead of - allocating a new object with malloc() means that there is no need to - image_free() the sub-image, and thus it can be used inline: - - image_t tmp; - image_hflip(src, image_sub(dst, x, y, w, h, &tmp)); - - A preprocessor macro is used to make the last parameter optional. If it's - not specified, a pointer to a static image_t will be returned instead. This - is useful in inline calls as shown above, which then simplify to: - - image_hflip(src, image_sub(dst, x, y, w, h)); - - However, another call to image_sub() or image_at() will override the - sub-image, so you should only use this in such temporary settings. If you - need multiple image_sub() or image_at() calls in the same statement, only - one can use the short form. - - If the requested rectangle does not intersect the source, the sub-image will - be of dimension 0x0. If the image format does not support sub-images (P4), - the sub-image will test invalid with image_valid(). */ -image_t *image_sub(image_t const *src, int x, int y, int w, int h, - image_t *dst); - -/* Make the last parameter optional */ -#define image_sub1(src, x, y, w, h, dst, ...) image_sub(src, x, y, w, h, dst) -#define image_sub(...) image_sub1(__VA_ARGS__, NULL) - -/* image_at(): Build a reference to a position within a sub-image */ -#define image_at(img, x, y) image_sub(img, x, y, -1, -1) - -//--- -// Geometric image transforms -// -// All geometric transforms render to position (0,0) of the target image and -// fail if the target image is not large enough to hold the transformed result -// (unlike the rendering functions which render only the visible portion). -// -// To render at position (x,y) of the target image, use img_at(). For instance: -// image_hflip(src, image_at(dst, x, y)); -// -// Each transform function has an [_alloc] variant which does the same -// transform but allocates the target image on the fly and returns it. Remember -// that allocation can fail, so you need to check whether the returned image is -// valid. -// -// (You can still pass invalid images to transform functions. The invalid image -// will be ignored or returned unchanged, so you can chain calls and check for -// validity at the end of the chain.) -// -// Some functions support in-place transforms. This means they can be called -// with the source as destination, and will transform the image without needing -// new memory. For instance, image_hflip(src, src) flips in-place and replaces -// src with a flipped version of itself. -// -// (However, it is not possible to transform in-place if the source and -// destination intersect in non-trivial ways. The result will be incorrect.) -// -// When transforming to a new image, transparent pixels are ignored, so if the -// destination already has some data, it will not be erased automatically. Use -// image_clear() beforehand to achieve that effect. This allows alpha blending -// while transforming, which is especially useful on the VRAM. -//--- - -/* image_hflip(): Flip horizontally - Formats: RGB16, P8 - Size requirement: destination at least as large as source (no clipping) - Supports in-place: Yes */ -void image_hflip(image_t const *src, image_t *dst, bool copy_alpha); -image_t *image_hflip_alloc(image_t const *src); - -/* image_vflip(): Flip vertically - Formats: RGB16, P8 - Size requirement: destination at least as large as source (no clipping) - Supports in-place: Yes */ -void image_vflip(image_t const *src, image_t *dst, bool copy_alpha); -image_t *image_vflip_alloc(image_t const *src); - -/* image_linear(): Linear transformation - - This function implements a generic linear transformation. This is a powerful - function that can perform any combination of rotation, mirroring and scaling - with nearest-neighbor sampling. - - The [image_linear_map] structure defines the settings for the transform. - Users familiar with linear algebra might want to use it directly, but they - are most conveniently generated with the rotation and scaling functions - listed below. - - Note: Currently the structure for the transform is modified by the - operation and cannot be reused. - - The image_linear_alloc() variant allocates a new image in addition to - performing the transform. The image is created with size (map->dst_w, - map->dst_h) which is always a reasonable default. If a target image of - smaller size is supplied to image_linear(), clipping is performed; only the - top-left corner of the full output is actually rendered. - - Formats: RGB16, P8 - Size requirement: none (clipping is performed) - Supports in-place: No */ - -struct image_linear_map { - /* Dimensions of the source and destination */ - int src_w, src_h, dst_w, dst_h; - /* Input and output stride in bytes */ - int src_stride, dst_stride; - - /* The following parameters define the linear transformation as a mapping - from coordinates in the destination image (x and y) into coordinates in - the source image (u and v). - - (u, v) indicate where the top-left corner of the destination lands in - the source image. - - (dx_u, dx_v) indicate the source-image movement for each movement of - x += 1 in the destination. - - (dy_u, dy_v) indicate the source-image movement for each movement of - y += 1 in the destination. - All of these values are specified as 16:16 fixed-point, ie. they encode - decimal values by multiplying them by 65536. */ - int u, v, dx_u, dx_v, dy_u, dy_v; -}; - -void image_linear(image_t const *src, image_t *dst, - struct image_linear_map *map); -image_t *image_linear_alloc(image_t const *src, - struct image_linear_map *map); - -/* image_scale(): Upscale or downscale an image - - This function generates a linear map to be used in image_linear() to scale - the input image. The scaling factor gamma can be specified independently for - the x and y dimensions. It is expressed as 16:16 fixed-point; you can set - any decimal value multiplied by 65536, for instance 1.5*65536 to increase - the width and height by 50%. */ -void image_scale(image_t const *src, int gamma_x, int gamma_y, - struct image_linear_map *map); - -/* image_rotate(): Rotate an image around its center - - This function generates a linear map to be used in image_linear() to perform - a rotation around the center of an image. If [resize=true], the target is - enlarged to make sure all the rotated pixels can be represented. This can - increase the final surface by a factor of up to 2. If the original image - doesn't extend to its corners, it is recommended to leave [resize=false] as - it noticeably affects performance. */ -void image_rotate(image_t const *src, float angle, bool resize, - struct image_linear_map *map); - -/* image_rotate_around(): Rotate an image around any point - - This function generalizes image_rotate() by allowing rotations around any - center, even a point not within the image. The center is specified through - two coordinates (*center_x, *center_y). If the center is near the side of - the image, a normal rotation would move most of the pixels out of frame; - this function moves the frame to make sure the whole image remains visible. - *center_x and *center_y are updated to indicate the position of the center - of rotation within the new frame (the target image). */ -void image_rotate_around(image_t const *src, float angle, bool resize, - int *center_x, int *center_y, struct image_linear_map *map); - -/* image_rotate_around_scale(): Rotate an image around any point and scale it - - This function generalizes image_rotate_around() by adding a scaling factor - to the transformation. The scaling factor gamma is expressed as 16:16 - fixed-point. If [resize=true] the image is further extended to make sure no - parts are cut out, as in other rotation functions. */ -void image_rotate_around_scale( - image_t const *src, float angle, int gamma, - bool resize, int *center_x, int *center_y, - struct image_linear_map *map); - -//--- -// Color transforms -//--- - -/* TODO: Color transforms */ - -//--- -// Image rendering functions -// -// The following functions extend dimage() and dsubimage(). The [effects] -// parameter takes a combination of IMAGE_* flags and effects, limited to the -// combinations previously described, with additional arguments depending on -// the color effect being applied. -// -// dimage_effect(x, y, img, effects, ...) -// dsubimage_effect(x, y, img, left, top, w, h, effects, ...) -// -// However if you use these super-generic functions you will link the code for -// all effects and all formats into your add-in, which takes a fair amount of -// space. If that's a problem, you can use the more specific functions below: -// -// * dimage__() for one particular format (rgb16, p8, p4) along -// with one particular color effect (clearbg, swapcolor, addbg, dye). -// * dimage_() is like the above when no color effect is applied. -// -// All of them support the HFLIP and VFLIP flags. For effect-specific functions -// the corresponding effect flag can be omitted (fi. IMAGE_CLEARBG is implicit -// when using dimage_p8_clearbg()). -//--- - -/* dimage_effect(): Generalized dimage() supporting dynamic effects */ -#define dimage_effect(x, y, img, eff, ...) \ - dsubimage_effect(x, y, img, 0, 0, (img)->width, (img)->height, eff, \ - ##__VA_ARGS__) -/* dsubimage_effect(): Generalized dsubimage() supporting dynamic effects */ -void dsubimage_effect(int x, int y, image_t const *img, - int left, int top, int w, int h, int effects, ...); - -/* Specific versions for each format */ -#define DIMAGE_SIG1(NAME, ...) \ - void dimage_ ## NAME(int x, int y, image_t const *img,##__VA_ARGS__); \ - void dsubimage_ ## NAME(int x, int y, image_t const *img, \ - int left, int top, int w, int h, ##__VA_ARGS__); -#define DIMAGE_SIG(NAME, ...) \ - DIMAGE_SIG1(rgb16 ## NAME, ##__VA_ARGS__) \ - DIMAGE_SIG1(p8 ## NAME, ##__VA_ARGS__) \ - DIMAGE_SIG1(p4 ## NAME, ##__VA_ARGS__) - -/* d[sub]image_{rgb16,p8,p4}_effect(..., effects, ) */ -DIMAGE_SIG(_effect, int effects, ...) -/* d[sub]image_{rgb16,p8,p4}(..., effects) (no color effect, like dimage()) */ -DIMAGE_SIG(, int effects) -/* d[sub]image_{rgb16,p8,p4}_clearbg(..., effects, bg_color_or_index) */ -DIMAGE_SIG(_clearbg, int effects, int bg_color_or_index) -/* d[sub]image_{rgb16,p8,p4}_swapcolor(..., effects, source, replacement) */ -DIMAGE_SIG(_swapcolor, int effects, int source, int replacement) -/* d[sub]image_{rgb16,p8,p4}_addbg(..., effects, bg_color) */ -DIMAGE_SIG(_addbg, int effects, int bg_color) -/* d[sub]image_{rgb16,p8,p4}_dye(..., effects, dye_color) */ -DIMAGE_SIG(_dye, int effects, int dye_color) - -/* d[sub]image_p4_clearbg_alt(..., effects, bg_index) - This is functionally identical to CLEARBG, but it uses an alternative - rendering method that is faster for larger images with wide transparent - areas. You can swap it with the normal CLEARBG freely. */ -DIMAGE_SIG1(p4_clearbg_alt, int effects, int bg_index) - -#define dimage_rgb16_effect(x, y, img, eff, ...) \ - dsubimage_rgb16_effect(x, y, img, 0, 0, (img)->width, (img)->height, \ - eff, ##__VA_ARGS__) -#define dimage_p8_effect(x, y, img, eff, ...) \ - dsubimage_p8_effect(x, y, img, 0, 0, (img)->width, (img)->height, \ - eff, ##__VA_ARGS__) -#define dimage_p4_effect(x, y, img, eff, ...) \ - dsubimage_p4_effect(x, y, img, 0, 0, (img)->width, (img)->height, \ - eff, ##__VA_ARGS__) - -#undef DIMAGE_SIG -#undef DIMAGE_SIG1 - -//--- -// Clipping utilities -//--- - -/* Double box specifying both a source and target area */ -struct gint_image_box -{ - /* Target location of top-left corner */ - int x, y; - /* Width and height of rendered sub-image */ - int w, h; - /* Source bounding box (low included, high excluded) */ - int left, top; -}; - -/* Clip the provided box against the input. If, after clipping, the box no - longer intersects the output window, returns false. Otherwise, returns - true. */ -bool gint_image_clip_input(image_t const *img, struct gint_image_box *box, - struct dwindow const *window); - -/* Clip the provided box against the output. */ -void gint_image_clip_output(struct gint_image_box *b, - struct dwindow const *window); - -//--- -// Internal image rendering routines -// -// The following functions (or non-functions) are implemented in assembler and -// make up the internal interface of the image renderer. If you just want to -// display images, use dimage() and variations; these are only useful if you -// have a different rendering system and wish to use image rendering with -// dynamic effects in it. -//--- - -/* Renderer command. This structure includes most of the information used by - the image renderer to perform blits. Some of the information on the target - is also passed as direct arguments, which is more convenient and slightly - faster. - - Most of the values here can be set with gint_image_mkcmd(). The last two - members, along with the return values of the gint_image_FORMAT_loop() - functions, are used to update the command if one needs to draw *parts* of - the image and resume the rendering later. This is used in Azur. */ -struct gint_image_cmd -{ - /* Shader ID. This is used in Azur, and ignored in gint */ - uint8_t shader_id; - /* Dynamic effects not already dispatched by renderer - Bit 0: VFLIP - Bit 1: HFLIP */ - uint8_t effect; - - /* Number of pixels to render per line. For formats that force either x - or width alignment (most of them), this is already adjusted to a - suitable multiple (usually a multiple of 2). */ - int16_t columns; - - /* Stride of the input image (number of pixels between each row), in - pixels, without subtracting the number of columns */ - int16_t input_stride; - - /* Number of lines in the command. This can be adjusted freely, and is - particularly useful in Azur for fragmented rendering. */ - uint8_t lines; - - /* [Any effect]: Offset of first edge */ - int8_t edge_1; - - /* Core loop; this is an internal label of the renderer */ - void const *loop; - /* Output pixel array, offset by target x/y */ - void const *output; - /* Input pixel array, offset by source x/y. For formats that force x - alignment, this is already adjusted. */ - void const *input; - /* Palette, when applicable */ - uint16_t const *palette; - - /* [Any effect]: Offset of right edge */ - int16_t edge_2; - /* [CLEARBG, SWAPCOLOR]: Source color */ - uint16_t color_1; - /* [SWAPCOLOR]: Destination color */ - uint16_t color_2; - - /* Remaining height (for updates between fragments) */ - int16_t height; - /* Local x position (for updates between fragments) */ - int16_t x; -}; - -/* gint_image_mkcmd(): Prepare a rendering command with dynamic effects - - This function crafts an image renderer command. It loads all the settings - except for effect-dependent parameters: the [.loop] label, the color section - of [.effect], and color effect settings. See the effect-specific functions - to see how they are defined. - - The benefit of this approach is that the rendering code does not need to be - linked in unless an effect is actually used, which avoids blowing up the - size of the add-in as the number of support dynamic effects increases. - - @box Requested on-screen box (will be clipped depending on effects) - @img Source image - @effects Set of dynamic effects to be applied, as an [IMAGE_*] bitmask - @left_edge Whether to force 2-alignment on the input (box->left) - @right_edge Whether to force 2-alignment on the width - @cmd Command to be filled - @window Rendering window (usually {0, 0, DWIDTH, DHEIGHT}) - - Returns false if there is nothing to render because of clipping (in which - case [cmd] is unchanged), true otherwise. [*box] is also updated to reflect - the final box after clipping but not accounting for edges. */ -bool gint_image_mkcmd(struct gint_image_box *box, image_t const *img, - int effects, bool left_edge, bool right_edge, - struct gint_image_cmd *cmd, struct dwindow const *window); - -/* Entry point of the renderers. These functions can be called normally as long - as you can build the commands (eg. by using gint_image_mkcmd() then filling - the effect-specific information). */ -void *gint_image_rgb16_loop (int output_width, struct gint_image_cmd *cmd); -void *gint_image_p8_loop (int output_width, struct gint_image_cmd *cmd); -void *gint_image_p4_loop (int output_width, struct gint_image_cmd *cmd); - -/* Renderer fragments. The following can absolutely not be called from C code - as they aren't full functions (and this isn't their prototype). These are - continuations to be specified in the [.loop] field of a command before using - one of the functions above. */ - -void gint_image_rgb16_normal(void); -void gint_image_rgb16_clearbg(void); -void gint_image_rgb16_swapcolor(void); -void gint_image_rgb16_dye(void); - -void gint_image_p8_normal(void); -void gint_image_p8_clearbg(void); -void gint_image_p8_swapcolor(void); -void gint_image_p8_dye(void); - -void gint_image_p4_normal(void); -void gint_image_p4_clearbg(void); -void gint_image_p4_clearbg_alt(void); -void gint_image_p4_swapcolor(void); -void gint_image_p4_dye(void); - -//--- -// Image library utilities -// -// The following functions and macros are mostly internal utilities; they are -// exposed here in case user applications want to extend the set of image -// transforms with custom additions. -//--- - -/* image_target(): Check if an image can be used as target for a transform - - This function is used to quickly check whether a transform from [src] to - [dst] is possible. It requires image_valid(src) and image_valid(dst), plus - any optional constraints specified as variadic arguments. These constraints - can be: - - * NOT_P4: fails if [dst] is P4. - * DATA_RW: fails if [dst] is not data-writable. - * PALETTE_RW: fails if [dst] is not palette-writable. - * SAME_SIZE: fails if [dst] is not at least as large as [src]. - - For example, in image_hflip(), we write: - if(!image_target(src, dst, NOT_P4, DATA_RW, SAME_SIZE)) return; */ - -enum { - IMAGE_TARGET_NONE, - IMAGE_TARGET_NOT_P4, - IMAGE_TARGET_DATA_RW, - IMAGE_TARGET_PALETTE_RW, - IMAGE_TARGET_SAME_SIZE, - IMAGE_TARGET_SAME_FORMAT, - IMAGE_TARGET_SAME_DEPTH, -}; -bool image_target(image_t const *src, image_t *dst, ...); - -#define image_target(src, dst, ...) \ - image_target(src, dst, image_target_arg1(__VA_ARGS__ __VA_OPT__(,) NONE)) -#define image_target_arg1(c, ...) \ - IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg2(__VA_ARGS__)) -#define image_target_arg2(c, ...) \ - IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg3(__VA_ARGS__)) -#define image_target_arg3(c, ...) \ - IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg4(__VA_ARGS__)) -#define image_target_arg4(c, ...) \ - IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg5(__VA_ARGS__)) -#define image_target_arg5(c, ...) \ - IMAGE_TARGET_ ## c __VA_OPT__(, image_target_arg6(__VA_ARGS__)) -#define image_target_arg6(c, ...) \ - IMAGE_TARGET_ ## c __VA_OPT__(, image_target_too_many_args(__VA_ARGS__)) - -/* image_alpha_2(): Conditional alpha */ -#define image_alpha_2(fmt, copy_alpha) \ - ((copy_alpha) ? 0x10000 : image_alpha(fmt)) - -#endif /* GINT_RENDER_RGB */ - -#ifdef __cplusplus -} -#endif - -#endif /* GINT_IMAGE */ diff --git a/src/game_data.cpp b/src/game_data.cpp deleted file mode 100644 index f9ee39d..0000000 --- a/src/game_data.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include -#include -#include - -#include "game_data.hpp" - -struct texture_t builtin_textures[NB_TEXTURES] = { - {"player_idle_sheet", &img_player_idle_sheet}, - {"player_walk_sheet", &img_player_walk_sheet} -}; - -void load_json_into_game_data(json *json_input, game_data_t *bin_output) -{ -} - -void write_game_data_as_bin_into_file(game_data_t *game_data, std::ofstream *bin_output_file) -{ -} - -void free_game_data(game_data_t *game_data) -{ -} diff --git a/src/game_data.hpp b/src/game_data.hpp deleted file mode 100644 index 5b085f2..0000000 --- a/src/game_data.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef GAME_DATA_HPP -#define GAME_DATA_HPP - -#include -#include -#include "nlohmann/json/json.hpp" - -using nlohmann::json; - -extern bopti_image_t img_player_idle_sheet; -extern bopti_image_t img_player_walk_sheet; - -typedef struct texture_t { - const char *name; - bopti_image_t *image; -} texture_t; - -#define NB_TEXTURES 2 -extern struct texture_t builtin_textures[]; - -typedef struct game_data_t { - texture_t *textures; -} game_data_t; - -void load_json_into_game_data(json *json_input, game_data_t *game_data); - -void write_game_data_as_bin_into_file(game_data_t *game_data, std::ofstream *bin_output_file); - -void free_game_data(game_data_t *game_data); - -#endif // GAME_DATA_HPP diff --git a/src/game_data/ecs/animation_system.hpp b/src/game_data/ecs/animation_system.hpp new file mode 100644 index 0000000..5a8d7d9 --- /dev/null +++ b/src/game_data/ecs/animation_system.hpp @@ -0,0 +1,16 @@ +#ifndef ANIMATION_SYSTEM_H +#define ANIMATION_SYSTEM_H + +#include + +typedef struct animation_system_data_t { + bool play :1; + bool loop :1; + bool reverse :1; + + float frame_delay_ms; + uint32_t actual_frame_nb; + uint32_t nb_frames; +} animation_system_data_t; + +#endif // SPRITE_COMPONENT_H \ No newline at end of file diff --git a/src/game_data/ecs/components.hpp b/src/game_data/ecs/components.hpp new file mode 100644 index 0000000..db835bd --- /dev/null +++ b/src/game_data/ecs/components.hpp @@ -0,0 +1,9 @@ +#ifndef COMPONENTS_H +#define COMPONENTS_H + +#include "transform_component.hpp" +#include "sprite_component.hpp" +#include "animation_system.hpp" +// Add new components header file here + +#endif // COMPONENTS_H \ No newline at end of file diff --git a/src/game_data/ecs/ecs.hpp b/src/game_data/ecs/ecs.hpp new file mode 100644 index 0000000..f765089 --- /dev/null +++ b/src/game_data/ecs/ecs.hpp @@ -0,0 +1,31 @@ +#ifndef ECS_H +#define ECS_H + +#include + +#include "components.hpp" + +typedef enum component_type_t { + TRANSFORM_COMPONENT, + SPRITE_COMPONENT, + ANIMATION_SYSTEM +} component_type_t; + +typedef struct component_t { + component_type_t component_type; + + union { + transform_component_data_t *transform_component_data; + sprite_component_data_t *sprite_component_data; + animation_system_data_t *animation_system_data; + } component_data; +} component_t; + +typedef struct entity_t { + uint16_t id; + + unsigned long nb_component; + component_t *components; +} entity_t; + +#endif // ECS_H \ No newline at end of file diff --git a/src/game_data/ecs/sprite_component.hpp b/src/game_data/ecs/sprite_component.hpp new file mode 100644 index 0000000..b9826c9 --- /dev/null +++ b/src/game_data/ecs/sprite_component.hpp @@ -0,0 +1,8 @@ +#ifndef SPRITE_COMPONENT_H +#define SPRITE_COMPONENT_H + +typedef struct sprite_component_data_t { + const char *texture_name; +} sprite_component_data_t; + +#endif // SPRITE_COMPONENT_H \ No newline at end of file diff --git a/src/game_data/ecs/transform_component.hpp b/src/game_data/ecs/transform_component.hpp new file mode 100644 index 0000000..92b9ca9 --- /dev/null +++ b/src/game_data/ecs/transform_component.hpp @@ -0,0 +1,10 @@ +#ifndef TRANSFORM_COMPONENT_H +#define TRANSFORM_COMPONENT_H + +typedef struct transform_component_data_t { + uint32_t x, y; + uint32_t w, h; + float speed; +} transform_component_data_t; + +#endif // TRANSFORM_COMPONENT_H \ No newline at end of file diff --git a/src/game_data/game_data.cpp b/src/game_data/game_data.cpp new file mode 100644 index 0000000..0f29ca9 --- /dev/null +++ b/src/game_data/game_data.cpp @@ -0,0 +1,11 @@ +#include + +#include "game_data.hpp" + +void load_game_data(game_data_t *game_data) +{ +} + +void write_game_data_as_bin_into_file(game_data_t *game_data, std::ofstream *bin_output_file) +{ +} diff --git a/src/game_data/game_data.hpp b/src/game_data/game_data.hpp new file mode 100644 index 0000000..080f96f --- /dev/null +++ b/src/game_data/game_data.hpp @@ -0,0 +1,21 @@ +#ifndef GAME_DATA_HPP +#define GAME_DATA_HPP + +#include + +#include "textures.hpp" +#include "maps.hpp" + +typedef struct game_data_t { + uint32_t nb_textures; + texture_t *textures; + + uint32_t nb_maps; + map_t *maps; +} game_data_t; + +void load_game_data(game_data_t *game_data); + +void write_game_data_as_bin_into_file(game_data_t *game_data, std::ofstream *bin_output_file); + +#endif // GAME_DATA_HPP diff --git a/src/game_data/maps.hpp b/src/game_data/maps.hpp new file mode 100644 index 0000000..c0f9460 --- /dev/null +++ b/src/game_data/maps.hpp @@ -0,0 +1,29 @@ +#ifndef MAP_HPP +#define MAP_HPP + +#include "ecs/ecs.hpp" + +typedef struct map_t { + const char *name; + + uint32_t map_width; + uint32_t map_height; + + uint16_t *map_background_layer1; + uint16_t *map_background_layer2; + uint16_t *map_background_layer3; + uint16_t *map_foreground; + + uint32_t nb_entities; + entity_t *entities; +} map_t; + +extern map_t map_example; + +static map_t *maps[] = { + &map_example +}; + +#define NB_MAPS sizeof(maps) / sizeof(map_t) + +#endif // MAP_HPP \ No newline at end of file diff --git a/src/game_data/textures.hpp b/src/game_data/textures.hpp new file mode 100644 index 0000000..fe5903d --- /dev/null +++ b/src/game_data/textures.hpp @@ -0,0 +1,25 @@ +#ifndef TEXTURES_HPP +#define TEXTURES_HPP + +#include + +typedef struct texture_t { + const char *name; + bopti_image_t *image; +} texture_t; + +extern bopti_image_t img_tileset; +extern bopti_image_t img_player_idle_sheet; +extern bopti_image_t img_player_walk_sheet; +extern bopti_image_t img_player_run_sheet; + +static texture_t textures[] = { + {"tileset", &img_tileset}, + {"player_idle_sheet", &img_player_idle_sheet}, + {"player_walk_sheet", &img_player_walk_sheet}, + {"player_run_sheet", &img_player_run_sheet} +}; + +#define NB_TEXTURES sizeof(textures) / sizeof(texture_t) + +#endif // TEXTURE_HPP \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 1193ff0..207bda4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ #include -#include "game_data.hpp" +#include "game_data/game_data.hpp" void error(std::string error); @@ -12,13 +12,6 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - std::ifstream json_input_file {argv[1]}; - if(!json_input_file) - { - error("Couldn't open input file"); - return EXIT_FAILURE; - } - std::ofstream bin_output_file {argv[2], std::ios::binary}; if(!bin_output_file) { @@ -26,15 +19,12 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - json json_input = json::parse(json_input_file); game_data_t game_data; - load_json_into_game_data(&json_input, &game_data); + load_game_data(&game_data); write_game_data_as_bin_into_file(&game_data, &bin_output_file); - free_game_data(&game_data); - return EXIT_SUCCESS; } diff --git a/src/test.cpp b/src/test.cpp deleted file mode 100644 index 48a60ad..0000000 --- a/src/test.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -extern bopti_image_t img_tileset; - -int main(void) -{ - int16_t value = 0; - printf("colorcount:%d, value:%d\n", img_tileset.color_count, value); - printf("width:%d, height:%d\n", img_tileset.width, img_tileset.height); - printf("totalsize:%ld\n", sizeof(img_tileset) + img_tileset.width * img_tileset.height); - - return 0; -}