Mercurial > molko
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 } |