From 933ee23bd3f97b9fc45a36ad8e3f75fea45d6202 Mon Sep 17 00:00:00 2001 From: KikooDX Date: Thu, 18 Mar 2021 18:30:36 +0100 Subject: [PATCH] Level read and write. --- .gitignore | 3 ++ CMakeLists.txt | 2 +- include/level.h | 4 +++ src/level.c | 90 ++++++++++++++++++++++++++++++++++++++++++------- src/main.c | 5 +-- 5 files changed, 89 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 567609b..3f0c725 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,4 @@ build/ + +# KBLE (Zig) files +backup_*.kble diff --git a/CMakeLists.txt b/CMakeLists.txt index 08e4796..2c3ff4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,4 +14,4 @@ target_compile_options(${PROJECT_NAME} PRIVATE -Wunreachable-code -Wstrict-prototypes -Wmissing-prototypes -Wold-style-definition -Werror-implicit-function-declaration -ansi -pedantic-errors -g -Os) -target_link_libraries(${PROJECT_NAME} raylib) +#target_link_libraries(${PROJECT_NAME} raylib) diff --git a/include/level.h b/include/level.h index 997da33..835cf16 100644 --- a/include/level.h +++ b/include/level.h @@ -1,3 +1,6 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* Copyright (C) 2021 KikooDX */ + #pragma once struct Level { @@ -8,3 +11,4 @@ struct Level { void level_read(struct Level*, char *path); void level_free(struct Level*); +void level_write(struct Level level, char *path); diff --git a/src/level.c b/src/level.c index 188d6e1..19668ae 100644 --- a/src/level.c +++ b/src/level.c @@ -10,13 +10,13 @@ static const int kble_fmt_version = 0; static int read_byte(FILE *file); -static int read_byte_group(FILE *file, int number); +static int read_byte_group(FILE *file, int size); +static void write_byte(FILE *file, unsigned char byte); +static void write_byte_group(FILE *file, int value, int size); void level_read(struct Level *level, char *path) { FILE *file = NULL; int byte = 0; - int width = 0; - int height = 0; int tile_size = 0; int level_size = 0; int tile = 0; @@ -25,7 +25,7 @@ void level_read(struct Level *level, char *path) { /* open file in read mode */ file = fopen(path, "rb"); if (file == NULL) { - fprintf(stderr, "ERROR: Cannot open input file %s\n", path); + fprintf(stderr, "ERROR: cannot open input file %s\n", path); exit(EXIT_FAILURE); } @@ -40,12 +40,12 @@ void level_read(struct Level *level, char *path) { /* get tile size (in bytes) */ tile_size = read_byte(file); /* get width */ - width = read_byte_group(file, 2); + level->width = read_byte_group(file, 2); /* get height */ - height = read_byte_group(file, 2); + level->height = read_byte_group(file, 2); /* allocate memory for data */ - level_size = width * height; + level_size = level->width * level->height; if (level->data == NULL) { level->data = malloc(level_size * sizeof(int)); } else { @@ -71,9 +71,52 @@ void level_free(struct Level *level) { free(level->data); } -/* Read a single byte safely (handles EOF). */ +void level_write(struct Level level, char *path) { + FILE *file = NULL; + int tile = 0; + int tile_size = 0; + int max_tile_size = 1; + int i = 0; + const int level_size = level.width * level.height; + + /* open file in write mode */ + file = fopen(path, "wb"); + if (file == NULL) { + fprintf(stderr, "ERROR: cannot open output file %s\n", path); + exit(EXIT_FAILURE); + } + + /* find longest value in data (in bytes) */ + for (i = 0; i < level_size; i += 1) { + tile = level.data[i]; + tile_size = 1; + while (tile >>= 8) + tile_size += 1; + if (tile_size > max_tile_size) + max_tile_size = tile_size; + } + + /* write KBLE format version */ + write_byte(file, kble_fmt_version); + /* write tile size (in bytes) */ + write_byte(file, max_tile_size); + /* write width */ + write_byte_group(file, level.width, 2); + /* write height */ + write_byte_group(file, level.height, 2); + + /* write level content */ + for (i = 0; i < level_size; i += 1) { + write_byte_group(file, level.data[i], max_tile_size); + } + + /* close file */ + fclose(file); +} + +/* Read a single byte safely (handle EOF). */ static int read_byte(FILE *file) { - const int byte = getc(file); + const int byte = fgetc(file); if (byte == EOF) { fprintf(stderr, "ERROR: unexpected EOF\n"); exit(EXIT_FAILURE); @@ -82,15 +125,38 @@ static int read_byte(FILE *file) { } /* Read multiple bytes and "merge" them into one integer. */ -static int read_byte_group(FILE *file, int number) { +static int read_byte_group(FILE *file, int size) { int byte = 0; int merged = 0; int i = 0; - int shift = number * 8; - for (i = 0; i < number; i += 1) { + int shift = size * 8; + for (i = 0; i < size; i += 1) { shift -= 8; byte = read_byte(file); merged |= byte << shift; } return merged; } + +/* Write a single byte safely (handle EOF). */ +static void write_byte(FILE *file, unsigned char byte) { + const int result = fputc(byte, file); + if (result == EOF) { + fprintf(stderr, "ERROR: file write error\n"); + exit(EXIT_FAILURE); + } +} + +/* Write an integer as multiple bytes. */ +static void write_byte_group(FILE *file, int value, int size) { + int byte = 0; + int shift = size * 8; + int i = 0; + const int mask = (1 << 8) - 1; + for (i = 0; i < size; i += 1) { + shift -= 8; + byte = value >> shift; + byte &= mask; + write_byte(file, byte); + } +} diff --git a/src/main.c b/src/main.c index 7da20ee..79e4c38 100644 --- a/src/main.c +++ b/src/main.c @@ -10,12 +10,13 @@ int main(int argc, char **argv) { struct Level level; level.data = NULL; - if (argc != 2) { - fprintf(stderr, "ERROR: expected 1 argument, got %d\n", argc-1); + if (argc != 3) { + fprintf(stderr, "ERROR: expected 2 argument, got %d\n", argc-1); return EXIT_FAILURE; } level_read(&level, argv[1]); + level_write(level, argv[2]); level_free(&level); return EXIT_SUCCESS;