summary refs log tree commit diff
diff options
context:
space:
mode:
authorzlago2024-09-27 18:34:24 +0200
committerzlago2024-09-27 18:34:24 +0200
commite304b0a4acc3f0870f55e6b584c464096333dfdc (patch)
tree9c985b966d758020e0aa0efdd8cbdb69ec716412
parentd3dc2389c308278442831f370950b2d25e5fa734 (diff)
tilemap collision
the 'middle ground' layer is the only layer which is solid,
and the boundary between the background and the foreground

additionally, the maps now can have a custom sky color
-rw-r--r--src/main.c15
-rw-r--r--src/res/untitled.tmx5
-rw-r--r--src/tilemap.c64
-rw-r--r--src/tilemap.h15
-rw-r--r--utl/json2map/main.c50
5 files changed, 128 insertions, 21 deletions
diff --git a/src/main.c b/src/main.c
index 6da4d9a..eccd351 100644
--- a/src/main.c
+++ b/src/main.c
@@ -46,6 +46,7 @@ int main(int argc, char **argv) {
 		goto end;
 	}
 	SDL_RenderSetLogicalSize(renderer, WINDOW_WIDTH, WINDOW_HEIGHT);
+	SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
 	
 	{
 		res_init();
@@ -57,7 +58,7 @@ int main(int argc, char **argv) {
 		}
 		free(a);
 		struct blob map = res_get_map("untitled");
-		tilemap = load_tilemap(map.data, map.size);
+		tilemap = tilemap_load(map.data, map.size);
 		printf("load_tilemap %p\n", (void *) tilemap);
 		SDL_SetRenderTarget(renderer, NULL);
 	}
