1 //----------------------------------------------------------------------------
2 //  EDGE Data Definition File Code (Images)
3 //----------------------------------------------------------------------------
4 //
5 //  Copyright (c) 1999-2008  The EDGE Team.
6 //
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License
9 //  as published by the Free Software Foundation; either version 2
10 //  of the License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 //  GNU General Public License for more details.
16 //
17 //----------------------------------------------------------------------------
18 //
19 // Image Setup and Parser Code
20 //
21 
22 #include "local.h"
23 
24 #include "epi/path.h"
25 
26 #include "image.h"
27 
28 static imagedef_c *dynamic_image;
29 
30 static void DDF_ImageGetType(const char *info, void *storage);
31 static void DDF_ImageGetSpecial(const char *info, void *storage);
32 static void DDF_ImageGetFixTrans(const char *info, void *storage);
33 
34 // -ACB- 1998/08/10 Use DDF_MainGetLumpName for getting the..lump name.
35 // -KM- 1998/09/27 Use DDF_MainGetTime for getting tics
36 
37 #define DDF_CMD_BASE  dummy_image
38 static imagedef_c dummy_image;
39 
40 static const commandlist_t image_commands[] =
41 {
42 	DDF_FIELD("IMAGE_DATA", type,     DDF_ImageGetType),
43 	DDF_FIELD("SPECIAL",    special,  DDF_ImageGetSpecial),
44 	DDF_FIELD("X_OFFSET",   x_offset, DDF_MainGetNumeric),
45 	DDF_FIELD("Y_OFFSET",   y_offset, DDF_MainGetNumeric),
46 	DDF_FIELD("SCALE",      scale,    DDF_MainGetFloat),
47 	DDF_FIELD("ASPECT",     aspect,   DDF_MainGetFloat),
48 	DDF_FIELD("FIX_TRANS",  fix_trans, DDF_ImageGetFixTrans),
49 
50 	DDF_CMD_END
51 };
52 
53 imagedef_container_c imagedefs;
54 
GetImageNamespace(const char * prefix)55 static image_namespace_e GetImageNamespace(const char *prefix)
56 {
57 	if (DDF_CompareName(prefix, "gfx") == 0)
58 		return INS_Graphic;
59 
60 	if (DDF_CompareName(prefix, "tex") == 0)
61 		return INS_Texture;
62 
63 	if (DDF_CompareName(prefix, "flat") == 0)
64 		return INS_Flat;
65 
66 	if (DDF_CompareName(prefix, "spr") == 0)
67 		return INS_Sprite;
68 
69 	DDF_Error("Invalid image prefix '%s' (use: gfx,tex,flat,spr)\n", prefix);
70 	return INS_Flat; /* NOT REACHED */
71 }
72 
73 //
74 //  DDF PARSE ROUTINES
75 //
76 
ImageStartEntry(const char * name,bool extend)77 static void ImageStartEntry(const char *name, bool extend)
78 {
79 	if (!name || !name[0])
80 		DDF_Error("New image entry is missing a name!\n");
81 
82 //	I_Debugf("ImageStartEntry [%s]\n", name);
83 
84 	image_namespace_e belong = INS_Graphic;
85 
86 	const char *pos = strchr(name, ':');
87 
88 	if (! pos)
89 		DDF_Error("Missing image prefix.\n");
90 
91 	if (pos)
92 	{
93 		std::string nspace(name, pos - name);
94 
95 		if (nspace.empty())
96 			DDF_Error("Missing image prefix.\n");
97 
98 		belong = GetImageNamespace(nspace.c_str());
99 
100 		name = pos + 1;
101 
102 		if (! name[0])
103 			DDF_Error("Missing image name.\n");
104 	}
105 
106 	// W_Image code has limited space for the name
107 	if (strlen(name) > 15)
108 		DDF_Error("Image name [%s] too long.\n", name);
109 
110 	dynamic_image = imagedefs.Lookup(name, belong);
111 
112 	if (extend)
113 	{
114 		if (! dynamic_image)
115 			DDF_Error("Unknown image to extend: %s\n", name);
116 		return;
117 	}
118 
119 	// replaces an existing entry?
120 	if (dynamic_image)
121 	{
122 		dynamic_image->Default();
123 		return;
124 	}
125 
126 	// not found, create a new one
127 	dynamic_image = new imagedef_c;
128 
129 	dynamic_image->name   = name;
130 	dynamic_image->belong = belong;
131 
132 	imagedefs.Insert(dynamic_image);
133 }
134 
135 
ImageParseField(const char * field,const char * contents,int index,bool is_last)136 static void ImageParseField(const char *field, const char *contents, int index, bool is_last)
137 {
138 #if (DEBUG_DDF)
139 	I_Debugf("IMAGE_PARSE: %s = %s;\n", field, contents);
140 #endif
141 
142 	if (DDF_MainParseField(image_commands, field, contents, (byte *)dynamic_image))
143 		return;  // OK
144 
145 	DDF_Error("Unknown images.ddf command: %s\n", field);
146 }
147 
148 
ImageFinishEntry(void)149 static void ImageFinishEntry(void)
150 {
151 	if (dynamic_image->type == IMGDT_File)
152 	{
153         const char *filename = dynamic_image->info.c_str();
154 
155 		// determine format
156         std::string ext(epi::PATH_GetExtension(filename));
157 
158 		if (DDF_CompareName(ext.c_str(), "png") == 0)
159 			dynamic_image->format = LIF_PNG;
160 		else if (DDF_CompareName(ext.c_str(), "jpg")  == 0 ||
161 				 DDF_CompareName(ext.c_str(), "jpeg") == 0)
162 			dynamic_image->format = LIF_JPEG;
163 		else if (DDF_CompareName(ext.c_str(), "tga") == 0)
164 			dynamic_image->format = LIF_TGA;
165 		else
166 			DDF_Error("Unknown image extension for '%s'\n", filename);
167 	}
168 
169 	// TODO: check more stuff...
170 }
171 
172 
ImageClearAll(void)173 static void ImageClearAll(void)
174 {
175 	I_Warning("Ignoring #CLEARALL in images.ddf\n");
176 }
177 
178 
DDF_ReadImages(void * data,int size)179 bool DDF_ReadImages(void *data, int size)
180 {
181 	readinfo_t images;
182 
183 	images.memfile = (char*)data;
184 	images.memsize = size;
185 	images.tag = "IMAGES";
186 	images.entries_per_dot = 2;
187 
188 	if (images.memfile)
189 	{
190 		images.message = NULL;
191 		images.filename = NULL;
192 		images.lumpname = "DDFIMAGE";
193 	}
194 	else
195 	{
196 		images.message = "DDF_InitImages";
197 		images.filename = "images.ddf";
198 		images.lumpname = NULL;
199 	}
200 
201 	images.start_entry  = ImageStartEntry;
202 	images.parse_field  = ImageParseField;
203 	images.finish_entry = ImageFinishEntry;
204 	images.clear_all    = ImageClearAll;
205 
206 	return DDF_MainReadFile(&images);
207 }
208 
209 
DDF_ImageInit(void)210 void DDF_ImageInit(void)
211 {
212 	imagedefs.Clear();
213 }
214 
215 
AddEssentialImages(void)216 static void AddEssentialImages(void)
217 {
218 	// -AJA- this is a hack, these really should just be added to
219 	//       our standard IMAGES.DDF file.  However some Mods use
220 	//       standalone DDF and in that case these essential images
221 	//       would never get loaded.
222 
223 	if (! imagedefs.Lookup("DLIGHT_EXP", INS_Graphic))
224 	{
225 		imagedef_c *def = new imagedef_c;
226 
227 		def->name   = "DLIGHT_EXP";
228 		def->belong = INS_Graphic;
229 
230 		def->info.Set("DLITEXPN");
231 
232 		def->type    = IMGDT_Lump;
233 		def->format  = LIF_PNG;
234 		def->special = (image_special_e) (IMGSP_Clamp | IMGSP_Smooth | IMGSP_NoMip);
235 
236 		imagedefs.Insert(def);
237 	}
238 
239 	if (! imagedefs.Lookup("FUZZ_MAP", INS_Texture))
240 	{
241 		imagedef_c *def = new imagedef_c;
242 
243 		def->name   = "FUZZ_MAP";
244 		def->belong = INS_Texture;
245 
246 		def->info.Set("FUZZMAP8");
247 
248 		def->type    = IMGDT_Lump;
249 		def->format  = LIF_PNG;
250 		def->special = (image_special_e) (IMGSP_NoSmooth | IMGSP_NoMip);
251 
252 		imagedefs.Insert(def);
253 	}
254 
255 	if (! imagedefs.Lookup("CON_FONT_2", INS_Graphic))
256 	{
257 		imagedef_c *def = new imagedef_c;
258 
259 		def->name   = "CON_FONT_2";
260 		def->belong = INS_Graphic;
261 
262 		def->info.Set("CONFONT2");
263 
264 		def->type    = IMGDT_Lump;
265 		def->format  = LIF_PNG;
266 		def->special = (image_special_e) (IMGSP_Clamp | IMGSP_Smooth | IMGSP_NoMip);
267 
268 		imagedefs.Insert(def);
269 	}
270 }
271 
272 
DDF_ImageCleanUp(void)273 void DDF_ImageCleanUp(void)
274 {
275  	AddEssentialImages();
276 
277 	imagedefs.Trim();		// <-- Reduce to allocated size
278 }
279 
280 
ImageParseColour(const char * value)281 static void ImageParseColour(const char *value)
282 {
283 	DDF_MainGetRGB(value, &dynamic_image->colour);
284 }
285 
286 
ImageParseBuiltin(const char * value)287 static void ImageParseBuiltin(const char *value)
288 {
289 	if (DDF_CompareName(value, "LINEAR") == 0)
290 		dynamic_image->builtin = BLTIM_Linear;
291 	else if (DDF_CompareName(value, "QUADRATIC") == 0)
292 		dynamic_image->builtin = BLTIM_Quadratic;
293 	else if (DDF_CompareName(value, "SHADOW") == 0)
294 		dynamic_image->builtin = BLTIM_Shadow;
295 	else
296 		DDF_Error("Unknown image BUILTIN kind: %s\n", value);
297 }
298 
299 
ImageParseInfo(const char * value)300 static void ImageParseInfo(const char *value)
301 {
302 	// ouch, hard work here...
303 	dynamic_image->info = value;
304 }
305 
306 
ImageParseLump(const char * spec)307 static void ImageParseLump(const char *spec)
308 {
309 	const char *colon = DDF_MainDecodeList(spec, ':', true);
310 
311 	if (! colon || colon == spec || (colon - spec) >= 16 || colon[1] == 0)
312 		DDF_Error("Malformed image lump spec: 'LUMP:%s'\n", spec);
313 
314 	char keyword[20];
315 
316 	strncpy(keyword, spec, colon - spec);
317 	keyword[colon - spec] = 0;
318 
319 	// store the lump name
320 	dynamic_image->info.Set(colon + 1);
321 
322 	if (DDF_CompareName(keyword, "PNG") == 0)
323 	{
324 		dynamic_image->format = LIF_PNG;
325 	}
326 	else if (DDF_CompareName(keyword, "JPG") == 0 ||
327 	         DDF_CompareName(keyword, "JPEG") == 0)
328 	{
329 		dynamic_image->format = LIF_JPEG;
330 	}
331 	else if (DDF_CompareName(keyword, "TGA") == 0)
332 	{
333 		dynamic_image->format = LIF_TGA;
334 	}
335 	else
336 		DDF_Error("Unknown image format: %s (use PNG or JPEG)\n", keyword);
337 }
338 
339 
DDF_ImageGetType(const char * info,void * storage)340 static void DDF_ImageGetType(const char *info, void *storage)
341 {
342 	const char *colon = DDF_MainDecodeList(info, ':', true);
343 
344 	if (! colon || colon == info || (colon - info) >= 16 || colon[1] == 0)
345 		DDF_Error("Malformed image type spec: %s\n", info);
346 
347 	char keyword[20];
348 
349 	strncpy(keyword, info, colon - info);
350 	keyword[colon - info] = 0;
351 
352 	if (DDF_CompareName(keyword, "COLOUR") == 0)
353 	{
354 		dynamic_image->type = IMGDT_Colour;
355 		ImageParseColour(colon + 1);
356 	}
357 	else if (DDF_CompareName(keyword, "BUILTIN") == 0)
358 	{
359 		dynamic_image->type = IMGDT_Builtin;
360 		ImageParseBuiltin(colon + 1);
361 	}
362 	else if (DDF_CompareName(keyword, "FILE") == 0)
363 	{
364 		dynamic_image->type = IMGDT_File;
365 		ImageParseInfo(colon + 1);
366 	}
367 	else if (DDF_CompareName(keyword, "LUMP") == 0)
368 	{
369 		dynamic_image->type = IMGDT_Lump;
370 		ImageParseLump(colon + 1);
371 	}
372 	else
373 		DDF_Error("Unknown image type: %s\n", keyword);
374 }
375 
376 static specflags_t image_specials[] =
377 {
378     {"NOALPHA",       IMGSP_NoAlpha,   0},
379     {"FORCE_MIP",     IMGSP_Mip,       0},
380     {"FORCE_NOMIP",   IMGSP_NoMip,     0},
381     {"FORCE_CLAMP",   IMGSP_Clamp,     0},
382     {"FORCE_SMOOTH",  IMGSP_Smooth,    0},
383     {"FORCE_NOSMOOTH",IMGSP_NoSmooth,  0},
384     {"CROSSHAIR",     IMGSP_Crosshair, 0},
385     {NULL, 0, 0}
386 };
387 
388 
DDF_ImageGetSpecial(const char * info,void * storage)389 static void DDF_ImageGetSpecial(const char *info, void *storage)
390 {
391 	image_special_e *dest = (image_special_e *)storage;
392 
393 	int flag_value;
394 
395 	switch (DDF_MainCheckSpecialFlag(info, image_specials,
396 			&flag_value, false /* allow_prefixes */, false))
397 	{
398 		case CHKF_Positive:
399 			*dest = (image_special_e)(*dest | flag_value);
400 			break;
401 
402 		case CHKF_Negative:
403 			*dest = (image_special_e)(*dest & ~flag_value);
404 			break;
405 
406 		case CHKF_User:
407 		case CHKF_Unknown:
408 			DDF_WarnError("Unknown image special: %s\n", info);
409 			break;
410 	}
411 }
412 
413 
DDF_ImageGetFixTrans(const char * info,void * storage)414 static void DDF_ImageGetFixTrans(const char *info, void *storage)
415 {
416 	image_fix_trans_e *var = (image_fix_trans_e *)storage;
417 
418 	if (DDF_CompareName(info, "NONE") == 0)
419 	{
420 		*var = FIXTRN_None;
421 	}
422 	else if (DDF_CompareName(info, "BLACKEN") == 0)
423 	{
424 		*var = FIXTRN_Blacken;
425 	}
426 	else
427 		DDF_Error("Unknown FIX_TRANS type: %s\n", info);
428 }
429 
430 
431 // ---> imagedef_c class
432 
imagedef_c()433 imagedef_c::imagedef_c() : name(), belong(INS_Graphic), info()
434 {
435 	Default();
436 }
437 
438 //
439 // Copies all the detail with the exception of ddf info
440 //
CopyDetail(const imagedef_c & src)441 void imagedef_c::CopyDetail(const imagedef_c &src)
442 {
443 	type    = src.type;
444 	colour  = src.colour;
445 	builtin = src.builtin;
446 	info    = src.info;
447 	format  = src.format;
448 
449 	special  = src.special;
450 	x_offset = src.x_offset;
451 	y_offset = src.y_offset;
452 	scale    = src.scale;
453 	aspect   = src.aspect;
454 	fix_trans = src.fix_trans;
455 }
456 
Default()457 void imagedef_c::Default()
458 {
459 	type    = IMGDT_Colour;
460 	colour  = 0x000000;  // black
461 	builtin = BLTIM_Quadratic;
462 	format  = LIF_PNG;
463 
464 	info.clear();
465 
466 	special  = IMGSP_None;
467 	x_offset = y_offset = 0;
468 
469 	scale  = 1.0f;
470 	aspect = 1.0f;
471 	fix_trans = FIXTRN_None;
472 }
473 
474 
475 // ---> imagedef_container_c class
476 
CleanupObject(void * obj)477 void imagedef_container_c::CleanupObject(void *obj)
478 {
479 	imagedef_c *a = *(imagedef_c**)obj;
480 
481 	if (a) delete a;
482 }
483 
484 
Lookup(const char * refname,image_namespace_e belong)485 imagedef_c * imagedef_container_c::Lookup(const char *refname, image_namespace_e belong)
486 {
487 	if (!refname || !refname[0])
488 		return NULL;
489 
490 	epi::array_iterator_c it;
491 
492 	for (it = GetBaseIterator(); it.IsValid(); it++)
493 	{
494 		imagedef_c *g = ITERATOR_TO_TYPE(it, imagedef_c*);
495 
496 		if (DDF_CompareName(g->name.c_str(), refname) == 0 && g->belong == belong)
497 			return g;
498 	}
499 
500 	return NULL;
501 }
502 
503 
504 //--- editor settings ---
505 // vi:ts=4:sw=4:noexpandtab
506