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