changeset 27:607bd90aba63

core: finalize map converter and opener, closes #2448 @6h
author David Demelier <markand@malikania.fr>
date Sun, 12 Jan 2020 21:04:49 +0100
parents 65398df5fb5c
children 783841af4033
files Makefile src/main.c src/map.c src/map.h src/sprite.c src/sprite.h tools/molko-map.c
diffstat 7 files changed, 257 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Sun Jan 12 21:01:10 2020 +0100
+++ b/Makefile	Sun Jan 12 21:04:49 2020 +0100
@@ -18,14 +18,15 @@
 
 .POSIX:
 
-CC=             clang
-CFLAGS=         -MMD -O3 -DNDEBUG -std=c18 -Wall -Wextra
+CC=             gcc
+CFLAGS=         -MMD -O3 -DNDEBUG -std=c18 -Wall -Wextra -g
 PROG=           molko
 LIB=            libmolko.a
 SRCS=           src/animation.c \
                 src/clock.c \
                 src/event.c \
                 src/font.c \
+                src/map.c \
                 src/message.c \
                 src/image.c \
                 src/sprite.c \
--- a/src/main.c	Sun Jan 12 21:01:10 2020 +0100
+++ b/src/main.c	Sun Jan 12 21:04:49 2020 +0100
@@ -24,22 +24,32 @@
 #include "event.h"
 #include "font.h"
 #include "image.h"
+#include "map.h"
 #include "message.h"
 #include "sprite.h"
 #include "sys.h"
 #include "texture.h"
 #include "window.h"
 
+#include <SDL.h>
+
 int
 main(int argc, char **argv)
 {
 	(void)argc;
 	(void)argv;
 
+	struct map map;
 	struct font *font;
 
 	sys_init();
-	window_init("Molko's Adventure", 1280, 720);
+	if (!window_init("Molko's Adventure", 1280, 720)) {
+		printf("%s\n", SDL_GetError());
+		exit(1);
+	}
+
+	if (!map_open(&map, "default.map"))
+		exit(1);
 
 	if (!(font = font_openf("assets/fonts/DejaVuSansCondensed.ttf", 12)))
 		exit(1);
@@ -76,12 +86,17 @@
 
 		window_set_color(0x667788ff);
 		window_clear();
+#if 0
 		message_update(&welcome, elapsed);
 		message_draw(&welcome);
+#endif
+		map_draw(&map);
 		window_present();
 	}
 
 	sys_close();
