]> git.xonotic.org Git - xonotic/darkplaces.git/blob - wad.c
r_showsurfaces: fix "ghost normals"
[xonotic/darkplaces.git] / wad.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20
21
22 #include "quakedef.h"
23 #include "image.h"
24 #include "wad.h"
25
26 typedef struct mwad_s
27 {
28         qfile_t *file;
29         int numlumps;
30         lumpinfo_t *lumps;
31 }
32 mwad_t;
33
34 typedef struct wadstate_s
35 {
36         unsigned char *gfx_base;
37         mwad_t gfx;
38         memexpandablearray_t hlwads;
39 }
40 wadstate_t;
41
42 static wadstate_t wad;
43
44 /*
45 ==================
46 W_CleanupName
47
48 Lowercases name and pads with spaces and a terminating 0 to the length of
49 lumpinfo_t->name.
50 Used so lumpname lookups can proceed rapidly by comparing 4 chars at a time
51 Space padding is so names can be printed nicely in tables.
52 Can safely be performed in place.
53 ==================
54 */
55 static void W_CleanupName (const char *in, char *out)
56 {
57         int             i;
58         int             c;
59
60         for (i=0 ; i<16 ; i++ )
61         {
62                 c = in[i];
63                 if (!c)
64                         break;
65
66                 if (c >= 'A' && c <= 'Z')
67                         c += ('a' - 'A');
68                 out[i] = c;
69         }
70
71         for ( ; i< 16 ; i++ )
72                 out[i] = 0;
73 }
74
75 static void W_SwapLumps(int numlumps, lumpinfo_t *lumps)
76 {
77         int i;
78         for (i = 0;i < numlumps;i++)
79         {
80                 lumps[i].filepos = LittleLong(lumps[i].filepos);
81                 lumps[i].disksize = LittleLong(lumps[i].disksize);
82                 lumps[i].size = LittleLong(lumps[i].size);
83                 W_CleanupName(lumps[i].name, lumps[i].name);
84         }
85 }
86
87 void W_UnloadAll(void)
88 {
89         unsigned int i;
90         mwad_t *w;
91         // free gfx.wad if it is loaded
92         if (wad.gfx_base)
93                 Mem_Free(wad.gfx_base);
94         wad.gfx_base = NULL;
95         // close all hlwad files and free their lumps data
96         for (i = 0;i < Mem_ExpandableArray_IndexRange(&wad.hlwads);i++)
97         {
98                 w = (mwad_t *) Mem_ExpandableArray_RecordAtIndex(&wad.hlwads, i);
99                 if (!w)
100                         continue;
101                 if (w->file)
102                         FS_Close(w->file);
103                 w->file = NULL;
104                 if (w->lumps)
105                         Mem_Free(w->lumps);
106                 w->lumps = NULL;
107         }
108         // free the hlwads array
109         Mem_ExpandableArray_FreeArray(&wad.hlwads);
110         // clear all state
111         memset(&wad, 0, sizeof(wad));
112 }
113
114 unsigned char *W_GetLumpName(const char *name)
115 {
116         int i;
117         fs_offset_t filesize;
118         lumpinfo_t *lump;
119         char clean[16];
120         wadinfo_t *header;
121         int infotableofs;
122
123         W_CleanupName (name, clean);
124
125         if (!wad.gfx_base)
126         {
127                 if ((wad.gfx_base = FS_LoadFile ("gfx.wad", cls.permanentmempool, false, &filesize)))
128                 {
129                         if (memcmp(wad.gfx_base, "WAD2", 4))
130                         {
131                                 Con_Print("gfx.wad doesn't have WAD2 id\n");
132                                 Mem_Free(wad.gfx_base);
133                                 wad.gfx_base = NULL;
134                         }
135                         else
136                         {
137                                 header = (wadinfo_t *)wad.gfx_base;
138                                 wad.gfx.numlumps = LittleLong(header->numlumps);
139                                 infotableofs = LittleLong(header->infotableofs);
140                                 wad.gfx.lumps = (lumpinfo_t *)(wad.gfx_base + infotableofs);
141
142                                 // byteswap the gfx.wad lumps in place
143                                 W_SwapLumps(wad.gfx.numlumps, wad.gfx.lumps);
144                         }
145                 }
146         }
147
148         for (lump = wad.gfx.lumps, i = 0;i < wad.gfx.numlumps;i++, lump++)
149                 if (!strcmp(clean, lump->name))
150                         return (wad.gfx_base + lump->filepos);
151         return NULL;
152 }
153
154 /*
155 ====================
156 W_LoadTextureWadFile
157 ====================
158 */
159 void W_LoadTextureWadFile (char *filename, int complain)
160 {
161         wadinfo_t               header;
162         int                             infotableofs;
163         qfile_t                 *file;
164         int                             numlumps;
165         mwad_t                  *w;
166
167         file = FS_OpenVirtualFile(filename, false);
168         if (!file)
169         {
170                 if (complain)
171                         Con_Printf("W_LoadTextureWadFile: couldn't find %s\n", filename);
172                 return;
173         }
174
175         if (FS_Read(file, &header, sizeof(wadinfo_t)) != sizeof(wadinfo_t))
176         {Con_Print("W_LoadTextureWadFile: unable to read wad header\n");FS_Close(file);file = NULL;return;}
177
178         if(memcmp(header.identification, "WAD3", 4))
179         {Con_Printf("W_LoadTextureWadFile: Wad file %s doesn't have WAD3 id\n",filename);FS_Close(file);file = NULL;return;}
180
181         numlumps = LittleLong(header.numlumps);
182         if (numlumps < 1 || numlumps > 65536)
183         {Con_Printf("W_LoadTextureWadFile: invalid number of lumps (%i)\n", numlumps);FS_Close(file);file = NULL;return;}
184         infotableofs = LittleLong(header.infotableofs);
185         if (FS_Seek (file, infotableofs, SEEK_SET))
186         {Con_Print("W_LoadTextureWadFile: unable to seek to lump table\n");FS_Close(file);file = NULL;return;}
187
188         if (!wad.hlwads.mempool)
189                 Mem_ExpandableArray_NewArray(&wad.hlwads, cls.permanentmempool, sizeof(mwad_t), 16);
190         w = (mwad_t *) Mem_ExpandableArray_AllocRecord(&wad.hlwads);
191         w->file = file;
192         w->numlumps = numlumps;
193         w->lumps = (lumpinfo_t *) Mem_Alloc(cls.permanentmempool, w->numlumps * sizeof(lumpinfo_t));
194
195         if (!w->lumps)
196         {
197                 Con_Print("W_LoadTextureWadFile: unable to allocate temporary memory for lump table\n");
198                 FS_Close(w->file);
199                 w->file = NULL;
200                 w->numlumps = 0;
201                 return;
202         }
203
204         if (FS_Read(file, w->lumps, sizeof(lumpinfo_t) * w->numlumps) != (fs_offset_t)sizeof(lumpinfo_t) * numlumps)
205         {
206                 Con_Print("W_LoadTextureWadFile: unable to read lump table\n");
207                 FS_Close(w->file);
208                 w->file = NULL;
209                 w->numlumps = 0;
210                 Mem_Free(w->lumps);
211                 w->lumps = NULL;
212                 return;
213         }
214
215         W_SwapLumps(w->numlumps, w->lumps);
216
217         // leaves the file open
218 }
219
220 unsigned char *W_ConvertWAD3TextureBGRA(miptex_t *tex)
221 {
222         unsigned char *in, *data, *out, *pal;
223         int d, p;
224
225         in = (unsigned char *)tex + tex->offsets[0];
226         data = out = (unsigned char *)Mem_Alloc(tempmempool, tex->width * tex->height * 4);
227         if (!data)
228                 return NULL;
229         image_width = tex->width;
230         image_height = tex->height;
231         pal = in + (((image_width * image_height) * 85) >> 6);
232         pal += 2;
233         for (d = 0;d < image_width * image_height;d++)
234         {
235                 p = *in++;
236                 if (tex->name[0] == '{' && p == 255)
237                         out[0] = out[1] = out[2] = out[3] = 0;
238                 else
239                 {
240                         p *= 3;
241                         out[2] = pal[p];
242                         out[1] = pal[p+1];
243                         out[0] = pal[p+2];
244                         out[3] = 255;
245                 }
246                 out += 4;
247         }
248         return data;
249 }
250
251 unsigned char *W_GetTextureBGRA(char *name)
252 {
253         unsigned int i, j, k;
254         miptex_t *tex;
255         unsigned char *data;
256         mwad_t *w;
257         char texname[17];
258         size_t range;
259
260         texname[16] = 0;
261         W_CleanupName(name, texname);
262         if (!wad.hlwads.mempool)
263                 Mem_ExpandableArray_NewArray(&wad.hlwads, cls.permanentmempool, sizeof(mwad_t), 16);
264         range = Mem_ExpandableArray_IndexRange(&wad.hlwads);
265         for (k = 0;k < range;k++)
266         {
267                 w = (mwad_t *)Mem_ExpandableArray_RecordAtIndex(&wad.hlwads, k);
268                 if (!w)
269                         continue;
270                 for (i = 0;i < (unsigned int)w->numlumps;i++)
271                 {
272                         if (!strcmp(texname, w->lumps[i].name)) // found it
273                         {
274                                 if (FS_Seek(w->file, w->lumps[i].filepos, SEEK_SET))
275                                 {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;}
276
277                                 tex = (miptex_t *)Mem_Alloc(tempmempool, w->lumps[i].disksize);
278                                 if (!tex)
279                                         return NULL;
280                                 if (FS_Read(w->file, tex, w->lumps[i].size) < w->lumps[i].disksize)
281                                 {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;}
282
283                                 tex->width = LittleLong(tex->width);
284                                 tex->height = LittleLong(tex->height);
285                                 for (j = 0;j < MIPLEVELS;j++)
286                                         tex->offsets[j] = LittleLong(tex->offsets[j]);
287                                 data = W_ConvertWAD3TextureBGRA(tex);
288                                 Mem_Free(tex);
289                                 return data;
290                         }
291                 }
292         }
293         image_width = image_height = 0;
294         return NULL;
295 }
296