1 //----------------------------------------------------------------------------
2 // EDGE WAD Support Code
3 //----------------------------------------------------------------------------
4 //
5 // Copyright (c) 1999-2009 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 // Based on the DOOM source code, released by Id Software under the
20 // following copyright:
21 //
22 // Copyright (C) 1993-1996 by id Software, Inc.
23 //
24 //----------------------------------------------------------------------------
25 //
26 // This file contains various levels of support for using sprites and
27 // flats directly from a PWAD as well as some minor optimisations for
28 // patches. Because there are some PWADs that do arcane things with
29 // sprites, it is possible that this feature may not always work (at
30 // least, not until I become aware of them and support them) and so
31 // this feature can be turned off from the command line if necessary.
32 //
33 // -MH- 1998/03/04
34 //
35
36 #include "i_defs.h"
37
38 #include <limits.h>
39
40 #include <list>
41
42 #include "epi/endianess.h"
43 #include "epi/file.h"
44 #include "epi/file_sub.h"
45 #include "epi/filesystem.h"
46 #include "epi/math_md5.h"
47 #include "epi/path.h"
48 #include "epi/str_format.h"
49 #include "epi/utility.h"
50
51 #include "ddf/main.h"
52 #include "ddf/anim.h"
53 #include "ddf/colormap.h"
54 #include "ddf/font.h"
55 #include "ddf/image.h"
56 #include "ddf/style.h"
57 #include "ddf/switch.h"
58
59 #include "dm_data.h"
60 #include "dm_defs.h"
61 #include "dm_state.h"
62 #include "dm_structs.h"
63 #include "dstrings.h"
64 #include "e_main.h"
65 #include "e_search.h"
66 #include "l_deh.h"
67 #include "l_glbsp.h"
68 #include "m_misc.h"
69 #include "r_image.h"
70 #include "rad_trig.h"
71 #include "vm_coal.h"
72 #include "w_wad.h"
73 #include "z_zone.h"
74
75 // -KM- 1999/01/31 Order is important, Languages are loaded before sfx, etc...
76 typedef struct ddf_reader_s
77 {
78 const char *name;
79 const char *print_name;
80 bool (* func)(void *data, int size);
81 }
82 ddf_reader_t;
83
84 static ddf_reader_t DDF_Readers[] =
85 {
86 { "DDFLANG", "Languages", DDF_ReadLangs },
87 { "DDFSFX", "Sounds", DDF_ReadSFX },
88 { "DDFCOLM", "ColourMaps", DDF_ReadColourMaps }, // -AJA- 1999/07/09.
89 { "DDFIMAGE","Images", DDF_ReadImages }, // -AJA- 2004/11/18
90 { "DDFFONT", "Fonts", DDF_ReadFonts }, // -AJA- 2004/11/13
91 { "DDFSTYLE","Styles", DDF_ReadStyles }, // -AJA- 2004/11/14
92 { "DDFATK", "Attacks", DDF_ReadAtks },
93 { "DDFWEAP", "Weapons", DDF_ReadWeapons },
94 { "DDFTHING","Things", DDF_ReadThings },
95 { "DDFPLAY", "Playlists", DDF_ReadMusicPlaylist },
96 { "DDFLINE", "Lines", DDF_ReadLines },
97 { "DDFSECT", "Sectors", DDF_ReadSectors },
98 { "DDFSWTH", "Switches", DDF_ReadSwitch },
99 { "DDFANIM", "Anims", DDF_ReadAnims },
100 { "DDFGAME", "Games", DDF_ReadGames },
101 { "DDFLEVL", "Levels", DDF_ReadLevels },
102 { "RSCRIPT", "RadTrig", RAD_ReadScript } // -AJA- 2000/04/21.
103 };
104
105 #define NUM_DDF_READERS (int)(sizeof(DDF_Readers) / sizeof(ddf_reader_t))
106
107 #define LANG_READER 0
108 #define COLM_READER 2
109 #define SWTH_READER 12
110 #define ANIM_READER 13
111 #define RTS_READER 16
112
113 class data_file_c
114 {
115 public:
116 const char *file_name;
117
118 // type of file (FLKIND_XXX)
119 int kind;
120
121 // file object
122 epi::file_c *file;
123
124 // lists for sprites, flats, patches (stuff between markers)
125 epi::u32array_c sprite_lumps;
126 epi::u32array_c flat_lumps;
127 epi::u32array_c patch_lumps;
128 epi::u32array_c colmap_lumps;
129 epi::u32array_c tx_lumps;
130 epi::u32array_c hires_lumps;
131
132 // level markers and skin markers
133 epi::u32array_c level_markers;
134 epi::u32array_c skin_markers;
135
136 // ddf lump list
137 int ddf_lumps[NUM_DDF_READERS];
138
139 // texture information
140 wadtex_resource_c wadtex;
141
142 // DeHackEd support
143 int deh_lump;
144
145 // COAL scripts
146 int coal_huds;
147
148 // BOOM stuff
149 int animated, switches;
150
151 // file containing the GL nodes for the levels in this WAD.
152 // -1 when none (usually when this WAD has no levels, but also
153 // temporarily before a new GWA files has been built and added).
154 int companion_gwa;
155
156 // MD5 hash of the contents of the WAD directory.
157 // This is used to disambiguate cached GWA/HWA filenames.
158 epi::md5hash_c dir_hash;
159
160 public:
data_file_c(const char * _fname,int _kind,epi::file_c * _file)161 data_file_c(const char *_fname, int _kind, epi::file_c* _file) :
162 file_name(_fname), kind(_kind), file(_file),
163 sprite_lumps(), flat_lumps(), patch_lumps(),
164 colmap_lumps(), tx_lumps(), hires_lumps(),
165 level_markers(), skin_markers(),
166 wadtex(), deh_lump(-1), coal_huds(-1),
167 animated(-1), switches(-1),
168 companion_gwa(-1), dir_hash()
169 {
170 file_name = strdup(_fname);
171
172 for (int d = 0; d < NUM_DDF_READERS; d++)
173 ddf_lumps[d] = -1;
174 }
175
~data_file_c()176 ~data_file_c()
177 {
178 free((void*)file_name);
179 }
180 };
181
182 static std::vector<data_file_c *> data_files;
183
184
185 // Raw filenames
186 class raw_filename_c
187 {
188 public:
189 std::string filename;
190 int kind;
191
192 public:
raw_filename_c(const char * _name,int _kind)193 raw_filename_c(const char *_name, int _kind) :
194 filename(_name), kind(_kind)
195 { }
196
~raw_filename_c()197 ~raw_filename_c()
198 { }
199 };
200
201 static std::list<raw_filename_c *> wadfiles;
202
203
204 typedef enum
205 {
206 LMKIND_Normal = 0, // fallback value
207 LMKIND_Marker = 3, // X_START, X_END, S_SKIN, level name
208 LMKIND_WadTex = 6, // palette, pnames, texture1/2
209 LMKIND_DDFRTS = 10, // DDF, RTS, DEHACKED lump
210 LMKIND_TX = 14,
211 LMKIND_Colmap = 15,
212 LMKIND_Flat = 16,
213 LMKIND_Sprite = 17,
214 LMKIND_Patch = 18,
215 LMKIND_HiRes = 19
216 }
217 lump_kind_e;
218
219 typedef struct
220 {
221 char name[10];
222 int position;
223 int size;
224
225 // file number (an index into data_files[]).
226 short file;
227
228 // value used when sorting. When lumps have the same name, the one
229 // with the highest sort_index is used (W_CheckNumForName). This is
230 // closely related to the `file' field, with some tweaks for
231 // handling GWA files (especially dynamic ones).
232 short sort_index;
233
234 // one of the LMKIND values. For sorting, this is the least
235 // significant aspect (but still necessary).
236 short kind;
237 }
238 lumpinfo_t;
239
240 // Create the start and end markers
241
242 //
243 // GLOBALS
244 //
245
246 // Location of each lump on disk.
247 lumpinfo_t *lumpinfo;
248 static int *lumpmap = NULL;
249 int numlumps;
250
251 #define LUMP_MAP_CMP(a) (strncmp(lumpinfo[lumpmap[a]].name, buf, 8))
252
253
254 typedef struct lumpheader_s
255 {
256 #ifdef DEVELOPERS
257 static const int LUMPID = (int)0xAC45197e;
258
259 int id; // Should be LUMPID
260 #endif
261
262 // number of users.
263 int users;
264
265 // index in lumplookup
266 int lumpindex;
267 struct lumpheader_s *next, *prev;
268 }
269 lumpheader_t;
270
271 static lumpheader_t **lumplookup;
272 static lumpheader_t lumphead;
273
274 // number of freeable bytes in cache (excluding headers).
275 // Used to decide how many bytes we should flush.
276 static int cache_size = 0;
277
278 // the first datafile which contains a PLAYPAL lump
279 static int palette_datafile = -1;
280
281 // Sprites & Flats
282 static bool within_sprite_list;
283 static bool within_flat_list;
284 static bool within_patch_list;
285 static bool within_colmap_list;
286 static bool within_tex_list;
287 static bool within_hires_list;
288
289 byte *W_ReadLumpAlloc(int lump, int *length);
290
291 //
292 // Is the name a sprite list start flag?
293 // If lax syntax match, fix up to standard syntax.
294 //
IsS_START(char * name)295 static bool IsS_START(char *name)
296 {
297 if (strncmp(name, "SS_START", 8) == 0)
298 {
299 // fix up flag to standard syntax
300 // Note: strncpy will pad will nulls
301 strncpy(name, "S_START", 8);
302 return 1;
303 }
304
305 return (strncmp(name, "S_START", 8) == 0);
306 }
307
308 //
309 // Is the name a sprite list end flag?
310 // If lax syntax match, fix up to standard syntax.
311 //
IsS_END(char * name)312 static bool IsS_END(char *name)
313 {
314 if (strncmp(name, "SS_END", 8) == 0)
315 {
316 // fix up flag to standard syntax
317 strncpy(name, "S_END", 8);
318 return 1;
319 }
320
321 return (strncmp(name, "S_END", 8) == 0);
322 }
323
324 //
325 // Is the name a flat list start flag?
326 // If lax syntax match, fix up to standard syntax.
327 //
IsF_START(char * name)328 static bool IsF_START(char *name)
329 {
330 if (strncmp(name, "FF_START", 8) == 0)
331 {
332 // fix up flag to standard syntax
333 strncpy(name, "F_START", 8);
334 return 1;
335 }
336
337 return (strncmp(name, "F_START", 8) == 0);
338 }
339
340 //
341 // Is the name a flat list end flag?
342 // If lax syntax match, fix up to standard syntax.
343 //
IsF_END(char * name)344 static bool IsF_END(char *name)
345 {
346 if (strncmp(name, "FF_END", 8) == 0)
347 {
348 // fix up flag to standard syntax
349 strncpy(name, "F_END", 8);
350 return 1;
351 }
352
353 return (strncmp(name, "F_END", 8) == 0);
354 }
355
356 //
357 // Is the name a patch list start flag?
358 // If lax syntax match, fix up to standard syntax.
359 //
IsP_START(char * name)360 static bool IsP_START(char *name)
361 {
362 if (strncmp(name, "PP_START", 8) == 0)
363 {
364 // fix up flag to standard syntax
365 strncpy(name, "P_START", 8);
366 return 1;
367 }
368
369 return (strncmp(name, "P_START", 8) == 0);
370 }
371
372 //
373 // Is the name a patch list end flag?
374 // If lax syntax match, fix up to standard syntax.
375 //
IsP_END(char * name)376 static bool IsP_END(char *name)
377 {
378 if (strncmp(name, "PP_END", 8) == 0)
379 {
380 // fix up flag to standard syntax
381 strncpy(name, "P_END", 8);
382 return 1;
383 }
384
385 return (strncmp(name, "P_END", 8) == 0);
386 }
387
388 //
389 // Is the name a colourmap list start/end flag?
390 //
IsC_START(char * name)391 static bool IsC_START(char *name)
392 {
393 return (strncmp(name, "C_START", 8) == 0);
394 }
395
IsC_END(char * name)396 static bool IsC_END(char *name)
397 {
398 return (strncmp(name, "C_END", 8) == 0);
399 }
400
401 //
402 // Is the name a texture list start/end flag?
403 //
IsTX_START(char * name)404 static bool IsTX_START(char *name)
405 {
406 return (strncmp(name, "TX_START", 8) == 0);
407 }
408
IsTX_END(char * name)409 static bool IsTX_END(char *name)
410 {
411 return (strncmp(name, "TX_END", 8) == 0);
412 }
413
414 //
415 // Is the name a high-resolution start/end flag?
416 //
IsHI_START(char * name)417 static bool IsHI_START(char *name)
418 {
419 return (strncmp(name, "HI_START", 8) == 0);
420 }
421
IsHI_END(char * name)422 static bool IsHI_END(char *name)
423 {
424 return (strncmp(name, "HI_END", 8) == 0);
425 }
426
427 //
428 // Is the name a dummy sprite/flat/patch marker ?
429 //
IsDummySF(const char * name)430 static bool IsDummySF(const char *name)
431 {
432 return (strncmp(name, "S1_START", 8) == 0 ||
433 strncmp(name, "S2_START", 8) == 0 ||
434 strncmp(name, "S3_START", 8) == 0 ||
435 strncmp(name, "F1_START", 8) == 0 ||
436 strncmp(name, "F2_START", 8) == 0 ||
437 strncmp(name, "F3_START", 8) == 0 ||
438 strncmp(name, "P1_START", 8) == 0 ||
439 strncmp(name, "P2_START", 8) == 0 ||
440 strncmp(name, "P3_START", 8) == 0);
441 }
442
443 //
444 // Is the name a skin specifier ?
445 //
IsSkin(const char * name)446 static bool IsSkin(const char *name)
447 {
448 return (strncmp(name, "S_SKIN", 6) == 0);
449 }
450
IsGL_Prefix(const char * name)451 static inline bool IsGL_Prefix(const char *name)
452 {
453 return name[0] == 'G' && name[1] == 'L' && name[2] == '_';
454 }
455
456 //
457 // W_GetTextureLumps
458 //
W_GetTextureLumps(int file,wadtex_resource_c * res)459 void W_GetTextureLumps(int file, wadtex_resource_c *res)
460 {
461 SYS_ASSERT(0 <= file && file < (int)data_files.size());
462 SYS_ASSERT(res);
463
464 data_file_c *df = data_files[file];
465
466 res->palette = df->wadtex.palette;
467 res->pnames = df->wadtex.pnames;
468 res->texture1 = df->wadtex.texture1;
469 res->texture2 = df->wadtex.texture2;
470
471 // find an earlier PNAMES lump when missing.
472 // Ditto for palette.
473
474 if (res->texture1 >= 0 || res->texture2 >= 0)
475 {
476 int cur;
477
478 for (cur=file; res->pnames == -1 && cur > 0; cur--)
479 res->pnames = data_files[cur]->wadtex.pnames;
480
481 for (cur=file; res->palette == -1 && cur > 0; cur--)
482 res->palette = data_files[cur]->wadtex.palette;
483 }
484 }
485
486 //
487 // SortLumps
488 //
489 // Create the lumpmap[] array, which is sorted by name for fast
490 // searching. It also makes sure that entries with the same name all
491 // refer to the same lump (prefering lumps in later WADs over those in
492 // earlier ones).
493 //
494 // -AJA- 2000/10/14: simplified.
495 //
SortLumps(void)496 static void SortLumps(void)
497 {
498 int i;
499
500 Z_Resize(lumpmap, int, numlumps);
501
502 for (i = 0; i < numlumps; i++)
503 lumpmap[i] = i;
504
505 // sort it, primarily by increasing name, secondly by decreasing
506 // file number, thirdly by the lump type.
507
508 #define CMP(a, b) \
509 (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) < 0 || \
510 (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) == 0 && \
511 (lumpinfo[a].sort_index > lumpinfo[b].sort_index || \
512 (lumpinfo[a].sort_index == lumpinfo[b].sort_index && \
513 lumpinfo[a].kind > lumpinfo[b].kind))))
514 QSORT(int, lumpmap, numlumps, CUTOFF);
515 #undef CMP
516
517 #if 0
518 for (i=1; i < numlumps; i++)
519 {
520 int a = lumpmap[i - 1];
521 int b = lumpmap[i];
522
523 if (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) == 0)
524 lumpmap[i] = lumpmap[i - 1];
525 }
526 #endif
527 }
528
529 //
530 // SortSpriteLumps
531 //
532 // Put the sprite list in sorted order (of name), required by
533 // R_InitSprites (speed optimisation).
534 //
SortSpriteLumps(data_file_c * df)535 static void SortSpriteLumps(data_file_c *df)
536 {
537 if (df->sprite_lumps.GetSize() < 2)
538 return;
539
540 #define CMP(a, b) (strncmp(lumpinfo[a].name, lumpinfo[b].name, 8) < 0)
541 QSORT(int, df->sprite_lumps, df->sprite_lumps.GetSize(), CUTOFF);
542 #undef CMP
543
544 #if 0 // DEBUGGING
545 {
546 int i, lump;
547
548 for (i=0; i < f->sprite_num; i++)
549 {
550 lump = f->sprite_lumps[i];
551
552 I_Debugf("Sorted sprite %d = lump %d [%s]\n", i, lump,
553 lumpinfo[lump].name);
554 }
555 }
556 #endif
557 }
558
559
560 //
561 // LUMP BASED ROUTINES.
562 //
563
564 //
565 // W_AddFile
566 //
567 // All files are optional, but at least one file must be
568 // found (PWAD, if all required lumps are present).
569 // Files with a .wad extension are wadlink files
570 // with multiple lumps.
571 // Other files are single lumps with the base filename
572 // for the lump name.
573 //
574
575 #if 0 // UNUSED ??
576 static void FreeLump(lumpheader_t *h)
577 {
578 int lumpnum = h->lumpindex;
579
580 cache_size -= W_LumpLength(lumpnum);
581 #ifdef DEVELOPERS
582 if (h->id != lumpheader_s::LUMPID)
583 I_Error("FreeLump: id != LUMPID");
584 h->id = 0;
585 if (h == NULL)
586 I_Error("FreeLump: NULL lump");
587 if (h->users)
588 I_Error("FreeLump: lump %d has %d users!", lumpnum, h->users);
589 if (lumplookup[lumpnum] != h)
590 I_Error("FreeLump: Internal error, lump %d", lumpnum);
591 #endif
592 lumplookup[lumpnum] = NULL;
593 h->prev->next = h->next;
594 h->next->prev = h->prev;
595 Z_Free(h);
596 }
597 #endif
598
599 //
600 // MarkAsCached
601 //
MarkAsCached(lumpheader_t * item)602 static void MarkAsCached(lumpheader_t *item)
603 {
604 #ifdef DEVELOPERS
605 if (item->id != lumpheader_s::LUMPID)
606 I_Error("MarkAsCached: id != LUMPID");
607 if (!item)
608 I_Error("MarkAsCached: lump %d is NULL", item->lumpindex);
609 if (item->users)
610 I_Error("MarkAsCached: lump %d has %d users!", item->lumpindex, item->users);
611 if (lumplookup[item->lumpindex] != item)
612 I_Error("MarkAsCached: Internal error, lump %d", item->lumpindex);
613 #endif
614
615 cache_size += W_LumpLength(item->lumpindex);
616 }
617
618 //
619 // AddLump
620 //
AddLump(data_file_c * df,int lump,int pos,int size,int file,int sort_index,const char * name,bool allow_ddf)621 static void AddLump(data_file_c *df, int lump, int pos, int size, int file,
622 int sort_index, const char *name, bool allow_ddf)
623 {
624 int j;
625 lumpinfo_t *lump_p = lumpinfo + lump;
626
627 lump_p->position = pos;
628 lump_p->size = size;
629 lump_p->file = file;
630 lump_p->sort_index = sort_index;
631 lump_p->kind = LMKIND_Normal;
632
633 Z_StrNCpy(lump_p->name, name, 8);
634 strupr(lump_p->name);
635
636 // -- handle special names --
637
638 if (strncmp(name, "PLAYPAL", 8) == 0)
639 {
640 lump_p->kind = LMKIND_WadTex;
641 df->wadtex.palette = lump;
642 if (palette_datafile < 0)
643 palette_datafile = file;
644 return;
645 }
646 else if (strncmp(name, "PNAMES", 8) == 0)
647 {
648 lump_p->kind = LMKIND_WadTex;
649 df->wadtex.pnames = lump;
650 return;
651 }
652 else if (strncmp(name, "TEXTURE1", 8) == 0)
653 {
654 lump_p->kind = LMKIND_WadTex;
655 df->wadtex.texture1 = lump;
656 return;
657 }
658 else if (strncmp(name, "TEXTURE2", 8) == 0)
659 {
660 lump_p->kind = LMKIND_WadTex;
661 df->wadtex.texture2 = lump;
662 return;
663 }
664 else if (strncmp(name, "DEHACKED", 8) == 0)
665 {
666 lump_p->kind = LMKIND_DDFRTS;
667 df->deh_lump = lump;
668 return;
669 }
670 else if (strncmp(name, "COALHUDS", 8) == 0)
671 {
672 lump_p->kind = LMKIND_DDFRTS;
673 df->coal_huds = lump;
674 return;
675 }
676 else if (strncmp(name, "ANIMATED", 8) == 0)
677 {
678 lump_p->kind = LMKIND_DDFRTS;
679 df->animated = lump;
680 return;
681 }
682 else if (strncmp(name, "SWITCHES", 8) == 0)
683 {
684 lump_p->kind = LMKIND_DDFRTS;
685 df->switches = lump;
686 return;
687 }
688
689 // -KM- 1998/12/16 Load DDF/RSCRIPT file from wad.
690 if (allow_ddf)
691 {
692 for (j=0; j < NUM_DDF_READERS; j++)
693 {
694 if (strncmp(name, DDF_Readers[j].name, 8) == 0)
695 {
696 lump_p->kind = LMKIND_DDFRTS;
697 df->ddf_lumps[j] = lump;
698 return;
699 }
700 }
701 }
702
703 if (IsSkin(lump_p->name))
704 {
705 lump_p->kind = LMKIND_Marker;
706 df->skin_markers.Insert(lump);
707 return;
708 }
709
710 // -- handle sprite, flat & patch lists --
711
712 if (IsS_START(lump_p->name))
713 {
714 lump_p->kind = LMKIND_Marker;
715 within_sprite_list = true;
716 return;
717 }
718 else if (IsS_END(lump_p->name))
719 {
720 if (!within_sprite_list)
721 I_Warning("Unexpected S_END marker in wad.\n");
722
723 lump_p->kind = LMKIND_Marker;
724 within_sprite_list = false;
725 return;
726 }
727 else if (IsF_START(lump_p->name))
728 {
729 lump_p->kind = LMKIND_Marker;
730 within_flat_list = true;
731 return;
732 }
733 else if (IsF_END(lump_p->name))
734 {
735 if (!within_flat_list)
736 I_Warning("Unexpected F_END marker in wad.\n");
737
738 lump_p->kind = LMKIND_Marker;
739 within_flat_list = false;
740 return;
741 }
742 else if (IsP_START(lump_p->name))
743 {
744 lump_p->kind = LMKIND_Marker;
745 within_patch_list = true;
746 return;
747 }
748 else if (IsP_END(lump_p->name))
749 {
750 if (!within_patch_list)
751 I_Warning("Unexpected P_END marker in wad.\n");
752
753 lump_p->kind = LMKIND_Marker;
754 within_patch_list = false;
755 return;
756 }
757 else if (IsC_START(lump_p->name))
758 {
759 lump_p->kind = LMKIND_Marker;
760 within_colmap_list = true;
761 return;
762 }
763 else if (IsC_END(lump_p->name))
764 {
765 if (!within_colmap_list)
766 I_Warning("Unexpected C_END marker in wad.\n");
767
768 lump_p->kind = LMKIND_Marker;
769 within_colmap_list = false;
770 return;
771 }
772 else if (IsTX_START(lump_p->name))
773 {
774 lump_p->kind = LMKIND_Marker;
775 within_tex_list = true;
776 return;
777 }
778 else if (IsTX_END(lump_p->name))
779 {
780 if (!within_tex_list)
781 I_Warning("Unexpected TX_END marker in wad.\n");
782
783 lump_p->kind = LMKIND_Marker;
784 within_tex_list = false;
785 return;
786 }
787 else if (IsHI_START(lump_p->name))
788 {
789 lump_p->kind = LMKIND_Marker;
790 within_hires_list = true;
791 return;
792 }
793 else if (IsHI_END(lump_p->name))
794 {
795 if (!within_hires_list)
796 I_Warning("Unexpected HI_END marker in wad.\n");
797
798 lump_p->kind = LMKIND_Marker;
799 within_hires_list = false;
800 return;
801 }
802
803 // ignore zero size lumps or dummy markers
804 if (lump_p->size > 0 && !IsDummySF(lump_p->name))
805 {
806 if (within_sprite_list)
807 {
808 lump_p->kind = LMKIND_Sprite;
809 df->sprite_lumps.Insert(lump);
810 }
811
812 if (within_flat_list)
813 {
814 lump_p->kind = LMKIND_Flat;
815 df->flat_lumps.Insert(lump);
816 }
817
818 if (within_patch_list)
819 {
820 lump_p->kind = LMKIND_Patch;
821 df->patch_lumps.Insert(lump);
822 }
823
824 if (within_colmap_list)
825 {
826 lump_p->kind = LMKIND_Colmap;
827 df->colmap_lumps.Insert(lump);
828 }
829
830 if (within_tex_list)
831 {
832 lump_p->kind = LMKIND_TX;
833 df->tx_lumps.Insert(lump);
834 }
835
836 if (within_hires_list)
837 {
838 lump_p->kind = LMKIND_HiRes;
839 df->hires_lumps.Insert(lump);
840 }
841 }
842 }
843
844 //
845 // CheckForLevel
846 //
847 // Tests whether the current lump is a level marker (MAP03, E1M7, etc).
848 // Because EDGE supports arbitrary names (via DDF), we look at the
849 // sequence of lumps _after_ this one, which works well since their
850 // order is fixed (e.g. THINGS is always first).
851 //
CheckForLevel(data_file_c * df,int lump,const char * name,const raw_wad_entry_t * raw,int remaining)852 static void CheckForLevel(data_file_c *df, int lump, const char *name,
853 const raw_wad_entry_t *raw, int remaining)
854 {
855 // we only test four lumps (it is enough), but fewer definitely
856 // means this is not a level marker.
857 if (remaining < 4)
858 return;
859
860 if (strncmp(raw[1].name, "THINGS", 8) == 0 &&
861 strncmp(raw[2].name, "LINEDEFS", 8) == 0 &&
862 strncmp(raw[3].name, "SIDEDEFS", 8) == 0 &&
863 strncmp(raw[4].name, "VERTEXES", 8) == 0)
864 {
865 if (strlen(name) > 5)
866 {
867 I_Warning("Level name '%s' is too long !!\n", name);
868 return;
869 }
870
871 // check for duplicates (Slige sometimes does this)
872 for (int L = 0; L < df->level_markers.GetSize(); L++)
873 {
874 if (strcmp(lumpinfo[df->level_markers[L]].name, name) == 0)
875 {
876 I_Warning("Duplicate level '%s' ignored.\n", name);
877 return;
878 }
879 }
880
881 df->level_markers.Insert(lump);
882 return;
883 }
884
885 // handle GL nodes here too
886
887 if (strncmp(raw[1].name, "GL_VERT", 8) == 0 &&
888 strncmp(raw[2].name, "GL_SEGS", 8) == 0 &&
889 strncmp(raw[3].name, "GL_SSECT", 8) == 0 &&
890 strncmp(raw[4].name, "GL_NODES", 8) == 0)
891 {
892 df->level_markers.Insert(lump);
893 return;
894 }
895 }
896
897 //
898 // HasInternalGLNodes
899 //
900 // Determine if WAD file contains GL nodes for every level.
901 //
HasInternalGLNodes(data_file_c * df,int datafile)902 static bool HasInternalGLNodes(data_file_c *df, int datafile)
903 {
904 int levels = 0;
905 int glnodes = 0;
906
907 for (int L = 0; L < df->level_markers.GetSize(); L++)
908 {
909 int lump = df->level_markers[L];
910
911 if (IsGL_Prefix(lumpinfo[lump].name))
912 continue;
913
914 levels++;
915
916 char gl_marker[10];
917
918 sprintf(gl_marker, "GL_%s", lumpinfo[lump].name);
919
920 for (int M = L+1; M < df->level_markers.GetSize(); M++)
921 {
922 int lump2 = df->level_markers[M];
923
924 if (strcmp(lumpinfo[lump2].name, gl_marker) == 0)
925 {
926 glnodes++;
927 break;
928 }
929 }
930 }
931
932 I_Debugf("Levels %d, Internal GL nodes %d\n", levels, glnodes);
933
934 return levels == glnodes;
935 }
936
ComputeFileMD5hash(epi::md5hash_c & hash,epi::file_c * file)937 static void ComputeFileMD5hash(epi::md5hash_c& hash, epi::file_c *file)
938 {
939 int length = file->GetLength();
940
941 if (length <= 0)
942 return;
943
944 byte *buffer = new byte[length];
945
946 // TODO: handle Read failure
947 file->Read(buffer, length);
948
949 hash.Compute(buffer, length);
950
951 delete[] buffer;
952 }
953
FindCacheFilename(std::string & out_name,const char * filename,data_file_c * df,const char * extension)954 static bool FindCacheFilename (std::string& out_name,
955 const char *filename, data_file_c *df,
956 const char *extension)
957 {
958 std::string wad_dir;
959 std::string hash_string;
960 std::string local_name;
961 std::string cache_name;
962
963 // Get the directory which the wad is currently stored
964 wad_dir = epi::PATH_GetDir(filename);
965
966 // Hash string used for files in the cache directory
967 hash_string = epi::STR_Format("-%02X%02X%02X-%02X%02X%02X",
968 df->dir_hash.hash[0], df->dir_hash.hash[1],
969 df->dir_hash.hash[2], df->dir_hash.hash[3],
970 df->dir_hash.hash[4], df->dir_hash.hash[5]);
971
972 // Determine the full path filename for "local" (same-directory) version
973 local_name = epi::PATH_GetBasename(filename);
974 local_name += (".");
975 local_name += (extension);
976
977 local_name = epi::PATH_Join(wad_dir.c_str(), local_name.c_str());
978
979 // Determine the full path filename for the cached version
980 cache_name = epi::PATH_GetBasename(filename);
981 cache_name += (hash_string);
982 cache_name += (".");
983 cache_name += (extension);
984
985 cache_name = epi::PATH_Join(cache_dir.c_str(), cache_name.c_str());
986
987 I_Debugf("FindCacheFilename: local_name = '%s'\n", local_name.c_str());
988 I_Debugf("FindCacheFilename: cache_name = '%s'\n", cache_name.c_str());
989
990 // Check for the existance of the local and cached dir files
991 bool has_local = epi::FS_Access(local_name.c_str(), epi::file_c::ACCESS_READ);
992 bool has_cache = epi::FS_Access(cache_name.c_str(), epi::file_c::ACCESS_READ);
993
994 // If both exist, use the local one.
995 // If neither exist, create one in the cache directory.
996
997 // Check whether the waddir gwa is out of date
998 if (has_local)
999 has_local = (L_CompareFileTimes(filename, local_name.c_str()) <= 0);
1000
1001 // Check whether the cached gwa is out of date
1002 if (has_cache)
1003 has_cache = (L_CompareFileTimes(filename, cache_name.c_str()) <= 0);
1004
1005 I_Debugf("FindCacheFilename: has_local=%s has_cache=%s\n",
1006 has_local ? "YES" : "NO", has_cache ? "YES" : "NO");
1007
1008
1009 if (has_local)
1010 {
1011 out_name = local_name;
1012 return true;
1013 }
1014 else if (has_cache)
1015 {
1016 out_name = cache_name;
1017 return true;
1018 }
1019
1020 // Neither is valid so create one in the cached directory
1021 out_name = cache_name;
1022 return false;
1023 }
1024
1025 //
1026 // AddFile
1027 //
1028 // -AJA- New `dyn_index' parameter -- this is for adding GWA files
1029 // which have been built by the GLBSP plugin. Nothing else is
1030 // supported, e.g. wads with textures/sprites/DDF/RTS.
1031 //
1032 // The dyn_index value is -1 for normal (non-dynamic) files,
1033 // otherwise it is the sort_index for the lumps (typically the
1034 // file number of the wad which the GWA is a companion for).
1035 //
AddFile(const char * filename,int kind,int dyn_index)1036 static void AddFile(const char *filename, int kind, int dyn_index)
1037 {
1038 int j;
1039 int length;
1040 int startlump;
1041
1042 raw_wad_header_t header;
1043 raw_wad_entry_t *curinfo;
1044
1045 // reset the sprite/flat/patch list stuff
1046 within_sprite_list = within_flat_list = false;
1047 within_patch_list = within_colmap_list = false;
1048 within_tex_list = within_hires_list = false;
1049
1050 // open the file and add to directory
1051 epi::file_c *file = epi::FS_Open(filename, epi::file_c::ACCESS_READ | epi::file_c::ACCESS_BINARY);
1052 if (file == NULL)
1053 {
1054 I_Error("Couldn't open file %s\n", filename);
1055 return;
1056 }
1057
1058 I_Printf(" Adding %s\n", filename);
1059
1060 startlump = numlumps;
1061
1062 int datafile = (int)data_files.size();
1063
1064 data_file_c *df = new data_file_c(filename, kind, file);
1065 data_files.push_back(df);
1066
1067 // for RTS scripts, adding the data_file is enough
1068 if (kind == FLKIND_RTS)
1069 return;
1070
1071 if (kind <= FLKIND_HWad)
1072 {
1073 // WAD file
1074 // TODO: handle Read failure
1075 file->Read(&header, sizeof(raw_wad_header_t));
1076
1077 if (strncmp(header.identification, "IWAD", 4) != 0)
1078 {
1079 // Homebrew levels?
1080 if (strncmp(header.identification, "PWAD", 4) != 0)
1081 {
1082 I_Error("Wad file %s doesn't have IWAD or PWAD id\n", filename);
1083 }
1084 }
1085
1086 header.num_entries = EPI_LE_S32(header.num_entries);
1087 header.dir_start = EPI_LE_S32(header.dir_start);
1088
1089 length = header.num_entries * sizeof(raw_wad_entry_t);
1090
1091 raw_wad_entry_t *fileinfo = new raw_wad_entry_t[header.num_entries];
1092
1093 file->Seek(header.dir_start, epi::file_c::SEEKPOINT_START);
1094 // TODO: handle Read failure
1095 file->Read(fileinfo, length);
1096
1097 // compute MD5 hash over wad directory
1098 df->dir_hash.Compute((const byte *)fileinfo, length);
1099
1100 // Fill in lumpinfo
1101 numlumps += header.num_entries;
1102 Z_Resize(lumpinfo, lumpinfo_t, numlumps);
1103
1104 for (j=startlump, curinfo=fileinfo; j < numlumps; j++,curinfo++)
1105 {
1106 AddLump(df, j, EPI_LE_S32(curinfo->pos), EPI_LE_S32(curinfo->size),
1107 datafile,
1108 (dyn_index >= 0) ? dyn_index : datafile,
1109 curinfo->name,
1110 (kind == FLKIND_PWad) || (kind == FLKIND_HWad) );
1111
1112 if (kind != FLKIND_HWad)
1113 CheckForLevel(df, j, lumpinfo[j].name, curinfo, numlumps-1 - j);
1114 }
1115
1116 delete[] fileinfo;
1117 }
1118 else /* single lump file */
1119 {
1120 char lump_name[32];
1121
1122 SYS_ASSERT(dyn_index < 0);
1123
1124 if (kind == FLKIND_DDF)
1125 {
1126 DDF_GetLumpNameForFile(filename, lump_name);
1127 }
1128 else
1129 {
1130 std::string base = epi::PATH_GetBasename(filename);
1131 if (base.size() > 8)
1132 I_Error("Filename base of %s >8 chars", filename);
1133
1134 strcpy(lump_name, base.c_str());
1135 strupr(lump_name); // Required to be uppercase
1136 }
1137
1138 // calculate MD5 hash over whole file
1139 ComputeFileMD5hash(df->dir_hash, file);
1140
1141 // Fill in lumpinfo
1142 numlumps++;
1143 Z_Resize(lumpinfo, lumpinfo_t, numlumps);
1144
1145 AddLump(df, startlump, 0,
1146 file->GetLength(), datafile, datafile,
1147 lump_name, true);
1148 }
1149
1150 I_Debugf(" md5hash = %02x%02x%02x%02x...%02x%02x%02x%02x\n",
1151 df->dir_hash.hash[0], df->dir_hash.hash[1],
1152 df->dir_hash.hash[2], df->dir_hash.hash[3],
1153 df->dir_hash.hash[12], df->dir_hash.hash[13],
1154 df->dir_hash.hash[14], df->dir_hash.hash[15]);
1155
1156 SortLumps();
1157 SortSpriteLumps(df);
1158
1159 // set up caching
1160 Z_Resize(lumplookup, lumpheader_t *, numlumps);
1161
1162 for (j=startlump; j < numlumps; j++)
1163 lumplookup[j] = NULL;
1164
1165 // check for unclosed sprite/flat/patch lists
1166 if (within_sprite_list)
1167 I_Warning("Missing S_END marker in %s.\n", filename);
1168
1169 if (within_flat_list)
1170 I_Warning("Missing F_END marker in %s.\n", filename);
1171
1172 if (within_patch_list)
1173 I_Warning("Missing P_END marker in %s.\n", filename);
1174
1175 if (within_colmap_list)
1176 I_Warning("Missing C_END marker in %s.\n", filename);
1177
1178 if (within_tex_list)
1179 I_Warning("Missing TX_END marker in %s.\n", filename);
1180
1181 if (within_hires_list)
1182 I_Warning("Missing HI_END marker in %s.\n", filename);
1183
1184 // -AJA- 1999/12/25: What did Santa bring EDGE ? Just some support
1185 // for "GWA" files (part of the "GL-Friendly Nodes" specs).
1186
1187 if (kind <= FLKIND_EWad && df->level_markers.GetSize() > 0)
1188 {
1189 if (HasInternalGLNodes(df, datafile))
1190 {
1191 df->companion_gwa = datafile;
1192 }
1193 else
1194 {
1195 SYS_ASSERT(dyn_index < 0);
1196
1197 std::string gwa_filename;
1198
1199 bool exists = FindCacheFilename(gwa_filename, filename, df, EDGEGWAEXT);
1200
1201 I_Debugf("Actual_GWA_filename: %s\n", gwa_filename.c_str());
1202
1203 if (! exists)
1204 {
1205 I_Printf("Building GL Nodes for: %s\n", filename);
1206
1207 if (! GB_BuildNodes(filename, gwa_filename.c_str()))
1208 I_Error("Failed to build GL nodes for: %s\n", filename);
1209 }
1210
1211 // Load it. This recursion bit is rather sneaky,
1212 // hopefully it doesn't break anything...
1213 AddFile(gwa_filename.c_str(), FLKIND_GWad, datafile);
1214
1215 df->companion_gwa = datafile + 1;
1216 }
1217 }
1218
1219 // handle DeHackEd patch files
1220 if (kind == FLKIND_Deh || df->deh_lump >= 0)
1221 {
1222 std::string hwa_filename;
1223
1224 char base_name[64];
1225 sprintf(base_name, "DEH_%04d.%s", datafile, EDGEHWAEXT);
1226
1227 hwa_filename = epi::PATH_Join(cache_dir.c_str(), base_name);
1228
1229 I_Debugf("Actual_HWA_filename: %s\n", hwa_filename.c_str());
1230
1231 if (kind == FLKIND_Deh)
1232 {
1233 I_Printf("Converting DEH file: %s\n", filename);
1234
1235 if (! DH_ConvertFile(filename, hwa_filename.c_str()))
1236 I_Error("Failed to convert DeHackEd patch: %s\n", filename);
1237 }
1238 else
1239 {
1240 const char *lump_name = lumpinfo[df->deh_lump].name;
1241
1242 I_Printf("Converting [%s] lump in: %s\n", lump_name, filename);
1243
1244 const byte *data = (const byte *)W_CacheLumpNum(df->deh_lump);
1245 int length = W_LumpLength(df->deh_lump);
1246
1247 if (! DH_ConvertLump(data, length, lump_name, hwa_filename.c_str()))
1248 I_Error("Failed to convert DeHackEd LUMP in: %s\n", filename);
1249
1250 W_DoneWithLump(data);
1251 }
1252
1253 // Load it (using good ol' recursion again).
1254 AddFile(hwa_filename.c_str(), FLKIND_HWad, -1);
1255 }
1256 }
1257
InitCaches(void)1258 static void InitCaches(void)
1259 {
1260 lumphead.next = lumphead.prev = &lumphead;
1261 }
1262
1263 //
1264 // W_AddRawFilename
1265 //
W_AddRawFilename(const char * file,int kind)1266 void W_AddRawFilename(const char *file, int kind)
1267 {
1268 I_Debugf("Added filename: %s\n", file);
1269
1270 wadfiles.push_back(new raw_filename_c(file, kind));
1271 }
1272
1273 //
1274 // W_InitMultipleFiles
1275 //
1276 // Pass a null terminated list of files to use.
1277 // Files with a .wad extension are idlink files with multiple lumps.
1278 // Other files are single lumps with the base filename for the lump name.
1279 // Lump names can appear multiple times.
1280 // The name searcher looks backwards, so a later file
1281 // does override all earlier ones.
1282 //
W_InitMultipleFiles(void)1283 void W_InitMultipleFiles(void)
1284 {
1285 InitCaches();
1286
1287 // open all the files, load headers, and count lumps
1288 numlumps = 0;
1289
1290 // will be realloced as lumps are added
1291 lumpinfo = NULL;
1292
1293 std::list<raw_filename_c *>::iterator it;
1294
1295 for (it = wadfiles.begin(); it != wadfiles.end(); it++)
1296 {
1297 raw_filename_c *rf = *it;
1298 AddFile(rf->filename.c_str(), rf->kind, -1);
1299 }
1300
1301 if (numlumps == 0)
1302 I_Error("W_InitMultipleFiles: no files found!\n");
1303 }
1304
TryLoadExtraLanguage(const char * name)1305 static bool TryLoadExtraLanguage(const char *name)
1306 {
1307 int lumpnum = W_CheckNumForName(name);
1308
1309 if (lumpnum < 0)
1310 return false;
1311
1312 I_Printf("Loading Languages from %s\n", name);
1313
1314 int length;
1315 char *data = (char *) W_ReadLumpAlloc(lumpnum, &length);
1316
1317 DDF_ReadLangs(data, length);
1318 delete[] data;
1319
1320 return true;
1321 }
1322
1323 // MUNDO HACK, but if only fixable by a new wad structure...
LoadTntPlutStrings(void)1324 static void LoadTntPlutStrings(void)
1325 {
1326 if (DDF_CompareName(iwad_base.c_str(), "TNT") == 0)
1327 TryLoadExtraLanguage("TNTLANG");
1328
1329 if (DDF_CompareName(iwad_base.c_str(), "PLUTONIA") == 0)
1330 TryLoadExtraLanguage("PLUTLANG");
1331 }
1332
1333
W_ReadDDF(void)1334 void W_ReadDDF(void)
1335 {
1336 // -AJA- the order here may look strange. Since DDF files
1337 // have dependencies between them, it makes more sense to
1338 // load all lumps of a certain type together (e.g. all
1339 // DDFSFX lumps before all the DDFTHING lumps).
1340
1341 for (int d = 0; d < NUM_DDF_READERS; d++)
1342 {
1343 if (true)
1344 {
1345 I_Printf("Loading external %s\n", DDF_Readers[d].print_name);
1346
1347 // call read function
1348 (* DDF_Readers[d].func)(NULL, 0);
1349 }
1350
1351 for (int f = 0; f < (int)data_files.size(); f++)
1352 {
1353 data_file_c *df = data_files[f];
1354
1355 // all script files get parsed here
1356 if (d == RTS_READER && df->kind == FLKIND_RTS)
1357 {
1358 I_Printf("Loading RTS script: %s\n", df->file_name);
1359
1360 RAD_LoadFile(df->file_name);
1361 continue;
1362 }
1363
1364 if (df->kind >= FLKIND_Demo)
1365 continue;
1366
1367 if (df->kind == FLKIND_EWad)
1368 {
1369 // special handling for TNT and Plutonia
1370 if (d == LANG_READER)
1371 LoadTntPlutStrings();
1372
1373 continue;
1374 }
1375
1376 int lump = df->ddf_lumps[d];
1377
1378 if (lump >= 0)
1379 {
1380 I_Printf("Loading %s from: %s\n", DDF_Readers[d].name, df->file_name);
1381
1382 int length;
1383 char *data = (char *) W_ReadLumpAlloc(lump, &length);
1384
1385 // call read function
1386 (* DDF_Readers[d].func)(data, length);
1387 delete[] data;
1388 }
1389
1390 // handle Boom's ANIMATED and SWITCHES lumps
1391 if (d == ANIM_READER && df->animated >= 0)
1392 {
1393 I_Printf("Loading ANIMATED from: %s\n", df->file_name);
1394
1395 int length;
1396 byte *data = W_ReadLumpAlloc(df->animated, &length);
1397
1398 DDF_ParseANIMATED(data, length);
1399 delete[] data;
1400 }
1401 if (d == SWTH_READER && df->switches >= 0)
1402 {
1403 I_Printf("Loading SWITCHES from: %s\n", df->file_name);
1404
1405 int length;
1406 byte *data = W_ReadLumpAlloc(df->switches, &length);
1407
1408 DDF_ParseSWITCHES(data, length);
1409 delete[] data;
1410 }
1411
1412 // handle BOOM Colourmaps (between C_START and C_END)
1413 if (d == COLM_READER && df->colmap_lumps.GetSize() > 0)
1414 {
1415 for (int i=0; i < df->colmap_lumps.GetSize(); i++)
1416 {
1417 int lump = df->colmap_lumps[i];
1418
1419 DDF_ColourmapAddRaw(W_GetLumpName(lump), W_LumpLength(lump));
1420 }
1421 }
1422 }
1423
1424 /// std::string msg_buf(epi::STR_Format(
1425 /// "Loaded %s %s\n", (d == NUM_DDF_READERS-1) ? "RTS" : "DDF",
1426 /// DDF_Readers[d].print_name));
1427 ///
1428 /// E_ProgressMessage(msg_buf.c_str());
1429
1430 E_LocalProgress(d, NUM_DDF_READERS);
1431 }
1432 }
1433
W_ReadCoalLumps(void)1434 void W_ReadCoalLumps(void)
1435 {
1436 for (int f = 0; f < (int)data_files.size(); f++)
1437 {
1438 data_file_c *df = data_files[f];
1439
1440 if (df->kind > FLKIND_Lump)
1441 continue;
1442
1443 if (df->coal_huds < 0)
1444 continue;
1445
1446 VM_LoadLumpOfCoal(df->coal_huds);
1447 }
1448 }
1449
W_OpenLump(int lump)1450 epi::file_c *W_OpenLump(int lump)
1451 {
1452 SYS_ASSERT(0 <= lump && lump < numlumps);
1453
1454 lumpinfo_t *l = lumpinfo + lump;
1455
1456 data_file_c *df = data_files[l->file];
1457
1458 SYS_ASSERT(df->file);
1459
1460 return new epi::sub_file_c(df->file, l->position, l->size);
1461 }
1462
W_OpenLump(const char * name)1463 epi::file_c *W_OpenLump(const char *name)
1464 {
1465 return W_OpenLump(W_GetNumForName(name));
1466 }
1467
1468 //
1469 // W_GetFileName
1470 //
1471 // Returns the filename of the WAD file containing the given lump, or
1472 // NULL if it wasn't a WAD file (e.g. a pure lump).
1473 //
W_GetFileName(int lump)1474 const char *W_GetFileName(int lump)
1475 {
1476 SYS_ASSERT(0 <= lump && lump < numlumps);
1477
1478 lumpinfo_t *l = lumpinfo + lump;
1479
1480 data_file_c *df = data_files[l->file];
1481
1482 if (df->kind >= FLKIND_Lump)
1483 return NULL;
1484
1485 return df->file_name;
1486 }
1487
1488 //
1489 // W_GetPaletteForLump
1490 //
1491 // Returns the palette lump that should be used for the given lump
1492 // (presumably an image), otherwise -1 (indicating that the global
1493 // palette should be used).
1494 //
1495 // NOTE: when the same WAD as the lump does not contain a palette,
1496 // there are two possibilities: search backwards for the "closest"
1497 // palette, or simply return -1. Neither one is ideal, though I tend
1498 // to think that searching backwards is more intuitive.
1499 //
1500 // NOTE 2: the palette_datafile stuff is there so we always return -1
1501 // for the "GLOBAL" palette.
1502 //
W_GetPaletteForLump(int lump)1503 int W_GetPaletteForLump(int lump)
1504 {
1505 SYS_ASSERT(0 <= lump && lump < numlumps);
1506
1507 int f = lumpinfo[lump].file;
1508
1509 for (; f > palette_datafile; f--)
1510 {
1511 data_file_c *df = data_files[f];
1512
1513 if (df->kind >= FLKIND_Lump)
1514 continue;
1515
1516 if (df->wadtex.palette >= 0)
1517 return df->wadtex.palette;
1518 }
1519
1520 // none found
1521 return -1;
1522 }
1523
1524
QuickFindLumpMap(char * buf)1525 static inline int QuickFindLumpMap(char *buf)
1526 {
1527 int i;
1528
1529 #define CMP(a) (LUMP_MAP_CMP(a) < 0)
1530 BSEARCH(numlumps, i);
1531 #undef CMP
1532
1533 if (i < 0 || i >= numlumps || LUMP_MAP_CMP(i) != 0)
1534 {
1535 // not found (nothing has that name)
1536 return -1;
1537 }
1538
1539 // jump to first matching name
1540 while (i > 0 && LUMP_MAP_CMP(i-1) == 0)
1541 i--;
1542
1543 return i;
1544 }
1545
1546
1547 //
1548 // W_CheckNumForName
1549 //
1550 // Returns -1 if name not found.
1551 //
1552 // -ACB- 1999/09/18 Added name to error message
1553 //
W_CheckNumForName2(const char * name)1554 int W_CheckNumForName2(const char *name)
1555 {
1556 int i;
1557 char buf[9];
1558
1559 for (i = 0; name[i]; i++)
1560 {
1561 if (i > 8)
1562 {
1563 I_Warning("W_CheckNumForName: Name '%s' longer than 8 chars!\n", name);
1564 return -1;
1565 }
1566 buf[i] = toupper(name[i]);
1567 }
1568 buf[i] = 0;
1569
1570 i = QuickFindLumpMap(buf);
1571
1572 if (i < 0)
1573 return -1; // not found
1574
1575 return lumpmap[i];
1576 }
1577
1578
W_CheckNumForName_GFX(const char * name)1579 int W_CheckNumForName_GFX(const char *name)
1580 {
1581 // this looks for a graphic lump, skipping anything which would
1582 // not be suitable (especially flats and HIRES replacements).
1583
1584 int i;
1585 char buf[9];
1586
1587 for (i = 0; name[i]; i++)
1588 {
1589 if (i > 8)
1590 {
1591 I_Warning("W_CheckNumForName: Name '%s' longer than 8 chars!\n", name);
1592 return -1;
1593 }
1594 buf[i] = toupper(name[i]);
1595 }
1596 buf[i] = 0;
1597
1598 // search backwards
1599 for (i = numlumps-1; i >= 0; i--)
1600 {
1601 if (lumpinfo[i].kind == LMKIND_Normal ||
1602 lumpinfo[i].kind == LMKIND_Sprite ||
1603 lumpinfo[i].kind == LMKIND_Patch)
1604 {
1605 if (strncmp(lumpinfo[i].name, buf, 8) == 0)
1606 return i;
1607 }
1608 }
1609
1610 return -1; // not found
1611 }
1612
1613 //
1614 // W_GetNumForName
1615 //
1616 // Calls W_CheckNumForName, but bombs out if not found.
1617 //
W_GetNumForName2(const char * name)1618 int W_GetNumForName2(const char *name)
1619 {
1620 int i;
1621
1622 if ((i = W_CheckNumForName2(name)) == -1)
1623 I_Error("W_GetNumForName: \'%.8s\' not found!", name);
1624
1625 return i;
1626 }
1627
1628 //
1629 // W_CheckNumForTexPatch
1630 //
1631 // Returns -1 if name not found.
1632 //
1633 // -AJA- 2004/06/24: Patches should be within the P_START/P_END markers,
1634 // so we should look there first. Also we should never return a
1635 // flat as a tex-patch.
1636 //
W_CheckNumForTexPatch(const char * name)1637 int W_CheckNumForTexPatch(const char *name)
1638 {
1639 int i;
1640 char buf[10];
1641
1642 for (i = 0; name[i]; i++)
1643 {
1644 #ifdef DEVELOPERS
1645 if (i > 8)
1646 I_Error("W_CheckNumForTexPatch: '%s' longer than 8 chars!", name);
1647 #endif
1648 buf[i] = toupper(name[i]);
1649 }
1650 buf[i] = 0;
1651
1652 i = QuickFindLumpMap(buf);
1653
1654 if (i < 0)
1655 return -1; // not found
1656
1657 for (; i < numlumps && LUMP_MAP_CMP(i) == 0; i++)
1658 {
1659 lumpinfo_t *L = lumpinfo + lumpmap[i];
1660
1661 if (L->kind == LMKIND_Patch || L->kind == LMKIND_Sprite ||
1662 L->kind == LMKIND_Normal)
1663 {
1664 // allow LMKIND_Normal to support patches outside of the
1665 // P_START/END markers. We especially want to disallow
1666 // flat and colourmap lumps.
1667 return lumpmap[i];
1668 }
1669 }
1670
1671 return -1; // nothing suitable
1672 }
1673
1674 //
1675 // W_VerifyLumpName
1676 //
1677 // Verifies that the given lump number is valid and has the given
1678 // name.
1679 //
1680 // -AJA- 1999/11/26: written.
1681 //
W_VerifyLumpName(int lump,const char * name)1682 bool W_VerifyLumpName(int lump, const char *name)
1683 {
1684 if (lump >= numlumps)
1685 return false;
1686
1687 return (strncmp(lumpinfo[lump].name, name, 8) == 0);
1688 }
1689
1690 //
1691 // W_LumpLength
1692 //
1693 // Returns the buffer size needed to load the given lump.
1694 //
W_LumpLength(int lump)1695 int W_LumpLength(int lump)
1696 {
1697 if (lump >= numlumps)
1698 I_Error("W_LumpLength: %i >= numlumps", lump);
1699
1700 return lumpinfo[lump].size;
1701 }
1702
1703 //
1704 // W_FindFlatSequence
1705 //
1706 // Returns the file number containing the sequence, or -1 if not
1707 // found. Search is from newest wad file to oldest wad file.
1708 //
W_FindFlatSequence(const char * start,const char * end,int * s_offset,int * e_offset)1709 int W_FindFlatSequence(const char *start, const char *end,
1710 int *s_offset, int *e_offset)
1711 {
1712 for (int file = (int)data_files.size()-1; file >= 0; file--)
1713 {
1714 data_file_c *df = data_files[file];
1715
1716 // look for start name
1717 int i;
1718 for (i=0; i < df->flat_lumps.GetSize(); i++)
1719 {
1720 if (strncmp(start, W_GetLumpName(df->flat_lumps[i]), 8) == 0)
1721 break;
1722 }
1723
1724 if (i >= df->flat_lumps.GetSize())
1725 continue;
1726
1727 (*s_offset) = i;
1728
1729 // look for end name
1730 for (i++; i < df->flat_lumps.GetSize(); i++)
1731 {
1732 if (strncmp(end, W_GetLumpName(df->flat_lumps[i]), 8) == 0)
1733 {
1734 (*e_offset) = i;
1735 return file;
1736 }
1737 }
1738 }
1739
1740 // not found
1741 return -1;
1742 }
1743
1744
1745 //
1746 // Returns NULL for an empty list.
1747 //
W_GetListLumps(int file,lumplist_e which)1748 epi::u32array_c& W_GetListLumps(int file, lumplist_e which)
1749 {
1750 SYS_ASSERT(0 <= file && file < (int)data_files.size());
1751
1752 data_file_c *df = data_files[file];
1753
1754 switch (which)
1755 {
1756 case LMPLST_Sprites: return df->sprite_lumps;
1757 case LMPLST_Flats: return df->flat_lumps;
1758 case LMPLST_Patches: return df->patch_lumps;
1759
1760 default: break;
1761 }
1762
1763 I_Error("W_GetListLumps: bad `which' (%d)\n", which);
1764 return df->sprite_lumps; /* NOT REACHED */
1765 }
1766
1767
W_GetNumFiles(void)1768 int W_GetNumFiles(void)
1769 {
1770 return (int)data_files.size();
1771 }
1772
1773
W_GetFileForLump(int lump)1774 int W_GetFileForLump(int lump)
1775 {
1776 SYS_ASSERT(lump >= 0 && lump < numlumps);
1777
1778 return lumpinfo[lump].file;
1779 }
1780
1781
1782 //
1783 // Loads the lump into the given buffer,
1784 // which must be >= W_LumpLength().
1785 //
W_ReadLump(int lump,void * dest)1786 static void W_ReadLump(int lump, void *dest)
1787 {
1788 if (lump >= numlumps)
1789 I_Error("W_ReadLump: %i >= numlumps", lump);
1790
1791 lumpinfo_t *L = lumpinfo + lump;
1792 data_file_c *df = data_files[L->file];
1793
1794 // -KM- 1998/07/31 This puts the loading icon in the corner of the screen :-)
1795 display_disk = true;
1796
1797 df->file->Seek(L->position, epi::file_c::SEEKPOINT_START);
1798
1799 int c = df->file->Read(dest, L->size);
1800
1801 if (c < L->size)
1802 I_Error("W_ReadLump: only read %i of %i on lump %i", c, L->size, lump);
1803 }
1804
1805 // FIXME !!! merge W_ReadLumpAlloc and W_LoadLumpNum into one good function
W_ReadLumpAlloc(int lump,int * length)1806 byte *W_ReadLumpAlloc(int lump, int *length)
1807 {
1808 *length = W_LumpLength(lump);
1809
1810 byte *data = new byte[*length + 1];
1811
1812 W_ReadLump(lump, data);
1813
1814 data[*length] = 0;
1815
1816 return data;
1817 }
1818
1819 //
1820 // W_DoneWithLump
1821 //
W_DoneWithLump(const void * ptr)1822 void W_DoneWithLump(const void *ptr)
1823 {
1824 lumpheader_t *h = ((lumpheader_t *)ptr); // Intentional Const Override
1825
1826 #ifdef DEVELOPERS
1827 if (h == NULL)
1828 I_Error("W_DoneWithLump: NULL pointer");
1829 if (h[-1].id != lumpheader_s::LUMPID)
1830 I_Error("W_DoneWithLump: id != LUMPID");
1831 if (h[-1].users == 0)
1832 I_Error("W_DoneWithLump: lump %d has no users!", h[-1].lumpindex);
1833 #endif
1834 h--;
1835 h->users--;
1836 if (h->users == 0)
1837 {
1838 // Move the item to the tail.
1839 h->prev->next = h->next;
1840 h->next->prev = h->prev;
1841 h->prev = lumphead.prev;
1842 h->next = &lumphead;
1843 h->prev->next = h;
1844 h->next->prev = h;
1845 MarkAsCached(h);
1846 }
1847 }
1848
1849 //
1850 // W_DoneWithLump_Flushable
1851 //
1852 // Call this if the lump probably won't be used for a while, to hint the
1853 // system to flush it early.
1854 //
1855 // Useful if you are creating a cache for e.g. some kind of lump
1856 // conversions (like the sound cache).
1857 //
W_DoneWithLump_Flushable(const void * ptr)1858 void W_DoneWithLump_Flushable(const void *ptr)
1859 {
1860 lumpheader_t *h = ((lumpheader_t *)ptr); // Intentional Const Override
1861
1862 #ifdef DEVELOPERS
1863 if (h == NULL)
1864 I_Error("W_DoneWithLump: NULL pointer");
1865 h--;
1866 if (h->id != lumpheader_s::LUMPID)
1867 I_Error("W_DoneWithLump: id != LUMPID");
1868 if (h->users == 0)
1869 I_Error("W_DoneWithLump: lump %d has no users!", h->lumpindex);
1870 #endif
1871 h->users--;
1872 if (h->users == 0)
1873 {
1874 // Move the item to the head of the list.
1875 h->prev->next = h->next;
1876 h->next->prev = h->prev;
1877 h->next = lumphead.next;
1878 h->prev = &lumphead;
1879 h->prev->next = h;
1880 h->next->prev = h;
1881 MarkAsCached(h);
1882 }
1883 }
1884
1885 //
1886 // W_CacheLumpNum
1887 //
W_CacheLumpNum2(int lump)1888 const void *W_CacheLumpNum2 (int lump)
1889 {
1890 lumpheader_t *h;
1891
1892 #ifdef DEVELOPERS
1893 if ((unsigned int)lump >= (unsigned int)numlumps)
1894 I_Error("W_CacheLumpNum: %i >= numlumps", lump);
1895 #endif
1896
1897 h = lumplookup[lump];
1898
1899 if (h)
1900 {
1901 // cache hit
1902 if (h->users == 0)
1903 cache_size -= W_LumpLength(h->lumpindex);
1904 h->users++;
1905 }
1906 else
1907 {
1908 // cache miss. load the new item.
1909 h = (lumpheader_t *) Z_Malloc(sizeof(lumpheader_t) + W_LumpLength(lump));
1910 lumplookup[lump] = h;
1911 #ifdef DEVELOPERS
1912 h->id = lumpheader_s::LUMPID;
1913 #endif
1914 h->lumpindex = lump;
1915 h->users = 1;
1916 h->prev = lumphead.prev;
1917 h->next = &lumphead;
1918 h->prev->next = h;
1919 lumphead.prev = h;
1920
1921 W_ReadLump(lump, (void *)(h + 1));
1922 }
1923
1924 return (void *)(h + 1);
1925 }
1926
1927 //
1928 // W_CacheLumpName
1929 //
W_CacheLumpName2(const char * name)1930 const void *W_CacheLumpName2(const char *name)
1931 {
1932 return W_CacheLumpNum2(W_GetNumForName2(name));
1933 }
1934
1935 //
1936 // W_PreCacheLumpNum
1937 //
1938 // Attempts to load lump into the cache, if it isn't already there
1939 //
W_PreCacheLumpNum(int lump)1940 void W_PreCacheLumpNum(int lump)
1941 {
1942 W_DoneWithLump(W_CacheLumpNum(lump));
1943 }
1944
1945 //
1946 // W_PreCacheLumpName
1947 //
W_PreCacheLumpName(const char * name)1948 void W_PreCacheLumpName(const char *name)
1949 {
1950 W_DoneWithLump(W_CacheLumpName(name));
1951 }
1952
1953 //
1954 // W_CacheInfo
1955 //
W_CacheInfo(int level)1956 int W_CacheInfo(int level)
1957 {
1958 lumpheader_t *h;
1959 int value = 0;
1960
1961 for (h = lumphead.next; h != &lumphead; h = h->next)
1962 {
1963 if ((level & 1) && h->users)
1964 value += W_LumpLength(h->lumpindex);
1965 if ((level & 2) && !h->users)
1966 value += W_LumpLength(h->lumpindex);
1967 }
1968 return value;
1969 }
1970
1971 //
1972 // W_LoadLumpNum
1973 //
1974 // Returns a copy of the lump (it is your responsibility to free it)
1975 //
W_LoadLumpNum(int lump)1976 void *W_LoadLumpNum(int lump)
1977 {
1978 void *p;
1979 const void *cached;
1980 int length = W_LumpLength(lump);
1981 p = (void *) Z_Malloc(length);
1982 cached = W_CacheLumpNum2(lump);
1983 memcpy(p, cached, length);
1984 W_DoneWithLump(cached);
1985 return p;
1986 }
1987
1988 //
1989 // W_LoadLumpName
1990 //
W_LoadLumpName(const char * name)1991 void *W_LoadLumpName(const char *name)
1992 {
1993 return W_LoadLumpNum(W_GetNumForName2(name));
1994 }
1995
1996 //
1997 // W_GetLumpName
1998 //
W_GetLumpName(int lump)1999 const char *W_GetLumpName(int lump)
2000 {
2001 return lumpinfo[lump].name;
2002 }
2003
2004
W_ProcessTX_HI(void)2005 void W_ProcessTX_HI(void)
2006 {
2007 // Add the textures that occur in between TX_START/TX_END markers
2008
2009 // TODO: collect names, remove duplicates
2010
2011 for (int file = 0; file < (int)data_files.size(); file++)
2012 {
2013 data_file_c *df = data_files[file];
2014
2015 for (int i = 0; i < (int)df->tx_lumps.GetSize(); i++)
2016 {
2017 int lump = df->tx_lumps[i];
2018 W_ImageAddTX(lump, W_GetLumpName(lump), false);
2019 }
2020 }
2021
2022 // Add the textures that occur in between HI_START/HI_END markers
2023
2024 for (int file = 0; file < (int)data_files.size(); file++)
2025 {
2026 data_file_c *df = data_files[file];
2027
2028 for (int i = 0; i < (int)df->hires_lumps.GetSize(); i++)
2029 {
2030 int lump = df->hires_lumps[i];
2031 W_ImageAddTX(lump, W_GetLumpName(lump), true);
2032 }
2033 }
2034 }
2035
2036
2037 static const char *FileKind_Strings[] =
2038 {
2039 "iwad", "pwad", "edge", "gwa", "hwa",
2040 "lump", "ddf", "demo", "rts", "deh",
2041 "???", "???", "???", "???"
2042 };
2043
2044 static const char *LumpKind_Strings[] =
2045 {
2046 "normal", "???", "???",
2047 "marker", "???", "???",
2048 "wadtex", "???", "???", "???",
2049 "ddf", "???", "???", "???",
2050
2051 "tx", "colmap", "flat", "sprite", "patch",
2052 "???", "???", "???", "???"
2053 };
2054
2055
W_ShowLumps(int for_file,const char * match)2056 void W_ShowLumps(int for_file, const char *match)
2057 {
2058 I_Printf("Lump list:\n");
2059
2060 int total = 0;
2061
2062 for (int i = 0; i < numlumps; i++)
2063 {
2064 lumpinfo_t *L = &lumpinfo[i];
2065
2066 if (for_file >= 1 && L->file != for_file-1)
2067 continue;
2068
2069 if (match && *match)
2070 if (! strstr(L->name, match))
2071 continue;
2072
2073 I_Printf(" %4d %-9s %2d %-6s %7d @ 0x%08x\n",
2074 i+1, L->name,
2075 L->file+1, LumpKind_Strings[L->kind],
2076 L->size, L->position);
2077 total++;
2078 }
2079
2080 I_Printf("Total: %d\n", total);
2081 }
2082
W_ShowFiles(void)2083 void W_ShowFiles(void)
2084 {
2085 I_Printf("File list:\n");
2086
2087 for (int i = 0; i < (int)data_files.size(); i++)
2088 {
2089 data_file_c *df = data_files[i];
2090
2091 I_Printf(" %2d %-4s \"%s\"\n", i+1, FileKind_Strings[df->kind], df->file_name);
2092 }
2093 }
2094
2095
2096 //--- editor settings ---
2097 // vi:ts=4:sw=4:noexpandtab
2098