Building maps into asset file !

This commit is contained in:
Ulysse Cura 2026-08-15 20:42:26 +02:00
parent ae3e040fac
commit e73b34e87d
15 changed files with 826 additions and 253 deletions

@ -1 +1 @@
Subproject commit 946cc2e4953cdbe5204adb5a5fe71650ba9542ca
Subproject commit 405ed84cae9b83eba540d7ee319f5ff025a314a1

View File

@ -5,7 +5,8 @@ ASSETS := \
props_sheets/lever_sheet.png \
props_sheets/barred_door_sheet.png \
props_sheets/wooden_door_sheet.png \
tileset/tileset.png
tileset/tileset.png \
maps/dungeon_room_1.map
ASSETS := $(addprefix $(ASSETS_DIR)/,$(ASSETS))

View File

@ -1,13 +1,13 @@
# Asset file structure
| Description | Length |
| :---------------- | :---------------------------------- |
| Assets number | unsigned int (32 bits) |
| ... | |
| Asset name | const char * (variable length) |
| Asset start index | unsigned int (32 bits) |
| ... | |
| Asset data | depend on assets content and number |
| Description | Length |
| :---------------- | :------------------------------------------------ |
| Assets number | unsigned int (32 bits) |
| ... | |
| Asset name | const char [] (variable length, ends with '\00') |
| Asset start index | unsigned int (32 bits) |
| ... | |
| Asset data | depend on assets content and number |
## Image (.png)
@ -32,21 +32,26 @@ Image data is in RGB 565.
### Maps asset data structure
| Description | Length |
| :-------------------------- | :-------------------------------------- |
| Map width | int (32 bits) |
| Map height | int (32 bits) |
| Map background layer 1 data | depend on map size, tile short (16 bit) |
| Map background layer 2 data | depend on map size, tile short (16 bit) |
| Map background layer 3 data | depend on map size, tile short (16 bit) |
| Map foreground layer data | depend on map size, tile short (16 bit) |
| Entities number | int (32 bits) |
| ... | |
| Entity ID | int (32 bits) |
| Entity component number | int (32 bits) |
| ... | |
| Component type | int (32 bits) |
| ... | |
| Component attributes | depend on attribute type |
| ... | |
| ... | |
| Description | Length |
| :-------------------------- | :------------------------------------------------ |
| Map width | unsigned int (32 bits) |
| Map height | unsigned int (32 bits) |
| Map background layer 1 data | depend on map size, tile short (16 bits) |
| Map background layer 2 data | depend on map size, tile short (16 bits) |
| Map background layer 3 data | depend on map size, tile short (16 bits) |
| Map foreground layer data | depend on map size, tile short (16 bits) |
| Map hitboxes data | depend on map size, tile unsigned char (8 bits) |
| Entities number | unsigned int (32 bits) |
| ... | |
| Entity ID | unsigned int (32 bits) |
| Entity components number | unsigned int (32 bits) |
| ... | |
| Component type | int (32 bits) |
| ... | |
| Component attributes | depend on attribute type |
| int | int (32 bits) |
| float | float (32 bits) |
| bool | bool (8 bits) |
| str | const char [] (variable length, ends with '\00') |
| ... | |
| ... | |

View File

@ -1,6 +1,7 @@
gcc
# Headers
-Iassets/asset_builder/src/headers
-Isrc/components/headers
# Macros
-DDEBUG=2

View File