+	map_close(&map);
+	font_close(font);
 
 	return 0;
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/map.c	Sun Jan 12 21:04:49 2020 +0100
@@ -0,0 +1,165 @@
+/*
+ * map.c -- game map
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "map.h"
+#include "image.h"
+#include "texture.h"
+#include "sprite.h"
+
+#include <SDL.h>
+
+#define MAXLEN(v) STRINGIFY(v)
+#define STRINGIFY(v) "%" #v "s"
+
+static void
+parse_layer(struct map *map, const char *line, FILE *fp)
+{
+	char layer_name[32];
+	struct map_layer *layer;
+	size_t amount, current;
+
+	/* Determine layer. */
+	if (sscanf(line, "layer|%32s", layer_name) <= 0)
+		return;
+	if (strcmp(layer_name, "background") == 0)
+		layer = &map->layers[0];
+	else if (strcmp(layer_name, "foreground") == 0)
+		layer = &map->layers[1];
+	else
+		return;
+
+	/* Check if weight/height has been specified. */
+	if (map->width == 0 || map->height == 0)
+		return;
+
+	amount = map->width * map->height;
+	current = 0;
+	if (!(layer->tiles = calloc(amount, sizeof (uint16_t))))
+		return;
+
+	for (int tile; fscanf(fp, "%d", &tile) && current < amount; ++current)
+		layer->tiles[current] = tile;
+}
+
+static void
+parse_tileset(struct map *map, const char *line)
+{
+	char filename[128 + 1] = { 0 };
+	char path[512] = { 0 };
+
+	sscanf(line, "tileset|%128s", filename);
+	snprintf(path, sizeof (path), "assets/tilesets/%s", filename);
+
+	if (!(map->tileset = image_openf(path)))
+		return;
+
+	sprite_init(&map->sprite, map->tileset, map->tilewidth, map->tileheight);
+}
+
+static void
+parse(struct map *map, const char *line, FILE *fp)
+{
+	if (strncmp(line, "title", 5) == 0)
+		sscanf(line, "title|" MAXLEN(MAP_TITLE_MAX), map->title);
+	else if (strncmp(line, "width", 5) == 0)
+		sscanf(line, "width|%hu", &map->width);
+	else if (strncmp(line, "height", 6) == 0)
+		sscanf(line, "height|%hu", &map->height);
+	else if (strncmp(line, "tilewidth", 9) == 0)
+		sscanf(line, "tilewidth|%hhu", &map->tilewidth);
+	else if (strncmp(line, "tileheight", 10) == 0)
+		sscanf(line, "tileheight|%hhu", &map->tileheight);
+	else if (strncmp(line, "tileset", 7) == 0)
+		parse_tileset(map, line);
+	else if (strncmp(line, "layer", 5) == 0)
+		parse_layer(map, line, fp);
+}
+
+static void
+draw_layer(struct map *map, const struct map_layer *layer)
+{
+	assert(map);
+	assert(layer);
+
+	int16_t x = 0, y = 0;
+
+	for (uint16_t r = 0; r < map->width; ++r) {
+		for (uint16_t c = 0; c < map->height; ++c) {
+			size_t si = r * map->width + c;
+			size_t sr = (layer->tiles[si] - 1) / map->sprite.ncols;
+			size_t sc = (layer->tiles[si] - 1) % map->sprite.nrows;
+
+			if (layer->tiles[si] != 0)
+				sprite_draw(&map->sprite, sr, sc, x, y);
+
+			x += map->tilewidth;
+		}
+
+		x = 0;
+		y += map->tileheight;
+	}
+}
+
+bool
+map_open(struct map *map, const char *path)
+{
+	assert(map);
+	assert(path);
+
+	memset(map, 0, sizeof (struct map));
+
+	FILE *fp = fopen(path, "r");
+	char line[BUFSIZ];
+
+	if (!fp)
+		return false;
+
+	while (fgets(line, sizeof (line), fp)) {
+		/* Remove \n if any */
+		line[strcspn(line, "\n")] = '\0';
+		parse(map, line, fp);
+	}
+
+	fclose(fp);
+
+	return true;
+}
+
+void
+map_draw(struct map *map)
+{
+	draw(map, &map->layers[0]);
+	draw(map, &map->layers[1]);
+}
+
+void
+map_close(struct map *map)
+{
+	assert(map);
+
+	if (map->tileset)
+		texture_close(map->tileset);
+
+	free(map->layers[0].tiles);
+	free(map->layers[1].tiles);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/map.h	Sun Jan 12 21:04:49 2020 +0100
@@ -0,0 +1,57 @@
+/*
+ * map.h -- game map
+ *
+ * Copyright (c) 2020 David Demelier <markand@malikania.fr>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MOLKO_MAP_H
+#define MOLKO_MAP_H
+
+/**
+ * \file map.h
+ * \brief Game map.
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "sprite.h"
+
+#define MAP_TITLE_MAX   32
+
+struct texture;
+
+struct map_layer {
+	uint16_t *tiles;
+};
+
+struct map {
+	char title[MAP_TITLE_MAX];
+	struct texture *tileset;
+	struct sprite sprite;
+	uint16_t width;
+	uint16_t height;
+	uint8_t tilewidth;
+	uint8_t tileheight;
+	struct map_layer layers[2];
+};
+
+bool
+map_open(struct map *map, const char *path);
+
+void
+map_close(struct map *map);
+
+#endif /* !MOLKO_MAP_H */
--- a/src/sprite.c	Sun Jan 12 21:01:10 2020 +0100
+++ b/src/sprite.c	Sun Jan 12 21:04:49 2020 +0100
@@ -23,7 +23,7 @@
 #include "texture.h"
 
 void
-sprite_init(struct sprite *sprite, struct texture *tex, uint16_t cellw, uint16_t cellh)
+sprite_init(struct sprite *sprite, struct texture *tex, uint8_t cellw, uint8_t cellh)
 {
 	int w = 0;
 	int h = 0;
--- a/src/sprite.h	Sun Jan 12 21:01:10 2020 +0100
+++ b/src/sprite.h	Sun Jan 12 21:04:49 2020 +0100
@@ -33,8 +33,8 @@
  */
 struct sprite {
 	struct texture *texture;        /*!< Texture to access (RO) */
-	uint16_t cellw;                 /*!< Width per cell (RW) */
-	uint16_t cellh;                 /*!< Height per cell (RW) */
+	uint8_t cellw;                 /*!< Width per cell (RW) */
+	uint8_t cellh;                 /*!< Height per cell (RW) */
 	uint16_t nrows;                 /*!< Number of rows (RW) */
 	uint16_t ncols;                 /*!< Number of columns (RW) */
 };
@@ -61,8 +61,8 @@
 void
 sprite_init(struct sprite *sprite,
             struct texture *tex,
-            uint16_t cellw,
-            uint16_t cellh);
+            uint8_t cellw,
+            uint8_t cellh);
 
 /**
  * Draw the sprite component from row `r' and column `c'.
--- a/tools/molko-map.c	Sun Jan 12 21:01:10 2020 +0100
+++ b/tools/molko-map.c	Sun Jan 12 21:04:49 2020 +0100
@@ -75,16 +75,24 @@
 static void
 write_metadata(const json_t *document)
 {
+	json_t *width = json_object_get(document, "width");
 	json_t *height = json_object_get(document, "height");
-	json_t *width = json_object_get(document, "width");
+	json_t *tilewidth = json_object_get(document, "tilewidth");
+	json_t *tileheight = json_object_get(document, "tileheight");
 
+	if (!width || !json_is_integer(width))
+		die("missing 'width' property\n");
 	if (!height || !json_is_integer(height))
 		die("missing 'height' property\n");
-	if (!width || !json_is_integer(width))
-		die("missing 'width' property\n");
+	if (!tilewidth || !json_is_integer(tilewidth))
+		die("missing 'tilewidth' property\n");
+	if (!tileheight || !json_is_integer(tileheight))
+		die("missing 'tileheight' property\n");
 
 	printf("width|%lld\n", json_integer_value(width));
 	printf("height|%lld\n", json_integer_value(height));
+	printf("tilewidth|%lld\n", json_integer_value(tilewidth));
+	printf("tileheight|%lld\n", json_integer_value(tileheight));
 }
 
 static void