1 /*
2  * File: grafmode.c
3  * Purpose: load a list of possible graphics modes.
4  *
5  * Copyright (c) 2011 Brett Reid
6  *
7  * This work is free software; you can redistribute it and/or modify it
8  * under the terms of:
9  *
10  * b) the "Angband license":
11  *    This software may be copied and distributed for educational, research,
12  *    and not for profit purposes provided that this copyright and statement
13  *    are included in all such copies.  Other copyrights may also apply.
14  */
15 
16 #include "c-angband.h"
17 #include "grafmode.h"
18 #include "../common/parser.h"
19 
20 /* Forward-compatibility with V4XX */
21 #define mem_zalloc ralloc
22 #define mem_free rnfree
23 /* XXX */
24 
25 graphics_mode *graphics_modes = NULL;
26 graphics_mode *current_graphics_mode = NULL;
27 int graphics_mode_high_id = 0;
28 int num_graphics_modes = 0;
29 
parse_graf_n(struct parser * p)30 static enum parser_error parse_graf_n(struct parser *p) {
31 	int i;
32 	graphics_mode *list = parser_priv(p);
33 	graphics_mode *mode = malloc(sizeof(graphics_mode));
34 	if (!mode) {
35 		return PARSE_ERROR_OUT_OF_MEMORY;
36 	}
37 	mode->pNext = list;
38 	mode->grafID = parser_getuint(p, "index");
39 	strncpy(mode->menuname, parser_getstr(p, "menuname"), 32);
40 
41 	mode->alphablend = 0;
42 	mode->overdrawRow = 0;
43 	mode->overdrawMax = 0;
44 	strncpy(mode->file, "", 32);
45 
46 	strncpy(mode->pref, "none", 32);
47 
48 	/* MAngband-specific properties: */
49 	strncpy(mode->mask, "", 32);
50 	mode->transparent = 0;
51 	mode->lightmap = 0;
52 	for (i = 0; i < 4; i++) {
53 		mode->light_offset[i][0] = 0;
54 		mode->light_offset[i][1] = 0;
55 	}
56 	parser_setpriv(p, mode);
57 	return PARSE_ERROR_NONE;
58 }
59 
parse_graf_i(struct parser * p)60 static enum parser_error parse_graf_i(struct parser *p) {
61 	graphics_mode *mode = parser_priv(p);
62 	if (!mode) {
63 		return PARSE_ERROR_INVALID_VALUE;
64 	}
65 	mode->cell_width = parser_getuint(p, "wid");
66 	mode->cell_height = parser_getuint(p, "hgt");
67 	strncpy(mode->file, parser_getstr(p, "filename"), 32);
68 	return PARSE_ERROR_NONE;
69 }
70 
parse_graf_m(struct parser * p)71 static enum parser_error parse_graf_m(struct parser *p) {
72 	graphics_mode *mode = parser_priv(p);
73 	if (!mode) {
74 		return PARSE_ERROR_INVALID_VALUE;
75 	}
76 	strncpy(mode->mask, parser_getstr(p, "filename"), 32);
77 	return PARSE_ERROR_NONE;
78 }
79 
parse_graf_p(struct parser * p)80 static enum parser_error parse_graf_p(struct parser *p) {
81 	graphics_mode *mode = parser_priv(p);
82 	if (!mode) {
83 		return PARSE_ERROR_INVALID_VALUE;
84 	}
85 	strncpy(mode->pref, parser_getstr(p, "prefname"), 32);
86 	return PARSE_ERROR_NONE;
87 }
88 
parse_graf_x(struct parser * p)89 static enum parser_error parse_graf_x(struct parser *p) {
90 	graphics_mode *mode = parser_priv(p);
91 	if (!mode) {
92 		return PARSE_ERROR_INVALID_VALUE;
93 	}
94 	mode->alphablend = parser_getuint(p, "alpha");
95 	mode->overdrawRow = parser_getuint(p, "row");
96 	mode->overdrawMax = parser_getuint(p, "max");
97 	return PARSE_ERROR_NONE;
98 }
99 
parse_graf_t(struct parser * p)100 static enum parser_error parse_graf_t(struct parser *p) {
101 	graphics_mode *mode = parser_priv(p);
102 	if (!mode) {
103 		return PARSE_ERROR_INVALID_VALUE;
104 	}
105 	mode->transparent = parser_getuint(p, "transparent");
106 	mode->lightmap    = parser_getuint(p, "lightmap");
107 	if (!mode->transparent) mode->lightmap = 0;
108 	return PARSE_ERROR_NONE;
109 }
110 
parse_graf_l(struct parser * p)111 static enum parser_error parse_graf_l(struct parser *p) {
112 	graphics_mode *mode = parser_priv(p);
113 	u32b level;
114 	if (!mode) {
115 		return PARSE_ERROR_INVALID_VALUE;
116 	}
117 	level = parser_getuint(p, "level");
118 	if (level > 3) {
119 		return PARSE_ERROR_INVALID_VALUE;
120 	}
121 	mode->light_offset[level][0] = parser_getuint(p, "yoffset");
122 	mode->light_offset[level][1] = parser_getuint(p, "xoffset");
123 	return PARSE_ERROR_NONE;
124 }
125 
init_parse_grafmode(void)126 static struct parser *init_parse_grafmode(void) {
127 	struct parser *p = parser_new();
128 	parser_setpriv(p, NULL);
129 
130 	parser_reg(p, "V sym version", ignored);
131 	parser_reg(p, "N uint index str menuname", parse_graf_n);
132 	parser_reg(p, "I uint wid uint hgt str filename", parse_graf_i);
133 	parser_reg(p, "M str maskfilename", parse_graf_m);
134 	parser_reg(p, "P str prefname", parse_graf_p);
135 	parser_reg(p, "X uint alpha uint row uint max", parse_graf_x);
136 	parser_reg(p, "T uint transparent uint lightmap", parse_graf_t);
137 	parser_reg(p, "L uint level int yoffset int xoffset", parse_graf_l);
138 
139 	return p;
140 }
141 
finish_parse_grafmode(struct parser * p)142 errr finish_parse_grafmode(struct parser *p) {
143 	graphics_mode *mode, *n;
144 	int max = 0;
145 	int count = 0;
146 	int i;
147 
148 	/* see how many graphics modes we have and what the highest index is */
149 	if (p) {
150 		mode = parser_priv(p);
151 		while (mode) {
152 			if (mode->grafID > max) {
153 				max = mode->grafID;
154 			}
155 			count++;
156 			mode = mode->pNext;
157 		}
158 	}
159 
160 	/* copy the loaded modes to the global variable */
161 	graphics_modes = realloc(graphics_modes, sizeof(graphics_mode) * (count+1+num_graphics_modes));
162 	for (i = 0; i < num_graphics_modes; i++) {
163 		graphics_modes[i].pNext = &(graphics_modes[i+1]);
164 	}
165 	if (p) {
166 		mode = parser_priv(p);
167 		for (i = count-1; i >= 0; i--, mode = mode->pNext) {
168 			int j = i + num_graphics_modes;
169 			memcpy(&(graphics_modes[j]), mode, sizeof(graphics_mode));
170 			/* HACK -- auto-assign grafID, unlike V. */
171 			graphics_modes[j].grafID = j + 1;
172 			graphics_modes[j].pNext = &(graphics_modes[j+1]);
173 		}
174 	}
175 	num_graphics_modes += count;
176 	count = num_graphics_modes;
177 
178 	/* hardcode the no graphics option */
179 	graphics_modes[count].pNext = NULL;
180 	graphics_modes[count].grafID = GRAPHICS_NONE;
181 	graphics_modes[count].alphablend = 0;
182 	graphics_modes[count].overdrawRow = 0;
183 	graphics_modes[count].overdrawMax = 0;
184 	strncpy(graphics_modes[count].pref, "none", 8);
185 	strncpy(graphics_modes[count].file, "", 32);
186 	strncpy(graphics_modes[count].menuname, "None", 32);
187 
188 	graphics_mode_high_id = count;
189 
190 	/* set the default graphics mode to be no graphics */
191 	current_graphics_mode = &(graphics_modes[count]);
192 
193 	if (p) {
194 		mode = parser_priv(p);
195 		while (mode) {
196 			n = mode->pNext;
197 			mem_free(mode);
198 			mode = n;
199 		}
200 
201 		parser_setpriv(p, NULL);
202 		parser_destroy(p);
203 	}
204 	return PARSE_ERROR_NONE;
205 }
206 
print_error(const char * name,struct parser * p)207 static void print_error(const char *name, struct parser *p) {
208 	struct parser_state s;
209 	parser_getstate(p, &s);
210 	printf("Parse error in %s line %d column %d: %s: %s\n", name,
211 	           s.line, s.col, s.msg, parser_error_str[s.error]);
212 	/* FIXME? message_flush(); */
213 }
214 
add_graphics_modes(const char * filename,bool buildpath)215 bool add_graphics_modes(const char *filename, bool buildpath) {
216 	char buf[1024];
217 
218 	ang_file *f;
219 	struct parser *p;
220 	errr e = 0;
221 
222 	int line_no = 0;
223 
224 	/* Build the filename */
225 	if (buildpath)
226 		path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, filename);
227 	else
228 		my_strcpy(buf, filename, sizeof(buf));
229 
230 	f = file_open(buf, MODE_READ, -1);
231 	if (!f) {
232 		e = PARSE_ERROR_GENERIC;
233 	} else {
234 		char line[1024];
235 
236 		p = init_parse_grafmode();
237 		while (file_getl(f, line, sizeof line)) {
238 			line_no++;
239 			e = parser_parse(p, line);
240 			if (e != PARSE_ERROR_NONE) {
241 				print_error(buf, p);
242 				break;
243 			}
244 		}
245 
246 		finish_parse_grafmode(p);
247 		file_close(f);
248 	}
249 
250 	/* Result */
251 	return e == PARSE_ERROR_NONE;
252 }
253 
init_graphics_modes(const char * filename)254 bool init_graphics_modes(const char *filename) {
255 	char buf[1024];
256 	ang_dir *dir;
257 	errr e = 0;
258 
259 	/* Read the 'main' file first */
260 	if (filename)
261 		add_graphics_modes(filename, TRUE);
262 
263 	/** Scan for definitions **/
264 
265 	/* Open the directory */
266 	dir = my_dopen(ANGBAND_DIR_XTRA_GRAF);
267 	if (!dir) return FALSE;
268 
269 	/* Read every filename */
270 	while (my_dread(dir, buf, sizeof buf)) {
271 		/* Skip 'main' file (it has already been read) */
272 		if (filename && !my_stricmp(buf, filename))
273 			continue;
274 		/* Check for file extension */
275 		if (isuffix(buf, ".txt"))
276 			add_graphics_modes(buf, TRUE);
277 	}
278 
279 	/* Done */
280 	my_dclose(dir);
281 
282 	/* Result */
283 	return e == PARSE_ERROR_NONE;
284 }
285 
286 #if 0
287 bool init_graphics_modes(const char *filename) {
288 	char buf[1024];
289 
290 	ang_file *f;
291 	struct parser *p;
292 	errr e = 0;
293 
294 	int line_no = 0;
295 
296 	/* Build the filename */
297 	path_build(buf, sizeof(buf), ANGBAND_DIR_XTRA_GRAF, filename);
298 
299 	f = file_open(buf, MODE_READ, -1);
300 	if (!f) {
301 		finish_parse_grafmode(NULL);
302 	} else {
303 		char line[1024];
304 
305 		p = init_parse_grafmode();
306 		while (file_getl(f, line, sizeof line)) {
307 			line_no++;
308 
309 			e = parser_parse(p, line);
310 			if (e != PARSE_ERROR_NONE) {
311 				print_error(buf, p);
312 				break;
313 			}
314 		}
315 
316 		finish_parse_grafmode(p);
317 		file_close(f);
318 	}
319 
320 	/* Result */
321 	return e == PARSE_ERROR_NONE;
322 }
323 #endif
324 
close_graphics_modes(void)325 void close_graphics_modes(void) {
326 	if (graphics_modes) {
327 		mem_free(graphics_modes);
328 		graphics_modes = NULL;
329 	}
330 	num_graphics_modes = 0;
331 	graphics_mode_high_id = 0;
332 }
333 
get_graphics_mode(byte id)334 graphics_mode* get_graphics_mode(byte id) {
335 	graphics_mode *test = graphics_modes;
336 	while (test) {
337 		if (test->grafID == id) {
338 			return test;
339 		}
340 		test = test->pNext;
341 	}
342 	return NULL;
343 }
344 
get_num_graphics_modes(void)345 size_t get_num_graphics_modes(void) {
346 	return num_graphics_modes;
347 }
348