@@ -125,6 +126,8 @@ int main(int argc, char **argv) {
 				case SDL_MOUSEWHEEL: // the scroll wheel gets rolled
 					//fprintf(stderr, "scrolled by %2i %2i %4.1f %4.1f\n", evt.wheel.x, evt.wheel.y, evt.wheel.preciseX, evt.wheel.preciseY);
 					break;
+				case SDL_CLIPBOARDUPDATE: // annoying
+					break;
 				case SDL_WINDOWEVENT: // window related events
 					switch (evt.window.event) {
 						case SDL_WINDOWEVENT_SHOWN:
@@ -179,9 +182,6 @@ int main(int argc, char **argv) {
 		SDL_SetRenderTarget(renderer, NULL);
 		SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
 		SDL_RenderClear(renderer);
-		SDL_SetRenderDrawColor(renderer, 0, 128, 255, 0);
-		SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
-		SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE);
 
 		x += input_right(input_now) - input_left(input_now);
 		y += input_down(input_now) - input_up(input_now);
@@ -189,16 +189,15 @@ int main(int argc, char **argv) {
 		if (y < 0) {y = 0;} else if (y + WINDOW_HEIGHT > tilemap->height * 8) {y = tilemap->height * 8 - WINDOW_HEIGHT;}
 		
 		//SDL_RenderCopy(renderer, tilemap->wang_tileset, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
-		for (int i = 0; i < tilemap->layers; i++) {
-			SDL_RenderCopy(renderer, tilemap->tilemaps[i], &(SDL_Rect) {x * tilemap->parallax[i].x, y * tilemap->parallax[i].y, WINDOW_WIDTH, WINDOW_HEIGHT}, &(SDL_Rect) {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT});
-		}
+		tilemap_background(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
+		tilemap_foreground(tilemap, x, y, WINDOW_WIDTH, WINDOW_HEIGHT);
 		//SDL_RenderCopy(renderer, res_get_texture("meow").data, &(SDL_Rect) {0, 0, 128, 90}, &(SDL_Rect) {0, 0, 128, 90});
 		// then we wait for the next video frame 
 		SDL_RenderPresent(renderer);
 	}
 	
 	end:
-	free_tilemap(tilemap), tilemap = NULL;
+	tilemap_free(tilemap), tilemap = NULL;
 	SDL_DestroyRenderer(renderer);
 	SDL_DestroyWindow(window);
 	//SDL_QuitSubSystem(INIT_SUBSYSTEMS);
diff --git a/src/res/untitled.tmx b/src/res/untitled.tmx
index 51b506c..6a8bbd0 100644
--- a/src/res/untitled.tmx
+++ b/src/res/untitled.tmx
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="8" tileheight="8" infinite="0" nextlayerid="7" nextobjectid="6">
+<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="30" height="20" tilewidth="8" tileheight="8" infinite="0" backgroundcolor="#63acef" nextlayerid="7" nextobjectid="6">
  <properties>
   <property name="custom 1" value="1234"/>
   <property name="custom 2" type="bool" value="true"/>
@@ -32,6 +32,9 @@
 </data>
  </layer>
  <group id="5" name="Group Layer 1">
+  <properties>
+   <property name="middleground" type="bool" value="true"/>
+  </properties>
   <layer id="1" name="Tile Layer 1" width="30" height="20" offsetx="-4" offsety="-4">
    <data encoding="csv">
 0,0,0,0,0,0,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/src/tilemap.c b/src/tilemap.c
index 84d2509..af2c163 100644
--- a/src/tilemap.c
+++ b/src/tilemap.c
@@ -14,19 +14,40 @@ struct tilemap *tilemap = NULL, *next_tilemap = NULL;
 
 #define PACKED __attribute__((__packed__))
 
+uint8_t const MAGIC[4] = "TMv1";
+
 struct PACKED sets {
+	uint8_t magic[4];
 	uint32_t tilesets_count;
 	uint32_t wang_count;
 };
 
 struct PACKED map {
+	struct {
+		uint8_t r, g, b, a;
+	} backdrop;
 	uint32_t width;
 	uint32_t height;
 	uint32_t layers;
+	uint32_t middleground;
 	uint8_t tiles[];
 };
 
-void free_tilemap(struct tilemap *tilemap) {
+void tilemap_background(struct tilemap *tilemap, int x, int y, int w, int h) {
+	SDL_SetRenderDrawColor(renderer, tilemap->backdrop.r, tilemap->backdrop.g, tilemap->backdrop.b, tilemap->backdrop.a);
+	SDL_RenderFillRect(renderer, &(SDL_Rect) {0, 0, w, h});
+	for (int i = 0; i < tilemap->middleground; i++) {
+		SDL_RenderCopy(renderer, tilemap->tilemaps[i], &(SDL_Rect) {x * tilemap->parallax[i].x, y * tilemap->parallax[i].y, w, h}, &(SDL_Rect) {0, 0, w, h});
+	}
+}
+
+void tilemap_foreground(struct tilemap *tilemap, int x, int y, int w, int h) {
+	for (int i = tilemap->middleground; i < tilemap->layers; i++) {
+		SDL_RenderCopy(renderer, tilemap->tilemaps[i], &(SDL_Rect) {x * tilemap->parallax[i].x, y * tilemap->parallax[i].y, w, h}, &(SDL_Rect) {0, 0, w, h});
+	}
+}
+
+void tilemap_free(struct tilemap *tilemap) {
 	SDL_DestroyTexture(tilemap->tileset);
 	SDL_DestroyTexture(tilemap->wang_tileset);
 	free(tilemap->parallax);
@@ -38,11 +59,23 @@ void free_tilemap(struct tilemap *tilemap) {
 	free(tilemap);
 }
 
-struct tilemap *load_tilemap(void *data, size_t size) {
+struct tilemap *tilemap_load(void *data, size_t size) {
+	size_t const insize = size;
+
+	struct sets *const sets = data;
+	data = sets + 1;
+	size -= sizeof (struct sets);
+
+	if (memcmp(sets->magic, MAGIC, sizeof (MAGIC)) != 0) {
+		fprintf(stderr, "error: unsupported level format (got '%.4s' expected '%.4s')\n", sets->magic, MAGIC);
+		return NULL;
+	}
+
 	struct tilemap *tilemap = malloc(sizeof (struct tilemap));
 	if (tilemap == NULL) {
 		return NULL;
 	}
+
 	tilemap->tileset = SDL_CreateTexture(renderer, SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, 128, 128);
 	tilemap->wang_tileset = SDL_CreateTexture(renderer, SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, 128, 128);
 	SDL_SetTextureBlendMode(tilemap->wang_tileset, SDL_BLENDMODE_BLEND);
@@ -51,9 +84,6 @@ struct tilemap *load_tilemap(void *data, size_t size) {
 	tilemap->collision = NULL;
 	tilemap->tilemaps = NULL;
 
-	struct sets *const sets = data;
-	data = sets + 1;
-	size -= sizeof (struct sets);
 	char *str = data;
 	int y = 0;
 	SDL_SetRenderTarget(renderer, tilemap->tileset);
@@ -95,7 +125,7 @@ struct tilemap *load_tilemap(void *data, size_t size) {
 		str += sizeof (uint32_t);
 		size_t len = strnlen(str, size);
 		if (len == size) {
-			free_tilemap(tilemap);
+			tilemap_free(tilemap);
 			return NULL;
 		}
 		void *tex = res_get_texture(str).data;
@@ -117,11 +147,29 @@ struct tilemap *load_tilemap(void *data, size_t size) {
 		goto fail;
 	}
 
+	tilemap->backdrop.r = map->backdrop.r;
+	tilemap->backdrop.g = map->backdrop.g;
+	tilemap->backdrop.b = map->backdrop.b;
+	tilemap->backdrop.a = map->backdrop.a;
 	tilemap->width = map->width;
 	tilemap->height = map->height;
 	tilemap->layers = map->layers;
+	tilemap->middleground = map->middleground;
 	tilemap->tilemaps = malloc(sizeof (void *) * tilemap->layers);
 	
+	if (tilemap->middleground > tilemap->layers) {
+		goto fail;
+	} else if (tilemap->middleground == 0) {
+		fputs("warn: map has no middle ground\n", stderr);
+		tilemap->collision = calloc(tilemap->width, tilemap->height * sizeof (collision_T));
+	} else {
+		tilemap->collision = malloc(tilemap->width * tilemap->height * sizeof (collision_T));
+		size_t const ll = (tilemap->middleground - 1) * map->width * map->height;
+		for (size_t i = 0; i < tilemap->width * tilemap->height; i++) {
+			tilemap->collision[i] = collision[map->tiles[i + ll]];
+		}
+	}
+	
 	for (int l = 0; l < tilemap->layers; l++) {
 		SDL_Texture *layer = SDL_CreateTexture(renderer, SDL_PIXELTYPE_UNKNOWN, SDL_TEXTUREACCESS_TARGET, map->width * 8, map->height * 8);
 		SDL_SetTextureBlendMode(layer, SDL_BLENDMODE_BLEND);
@@ -170,11 +218,13 @@ struct tilemap *load_tilemap(void *data, size_t size) {
 
 	size -= sizeof (struct parallax) * map->layers;
 	
+	tilemap->input_bytes = insize - size;
+	//fprintf(stderr, "size: %zuB remaining: %zuB total: %zuB\n", tilemap->input_bytes, size, insize);
 	SDL_SetRenderTarget(renderer, NULL);
 	return tilemap;
 	
 	fail:
-	free_tilemap(tilemap);
+	tilemap_free(tilemap);
 	SDL_SetRenderTarget(renderer, NULL);
 	return NULL;
 }
diff --git a/src/tilemap.h b/src/tilemap.h
index 587bdf6..912b67f 100644
--- a/src/tilemap.h
+++ b/src/tilemap.h
@@ -4,17 +4,24 @@
 extern struct tilemap {
 	void *tileset;
 	void *wang_tileset;
+	struct {
+		unsigned char r, g, b, a;
+	} backdrop;
 	unsigned width;
 	unsigned height;
 	unsigned layers;
-	unsigned behind;
+	unsigned middleground;
 	struct parallax {
 		float x, y;
 	} *parallax;
 	collision_T *collision;
 	void **tilemaps;
+	size_t input_bytes;
 } *tilemap, *next_tilemap;
 
-void init_tilemap(void);
-void free_tilemap(struct tilemap *tilemap);
-struct tilemap *load_tilemap(void *data, size_t size);
+// render the fore/back ground of the tilemap to `renderer`
+void tilemap_background(struct tilemap *tilemap, int x, int y, int w, int h);
+void tilemap_foreground(struct tilemap *tilemap, int x, int y, int w, int h);
+
+void tilemap_free(struct tilemap *tilemap);
+struct tilemap *tilemap_load(void *data, size_t size);
diff --git a/utl/json2map/main.c b/utl/json2map/main.c
index f3e7716..b298626 100644
--- a/utl/json2map/main.c
+++ b/utl/json2map/main.c
@@ -12,15 +12,22 @@ struct tilemap_T {
 
 #define PACKED __attribute__((__packed__))
 
+#define MAGIC "TMv1"
+
 struct PACKED sets {
+	uint8_t magic[4];
 	uint32_t tilesets_count;
 	uint32_t wang_count;
 };
 
 struct PACKED map {
+	struct {
+		uint8_t r, g, b, a;
+	} backdrop;
 	uint32_t width;
 	uint32_t height;
 	uint32_t layers;
+	uint32_t middleground;
 	uint8_t tiles[];
 };
 
@@ -119,7 +126,7 @@ int main(int argc, char **argv) {
 	uint32_t wang_height;
 	char *tilesets_data = NULL;
 	size_t tilesets_size = 0;
-	struct sets counts = {0, 0};
+	struct sets counts = {MAGIC, 0, 0};
 	
 	cJSON_ArrayForEach(tileset, tilesets) {
 		//printf("=== tileset (%% tiles) ===\n");
@@ -217,12 +224,39 @@ int main(int argc, char **argv) {
 		return 1;
 	}
 	struct map map = {
+		.backdrop = {0x9f, 0x9f, 0x9f, 0xff},
 		.width = width_obj->valueint - 1,
 		.height = height_obj->valueint - 1,
 		.layers = 0,
+		.middleground = 0,
 	};
 	uint8_t *tile_data = NULL;
 	float *parallaxes = NULL;
+
+	cJSON const *backdrop = cJSON_GetObjectItemCaseSensitive(json, "backgroundcolor");
+	if (cJSON_IsString(backdrop)) {
+		switch (strlen(backdrop->valuestring)) {
+			unsigned value;
+			case 9:
+				value = strtoul(backdrop->valuestring + 1, NULL, 16);
+				map.backdrop.r = value >> 16;
+				map.backdrop.g = value >> 8;
+				map.backdrop.b = value >> 0;
+				map.backdrop.a = value >> 24;
+				break;
+			case 7:
+				value = strtoul(backdrop->valuestring + 1, NULL, 16);
+				map.backdrop.r = value >> 16;
+				map.backdrop.g = value >> 8;
+				map.backdrop.b = value >> 0;
+				map.backdrop.a = 0xff;
+				break;
+			default:
+				fputs("incorrect backdrop color format\n", stderr);
+				return 1;
+		}
+	}
+	//printf("sky: # %02x %02x %02x %02x\n", map.backdrop.r, map.backdrop.g, map.backdrop.b, map.backdrop.a);
 	
 	cJSON const *layers = cJSON_GetObjectItemCaseSensitive(json, "layers");
 	cJSON const *layer = NULL;
@@ -334,6 +368,20 @@ int main(int argc, char **argv) {
 		} else {
 			// ??? layer
 		}
+
+		cJSON const *properties = cJSON_GetObjectItemCaseSensitive(layer, "properties");
+		cJSON const *property = NULL;
+		cJSON_ArrayForEach (property, properties) {
+			char const *const name = cJSON_GetObjectItemCaseSensitive(property, "name")->valuestring;
+			if (strcmp(name, "middleground") == 0) {
+				if (cJSON_IsTrue(cJSON_GetObjectItemCaseSensitive(property, "value"))) {
+					map.middleground = map.layers;
+				}
+			} else {
+				printf("unknown property '%s'\n", name);
+				return 1;
+			}
+		}
 	}
 	
 	fwrite(&counts, 1, sizeof (counts), outfile);