comparison librpg/rpg/map.c @ 148:c577c15df07f

misc: split libraries, closes #2496
author David Demelier <markand@malikania.fr>
date Thu, 15 Oct 2020 10:32:18 +0200
parents libcore/core/map.c@c679e08b32b2
children aab824406d3d
comparison
equal deleted inserted replaced
147:b386d25832c8 148:c577c15df07f
1 /*
2 * map.c -- game map
3 *
4 * Copyright (c) 2020 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #include <core/error.h>
25 #include <core/error_p.h>
26 #include <core/image.h>
27 #include <core/painter.h>
28 #include <core/sprite.h>
29 #include <core/sys.h>
30 #include <core/texture.h>
31 #include <core/window.h>
32
33 #include "map.h"
34
35 /* Create %<v>c string literal for scanf */
36 #define MAX_F(v) MAX_F_(v)
37 #define MAX_F_(v) "%" #v "c"
38
39 static void
40 parse_layer(struct map_data *data, const char *line, FILE *fp)
41 {
42 char layer_name[32 + 1] = { 0 };
43 struct map_layer *layer;
44 size_t amount, current;
45
46 /* Determine layer. */
47 if (sscanf(line, "layer|%32s", layer_name) <= 0)
48 return;
49 if (strcmp(layer_name, "background") == 0)
50 layer = &data->layers[0];
51 else if (strcmp(layer_name, "foreground") == 0)
52 layer = &data->layers[1];
53 else
54 return;
55
56 /* Check if weight/height has been specified. */
57 if (data->w == 0 || data->h == 0)
58 return;
59
60 amount = data->w * data->h;
61 current = 0;
62
63 if (!(layer->tiles = calloc(amount, sizeof (unsigned short))))
64 return;
65
66 for (int tile; fscanf(fp, "%d", &tile) && current < amount; ++current)
67 layer->tiles[current] = tile;
68 }
69
70 static void
71 parse(struct map_data *data, const char *line, FILE *fp)
72 {
73 if (strncmp(line, "title", 5) == 0)
74 sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), data->title);
75 else if (strncmp(line, "width", 5) == 0)
76 sscanf(line, "width|%u", &data->w);
77 else if (strncmp(line, "height", 6) == 0)
78 sscanf(line, "height|%u", &data->h);
79 else if (strncmp(line, "tilewidth", 9) == 0)
80 sscanf(line, "tilewidth|%hu", &data->tile_w);
81 else if (strncmp(line, "tileheight", 10) == 0)
82 sscanf(line, "tileheight|%hu", &data->tile_h);
83 else if (strncmp(line, "origin", 6) == 0)
84 sscanf(line, "origin|%d|%d", &data->origin_x, &data->origin_y);
85 else if (strncmp(line, "tileset", 7) == 0)
86 sscanf(line, "tileset|" MAX_F(MAP_TILESET_MAX), data->tileset);
87 else if (strncmp(line, "layer", 5) == 0)
88 parse_layer(data, line, fp);
89 }
90
91 static bool
92 check(struct map_data *data)
93 {
94 if (strlen(data->title) == 0)
95 return error_printf("data has no title");
96 if (data->w == 0 || data->h == 0)
97 return error_printf("data has null sizes");
98 if (data->tile_w == 0 || data->tile_h == 0)
99 return error_printf("data has null tile sizes");
100 if (!data->layers[0].tiles || !data->layers[1].tiles)
101 return error_printf("could not allocate data");
102
103 return true;
104 }
105
106 static void
107 draw_layer(struct map *map, const struct map_layer *layer)
108 {
109 assert(map);
110 assert(layer);
111
112 struct sprite sprite;
113 int x = 0, y = 0;
114
115 sprite_init(&sprite, map->tileset, map->data->tile_w, map->data->tile_h);
116
117 for (unsigned int r = 0; r < map->data->w; ++r) {
118 for (unsigned int c = 0; c < map->data->h; ++c) {
119 unsigned int si = r * map->data->w + c;
120 unsigned int sr = (layer->tiles[si] - 1) / sprite.ncols;
121 unsigned int sc = (layer->tiles[si] - 1) % sprite.nrows;
122
123 if (layer->tiles[si] != 0)
124 sprite_draw(&sprite, sr, sc, x, y);
125
126 x += map->data->tile_w;
127 }
128
129 x = 0;
130 y += map->data->tile_h;
131 }
132 }
133
134 bool
135 map_data_open_fp(struct map_data *data, FILE *fp)
136 {
137 assert(data);
138
139 char line[1024];
140
141 if (!fp)
142 return false;
143
144 memset(data, 0, sizeof (*data));
145
146 while (fgets(line, sizeof (line), fp)) {
147 /* Remove \n if any */
148 line[strcspn(line, "\n")] = '\0';
149 parse(data, line, fp);
150 }
151
152 fclose(fp);
153
154 if (!check(data)) {
155 map_data_finish(data);
156 return false;
157 }
158
159 /* Compute real size. */
160 data->real_w = data->w * data->tile_w;
161 data->real_h = data->h * data->tile_h;
162
163 return true;
164 }
165
166 bool
167 map_data_open(struct map_data *data, const char *path)
168 {
169 assert(data);
170 assert(path);
171
172 return map_data_open_fp(data, fopen(path, "r"));
173 }
174
175 bool
176 map_data_openmem(struct map_data *data, const void *buf, size_t bufsz)
177 {
178 assert(data);
179 assert(buf);
180
181 return map_data_open_fp(data, fmemopen((void *)buf, bufsz, "r"));
182 }
183
184 void
185 map_data_finish(struct map_data *data)
186 {
187 assert(data);
188
189 free(data->layers[0].tiles);
190 free(data->layers[1].tiles);
191
192 memset(data, 0, sizeof (*data));
193 }
194
195 bool
196 map_init(struct map *map, struct map_data *data, struct texture *tileset)
197 {
198 assert(map);
199 assert(data);
200 assert(tileset && texture_ok(tileset));
201
202 if (!(texture_new(&map->picture, data->real_w, data->real_h)))
203 return false;
204
205 map->data = data;
206 map->tileset = tileset;
207
208 map_repaint(map);
209
210 return true;
211 }
212
213 void
214 map_draw(struct map *map, int srcx, int srcy)
215 {
216 texture_scale(&map->picture, srcx, srcy, window.w, window.h,
217 0, 0, window.w, window.h, 0.0);
218 }
219
220 void
221 map_repaint(struct map *map)
222 {
223 PAINTER_BEGIN(&map->picture);
224 draw_layer(map, &map->data->layers[0]);
225 draw_layer(map, &map->data->layers[1]);
226 PAINTER_END();
227 }
228
229 void
230 map_finish(struct map *map)
231 {
232 assert(map);
233
234 texture_finish(&map->picture);
235
236 memset(map, 0, sizeof (*map));
237 }