@ -1,16 +1,18 @@
# Source files
ASSET_BUILDER_SOURCES := \
asset_file.c \
image.c \
map.c \
main.c
# Compiler and flags
ASSET_BUILDER_CC = gcc
ifeq ($(RELEASE), 1)
ASSET_BUILDER_CFLAGS = --std=c17 --pedantic -O3 $(shell pkg-config --cflags libpng) # RELEASE
ASSET_BUILDER_CFLAGS = --std=c17 --pedantic -O3 $(shell pkg-config --cflags libpng json-c) # RELEASE
else
ASSET_BUILDER_CFLAGS = --std=c17 --pedantic -O1 -g $(shell pkg-config --cflags libpng) \
ASSET_BUILDER_CFLAGS = --std=c17 --pedantic -O1 -DDEBUG=1 -g $(shell pkg-config --cflags libpng json-c) \
-Wall -Wno-missing-braces -Wextra -Wno-missing-field-initializers \
-Wformat=2 -Wswitch-default -Wswitch-enum -Wcast-align \
-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 \
@ -18,10 +20,10 @@ ASSET_BUILDER_CFLAGS = --std=c17 --pedantic -O1 -g $(shell pkg-config --cflags l
-Wold-style-definition # DEVELOPEMENT
endif
ASSET_BUILDER_INCLUDE_DIRS = $(ASSET_BUILDER_DIR)/headers
ASSET_BUILDER_INCLUDE_DIRS = $(ASSET_BUILDER_DIR)/headers $(SOURCE_DIR)/components/headers
ASSET_BUILDER_INCLUDE_DIRS := $(addprefix -I, $(ASSET_BUILDER_INCLUDE_DIRS))
ASSET_BUILDER_LDFLAGS = $(shell pkg-config --libs libpng)
ASSET_BUILDER_LDFLAGS = $(shell pkg-config --libs libpng json-c)
# Deduce objects
ASSET_BUILDER_OBJECTS = $(ASSET_BUILDER_SOURCES:%.c=$(BUILD_DIR)/$(ASSET_BUILDER_DIR)/%.o)

View File

@ -1,14 +1,11 @@
#include "asset_file.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <png.h>
#include "image.h"
#include "map.h"
#include "errors.h"
int parse_png_for_header(const char *input_file_name, asset_header_def_t *asset_header_def);
int parse_png_for_content_and_write(const char *input_file_name, FILE *output_file);
int parse_file_for_header(const char *input_file_name, asset_header_def_t *asset_header_def)
{
const char *file_name_dot = strrchr(input_file_name, '.');
@ -25,6 +22,10 @@ int parse_file_for_header(const char *input_file_name, asset_header_def_t *asset
{
if(parse_png_for_header(input_file_name, asset_header_def)) return_failure_int;
}
else if(!strcmp(file_name_ext, "map"))
{
if(parse_map_for_header(input_file_name, asset_header_def)) return_failure_int;
}
else
{
error_printf("Extension unsupported : %s", file_name_dot);
@ -77,6 +78,10 @@ int parse_file_for_content_and_write(const char *input_file_name, FILE *output_f
{
if(parse_png_for_content_and_write(input_file_name, output_file)) return_failure_int;
}
else if(!strcmp(file_name_ext, "map"))
{
if(parse_map_for_content_and_write(input_file_name, output_file)) return_failure_int;
}
else
{
error_printf("Extension unsupported : %s", file_name_dot);
@ -85,213 +90,3 @@ int parse_file_for_content_and_write(const char *input_file_name, FILE *output_f
return EXIT_SUCCESS;
}
// File specific functions.
int parse_png_for_header(const char *file_name, asset_header_def_t *asset_header_def)
{
FILE *input_file = fopen(file_name, "rb");
if(!input_file)
{
error_printf("Failed to open input file.");
return EXIT_FAILURE;
}
// Check png autenticity.
unsigned char sig[8];
if(fread(sig, sizeof(unsigned char), 8, input_file) != 8)
{
fclose(input_file);
error_printf("Failed to read input file.");
return EXIT_FAILURE;
}
if(!png_check_sig(sig, 8))
{
fclose(input_file);
error_printf("Png file is not valid.");
return EXIT_FAILURE;
}
// PNG structs.
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
{
fclose(input_file);
error_printf("Failed to allocate png ptr.");
return EXIT_FAILURE;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(input_file);
error_printf("Failed to allocate png info.");
return EXIT_FAILURE;
}
// Fill structs and load data.
png_init_io(png_ptr, input_file);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
uint32_t width = png_get_image_width(png_ptr, info_ptr);
uint32_t height = png_get_image_height(png_ptr, info_ptr);
uint8_t bit_depth = png_get_bit_depth(png_ptr, info_ptr);
uint8_t color_type = png_get_color_type(png_ptr, info_ptr);
// Verify png attributes.
if(bit_depth != 8)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Png bit depth not supported.");
return EXIT_FAILURE;
}
switch(color_type)
{
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
break;
default:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Png color type not supported.");
return EXIT_FAILURE;
}
// Fill asset def.
asset_header_def->start = 0;
asset_header_def->end = sizeof(int) * 2 + height * width * sizeof(uint16_t);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
return EXIT_SUCCESS;
}
int parse_png_for_content_and_write(const char *input_file_name, FILE *output_file)
{
FILE *input_file = fopen(input_file_name, "rb");
if(!input_file)
{
error_printf("Failed to open input file.");
return EXIT_FAILURE;
}
// Check png autenticity.
unsigned char sig[8];
if(fread(sig, sizeof(unsigned char), 8, input_file) != 8)
{
fclose(input_file);
error_printf("Failed to read input file.");
return EXIT_FAILURE;
}
if(!png_check_sig(sig, 8))
{
fclose(input_file);
error_printf("Png file is not valid.");
return EXIT_FAILURE;
}
// PNG structs.
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
{
fclose(input_file);
error_printf("Failed to allocate png ptr.");
return EXIT_FAILURE;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(input_file);
error_printf("Failed to allocate png info.");
return EXIT_FAILURE;
}
// Fill structs and load data.
png_init_io(png_ptr, input_file);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
uint32_t width = png_get_image_width(png_ptr, info_ptr);
uint32_t height = png_get_image_height(png_ptr, info_ptr);
size_t row_length = png_get_rowbytes(png_ptr, info_ptr);
// Write image size.
if(fwrite(&width, sizeof(width), 1, output_file) != 1)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
if(fwrite(&height, sizeof(height), 1, output_file) != 1)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
// Prepare storage.
png_byte src_pixels[height * row_length];
png_bytep src_row_ptrs[height];
for(png_uint_32 i = 0; i < height; i++)
src_row_ptrs[i] = &src_pixels[i * row_length];
// Read pixels.
png_read_image(png_ptr, src_row_ptrs);
uint16_t dst_pixels[width * height * sizeof(uint16_t)];
for(uint32_t i = 0; i < height; i++)
{
for(uint32_t j = 0; j < width; j += 1)
{
uint8_t r, g, b;
if(src_pixels[i * row_length + j * 4 + 3])
{
r = src_pixels[i * row_length + j * 4] >> 3;
g = src_pixels[i * row_length + j * 4 + 1] >> 2;
b = src_pixels[i * row_length + j * 4 + 2] >> 3;
}
else
{
r = 0x1F;
g = 0x00;
b = 0x1F;
}
uint16_t pixel = ((r) << 11) | ((g) << 5) | b;
dst_pixels[i * width + j] = pixel;
// printf("\033[48;2;%d;%d;%dm ", r << 3, g << 2, b << 3);
}
// puts("\033[m");
}
if(fwrite(&dst_pixels, sizeof(uint16_t), width * height, output_file) != width * height)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,9 @@
#ifndef IMAGE_H
#define IMAGE_H
#include "asset_file.h"
int parse_png_for_header(const char *input_file_name, asset_header_def_t *asset_header_def);
int parse_png_for_content_and_write(const char *input_file_name, FILE *output_file);
#endif // IMAGE_H

View File

@ -0,0 +1,9 @@
#ifndef MAP_H
#define MAP_H
#include "asset_file.h"
int parse_map_for_header(const char *input_file_name, asset_header_def_t *asset_header_def);
int parse_map_for_content_and_write(const char *input_file_name, FILE *output_file);
#endif // MAP_H

View File

@ -0,0 +1,215 @@
#include "image.h"
#include <png.h>
#include <stdlib.h>
#include "asset_file.h"
#include "errors.h"
int parse_png_for_header(const char *file_name, asset_header_def_t *asset_header_def)
{
FILE *input_file = fopen(file_name, "rb");
if(!input_file)
{
error_printf("Failed to open input file.");
return EXIT_FAILURE;
}
// Check png autenticity.
unsigned char sig[8];
if(fread(sig, sizeof(unsigned char), 8, input_file) != 8)
{
fclose(input_file);
error_printf("Failed to read input file.");
return EXIT_FAILURE;
}
if(!png_check_sig(sig, 8))
{
fclose(input_file);
error_printf("Png file is not valid.");
return EXIT_FAILURE;
}
// PNG structs.
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
{
fclose(input_file);
error_printf("Failed to allocate png ptr.");
return EXIT_FAILURE;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(input_file);
error_printf("Failed to allocate png info.");
return EXIT_FAILURE;
}
// Fill structs and load data.
png_init_io(png_ptr, input_file);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
uint32_t width = png_get_image_width(png_ptr, info_ptr);
uint32_t height = png_get_image_height(png_ptr, info_ptr);
uint8_t bit_depth = png_get_bit_depth(png_ptr, info_ptr);
uint8_t color_type = png_get_color_type(png_ptr, info_ptr);
// Verify png attributes.
if(bit_depth != 8)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Png bit depth not supported.");
return EXIT_FAILURE;
}
switch(color_type)
{
case PNG_COLOR_TYPE_RGB:
case PNG_COLOR_TYPE_RGB_ALPHA:
break;
default:
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Png color type not supported.");
return EXIT_FAILURE;
}
// Fill asset def.
asset_header_def->start = 0;
asset_header_def->end = sizeof(width) + sizeof(height) + height * width * sizeof(uint16_t);
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
return EXIT_SUCCESS;
}
int parse_png_for_content_and_write(const char *input_file_name, FILE *output_file)
{
FILE *input_file = fopen(input_file_name, "rb");
if(!input_file)
{
error_printf("Failed to open input file.");
return EXIT_FAILURE;
}
// Check png autenticity.
unsigned char sig[8];
if(fread(sig, sizeof(unsigned char), 8, input_file) != 8)
{
fclose(input_file);
error_printf("Failed to read input file.");
return EXIT_FAILURE;
}
if(!png_check_sig(sig, 8))
{
fclose(input_file);
error_printf("Png file is not valid.");
return EXIT_FAILURE;
}
// PNG structs.
png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(!png_ptr)
{
fclose(input_file);
error_printf("Failed to allocate png ptr.");
return EXIT_FAILURE;
}
png_infop info_ptr = png_create_info_struct(png_ptr);
if(!info_ptr)
{
png_destroy_read_struct(&png_ptr, NULL, NULL);
fclose(input_file);
error_printf("Failed to allocate png info.");
return EXIT_FAILURE;
}
// Fill structs and load data.
png_init_io(png_ptr, input_file);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
uint32_t width = png_get_image_width(png_ptr, info_ptr);
uint32_t height = png_get_image_height(png_ptr, info_ptr);
size_t row_length = png_get_rowbytes(png_ptr, info_ptr);
// Write image size.
if(fwrite(&width, sizeof(width), 1, output_file) != 1)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
if(fwrite(&height, sizeof(height), 1, output_file) != 1)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
// Prepare storage.
png_byte src_pixels[height * row_length];
png_bytep src_row_ptrs[height];
for(png_uint_32 i = 0; i < height; i++)
src_row_ptrs[i] = &src_pixels[i * row_length];
// Read pixels.
png_read_image(png_ptr, src_row_ptrs);
uint16_t dst_pixels[width * height * sizeof(uint16_t)];
for(uint32_t i = 0; i < height; i++)
{
for(uint32_t j = 0; j < width; j += 1)
{
uint8_t r, g, b;
if(src_pixels[i * row_length + j * 4 + 3])
{
r = src_pixels[i * row_length + j * 4] >> 3;
g = src_pixels[i * row_length + j * 4 + 1] >> 2;
b = src_pixels[i * row_length + j * 4 + 2] >> 3;
}
else
{
r = 0x1F;
g = 0x00;
b = 0x1F;
}
uint16_t pixel = ((r) << 11) | ((g) << 5) | b;
dst_pixels[i * width + j] = pixel;
// printf("\033[48;2;%d;%d;%dm ", r << 3, g << 2, b << 3);
}
// puts("\033[m");
}
if(fwrite(&dst_pixels, sizeof(uint16_t), width * height, output_file) != width * height)
{
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
fclose(input_file);
return EXIT_SUCCESS;
}

View File

@ -21,12 +21,11 @@ int main(int argc, char *argv[])
asset_file_header_t asset_file_header;
asset_file_header.assets_number = argc - 2;
asset_file_header.header_size = sizeof(asset_file_header.assets_number) + sizeof(uint32_t) * asset_file_header.assets_number;
asset_file_header.assets_header_def = malloc(asset_file_header.assets_number * sizeof(asset_header_def_t));
asset_file_header.assets_header_def = calloc(asset_file_header.assets_number, sizeof(asset_header_def_t));
if(!asset_file_header.assets_header_def)
{
error_printf("Failed to allocate memory.");
goto end;
}
// Set assets name.

View File

@ -0,0 +1,536 @@
#include "map.h"
#include <json-c/json.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include "asset_file.h"
#include "errors.h"
int parse_map_for_header(const char *input_file_name, asset_header_def_t *asset_header_def)
{
json_object *root = json_object_from_file(input_file_name);
if (!root)
{
error_printf("Failed to load input file.");
return EXIT_FAILURE;
}
if(json_object_object_length(root) != 8)
{
json_object_put(root);
error_printf("Map file doesn't contain 8 elements at its root.");
return EXIT_FAILURE;
}
json_object *tmp_obj;
if(!json_object_object_get_ex(root, "MapWidth", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"MapWidth\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_int))
{
error_printf("Map key \"MapWidth\" is not of type int.");
return EXIT_FAILURE;
}
int map_width = json_object_get_int(tmp_obj);
if(!json_object_object_get_ex(root, "MapHeight", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"MapHeight\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_int))
{
error_printf("Map key \"MapHeight\" is not of type int.");
return EXIT_FAILURE;
}
int map_height = json_object_get_int(tmp_obj);
json_object *entities;
if(!json_object_object_get_ex(root, "Entities", &entities))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"Entities\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(entities, json_type_array))
{
json_object_put(root);
error_printf("Map object \"Entities\" is not an array.");
return EXIT_FAILURE;
}
uint32_t entities_nb = json_object_array_length(entities);
asset_header_def->start = 0;
asset_header_def->end = sizeof(map_width) + sizeof(map_height)
+ map_width * map_height * sizeof(uint16_t) * 4
+ map_width * map_height * sizeof(uint8_t)
+ sizeof(entities_nb);
for(uint32_t i = 0; i < entities_nb; i++)
{
json_object *entity = json_object_array_get_idx(entities, i);
if(!json_object_is_type(entity, json_type_object))
{
error_printf("Map entity is not of type object.");
return EXIT_FAILURE;
}
asset_header_def->end += sizeof(uint32_t);
json_object *components;
if(!json_object_object_get_ex(entity, "Components", &components))
{
error_printf("Entity doesn't have key \"Components\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(components, json_type_array))
{
error_printf("Component is not of type array.");
return EXIT_FAILURE;
}
uint32_t components_nb = json_object_array_length(components);
asset_header_def->end += sizeof(components_nb);
for(uint32_t j = 0; j < components_nb; j++)
{
json_object *component = json_object_array_get_idx(components, j);
if(!json_object_is_type(component, json_type_object))
{
error_printf("Entity component is not of type object.");
return EXIT_FAILURE;
}
asset_header_def->end += sizeof(uint32_t);
json_object *attributes;
if(!json_object_object_get_ex(component, "Attributes", &attributes))
{
error_printf("Component doesn't have key \"Attributes\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(attributes, json_type_array))
{
error_printf("Attributes is not of type array.");
return EXIT_FAILURE;
}
uint32_t attributes_nb = json_object_array_length(attributes);
for(uint32_t k = 0; k < attributes_nb; k++)
{
json_object *attribute = json_object_array_get_idx(attributes, k);
switch(json_object_get_type(attribute))
{
case json_type_int:
asset_header_def->end += sizeof(uint32_t);
break;
case json_type_double:
asset_header_def->end += sizeof(float);
break;
case json_type_boolean:
asset_header_def->end += sizeof(bool);
break;
case json_type_string:
asset_header_def->end += json_object_get_string_len(attribute) + 1;
break;
default:
error_printf("Attribute type is not supported : %s", json_type_to_name(json_object_get_type(attribute)));
return EXIT_FAILURE;
}
}
}
}
json_object_put(root);
return EXIT_SUCCESS;
}
typedef enum component_type_t {
#define COMPONENT(NAME, ...) NAME,
#include "components.def"
} component_type_t;
int parse_map_for_content_and_write(const char *input_file_name, FILE *output_file)
{
json_object *root = json_object_from_file(input_file_name);
if (!root)
{
error_printf("Failed to load input file.");
return EXIT_FAILURE;
}
json_object *tmp_obj;
if(!json_object_object_get_ex(root, "MapWidth", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"MapWidth\".");
return EXIT_FAILURE;
}
int map_width = json_object_get_int(tmp_obj);
if(fwrite(&map_width, sizeof(map_width), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
if(!json_object_object_get_ex(root, "MapHeight", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"MapHeight\".");
return EXIT_FAILURE;
}
int map_height = json_object_get_int(tmp_obj);
if(fwrite(&map_height, sizeof(map_height), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
// Background Layer 1
if(!json_object_object_get_ex(root, "BackgroundLayer1", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"BackgroundLayer1\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_array))
{
json_object_put(root);
error_printf("Map background layer 1 is not of type array.");
return EXIT_FAILURE;
}
uint16_t layer_data[map_width * map_height];
for(size_t i = 0; i < (size_t)map_width * (size_t)map_height; i++)
{
json_object *tile = json_object_array_get_idx(tmp_obj, i);
layer_data[i] = json_object_get_int(tile);
}
if(fwrite(&layer_data, sizeof(uint16_t), map_width * map_height, output_file) != (size_t)map_width * (size_t)map_height)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
// Background Layer 2
if(!json_object_object_get_ex(root, "BackgroundLayer2", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"BackgroundLayer2\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_array))
{
json_object_put(root);
error_printf("Map background layer 1 is not of type array.");
return EXIT_FAILURE;
}
for(size_t i = 0; i < (size_t)map_width * (size_t)map_height; i++)
{
json_object *tile = json_object_array_get_idx(tmp_obj, i);
layer_data[i] = json_object_get_int(tile);
}
if(fwrite(&layer_data, sizeof(uint16_t), map_width * map_height, output_file) != (size_t)map_width * (size_t)map_height)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
// Background Layer 3
if(!json_object_object_get_ex(root, "BackgroundLayer3", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"BackgroundLayer3\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_array))
{
json_object_put(root);
error_printf("Map background layer 1 is not of type array.");
return EXIT_FAILURE;
}
for(size_t i = 0; i < (size_t)map_width * (size_t)map_height; i++)
{
json_object *tile = json_object_array_get_idx(tmp_obj, i);
layer_data[i] = json_object_get_int(tile);
}
if(fwrite(&layer_data, sizeof(uint16_t), map_width * map_height, output_file) != (size_t)map_width * (size_t)map_height)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
// Foreground
if(!json_object_object_get_ex(root, "Foreground", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"Foreground\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_array))
{
json_object_put(root);
error_printf("Map background layer 1 is not of type array.");
return EXIT_FAILURE;
}
for(size_t i = 0; i < (size_t)map_width * (size_t)map_height; i++)
{
json_object *tile = json_object_array_get_idx(tmp_obj, i);
layer_data[i] = json_object_get_int(tile);
}
if(fwrite(&layer_data, sizeof(uint16_t), map_width * map_height, output_file) != (size_t)map_width * (size_t)map_height)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
// Hitboxes
if(!json_object_object_get_ex(root, "Hitboxes", &tmp_obj))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"Hitboxes\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_array))
{
json_object_put(root);
error_printf("Map background layer 1 is not of type array.");
return EXIT_FAILURE;
}
uint8_t hitboxes_layer[map_width * map_height];
for(size_t i = 0; i < (size_t)map_width * (size_t)map_height; i++)
{
json_object *tile = json_object_array_get_idx(tmp_obj, i);
hitboxes_layer[i] = json_object_get_int(tile);
}
if(fwrite(&hitboxes_layer, sizeof(uint8_t), map_width * map_height, output_file) != (size_t)map_width * (size_t)map_height)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
json_object *entities;
if(!json_object_object_get_ex(root, "Entities", &entities))
{
json_object_put(root);
error_printf("Map file doesn't contain key \"Entities\".");
return EXIT_FAILURE;
}
uint32_t entities_nb = json_object_array_length(entities);
if(fwrite(&entities_nb, sizeof(entities_nb), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
for(uint32_t i = 0; i < entities_nb; i++)
{
json_object *entity = json_object_array_get_idx(entities, i);
if(!json_object_object_get_ex(entity, "ID", &tmp_obj))
{
json_object_put(root);
error_printf("Entity doesn't have key \"ID\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_int))
{
json_object_put(root);
error_printf("Entity ID is not of type int.");
return EXIT_FAILURE;
}
uint32_t entity_id = json_object_get_int(tmp_obj);
if(fwrite(&entity_id, sizeof(entity_id), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
json_object *components;
if(!json_object_object_get_ex(entity, "Components", &components))
{
json_object_put(root);
error_printf("Entity doesn't have key \"Components\".");
return EXIT_FAILURE;
}
uint32_t components_nb = json_object_array_length(components);
if(fwrite(&components_nb, sizeof(components_nb), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
for(uint32_t j = 0; j < components_nb; j++)
{
json_object *component = json_object_array_get_idx(components, j);
json_object *attributes;
if(!json_object_object_get_ex(component, "Type", &tmp_obj))
{
json_object_put(root);
error_printf("Component doesn't have key \"Type\".");
return EXIT_FAILURE;
}
if(!json_object_is_type(tmp_obj, json_type_string))
{
json_object_put(root);
error_printf("Component type is not of type string.");
return EXIT_FAILURE;
}
component_type_t component_type;
#define COMPONENT(NAME, ...) \
if(!strcmp(#NAME, json_object_get_string(tmp_obj))) \
component_type = NAME;
#include "components.def"
if(fwrite(&component_type, sizeof(uint32_t), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
if(!json_object_object_get_ex(component, "Attributes", &attributes))
{
json_object_put(root);
error_printf("Component doesn't have key \"Attributes\".");
return EXIT_FAILURE;
}
uint32_t attributes_nb = json_object_array_length(attributes);
for(uint32_t k = 0; k < attributes_nb; k++)
{
json_object *attribute = json_object_array_get_idx(attributes, k);
switch(json_object_get_type(attribute))
{
case json_type_int:
{
int value = json_object_get_int(attribute);
if(fwrite(&value, sizeof(value), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
break;
}
case json_type_double:
{
float value = json_object_get_double(attribute);
if(fwrite(&value, sizeof(value), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
break;
}
case json_type_boolean:
{
bool value = json_object_get_boolean(attribute);
if(fwrite(&value, sizeof(value), 1, output_file) != 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
break;
}
case json_type_string:
{
const char *str = json_object_get_string(attribute);
if(fwrite(str, sizeof(char), strlen(str) + 1, output_file) != strlen(str) + 1)
{
json_object_put(root);
error_printf("Failed to write to output file : %d", errno);
return EXIT_FAILURE;
}
break;
}
default:
return EXIT_FAILURE;
}
}
}
}
json_object_put(root);
return EXIT_SUCCESS;
}

View File

@ -134,7 +134,7 @@
{
"Type": "DOOR_COMPONENT",
"Attributes": [
"0",
0,
false
]
}

View File

@ -131,7 +131,7 @@
</item>
<item type="list">
<item value="DOOR_COMPONENT"/>
<item value="0"/>
<item type="int" value="0"/>
<item type="bool" value="false"/>
</item>
</property>

View File

@ -10,6 +10,7 @@ stdenv.mkDerivation {
];
buildInputs = [
libpng
json_c
sdl3
ncurses
];

View File

@ -20,7 +20,7 @@ SRC_LDFLAGS = -O3
else
SRC_CFLAGS = --std=c17 --pedantic -O1 -g -DDEBUG=2 \
-Wall -Wno-missing-braces -Wextra -Wno-missing-field-initializers \
-Wformat=2 -Wswitch-default -Wswitch-enum -Wcast-align \
-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 \