changed texture formats from RGBA to BGRA, yes this is a massive change,
[divverent/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 = 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
152         if (wad.gfx_base)
153                 Con_DPrintf("W_GetLumpByName(\"%s\"): couldn't find file in gfx.wad\n", name);
154         else
155                 Con_DPrintf("W_GetLumpByName(\"%s\"): couldn't load gfx.wad\n", name);
156         return NULL;
157 }
158
159 /*
160 ====================
161 W_LoadTextureWadFile
162 ====================
163 */
164 void W_LoadTextureWadFile (char *filename, int complain)
165 {
166         wadinfo_t               header;
167         int                             infotableofs;
168         qfile_t                 *file;
169         int                             numlumps;
170         mwad_t                  *w;
171
172         file = FS_Open (filename, "rb", false, false);
173         if (!file)
174         {
175                 if (complain)
176                         Con_Printf("W_LoadTextureWadFile: couldn't find %s\n", filename);
177                 return;
178         }
179
180         if (FS_Read(file, &header, sizeof(wadinfo_t)) != sizeof(wadinfo_t))
181         {Con_Print("W_LoadTextureWadFile: unable to read wad header\n");FS_Close(file);file = NULL;return;}
182
183         if(memcmp(header.identification, "WAD3", 4))
184         {Con_Printf("W_LoadTextureWadFile: Wad file %s doesn't have WAD3 id\n",filename);FS_Close(file);file = NULL;return;}
185
186         numlumps = LittleLong(header.numlumps);
187         if (numlumps < 1 || numlumps > 65536)
188         {Con_Printf("W_LoadTextureWadFile: invalid number of lumps (%i)\n", numlumps);FS_Close(file);file = NULL;return;}
189         infotableofs = LittleLong(header.infotableofs);
190         if (FS_Seek (file, infotableofs, SEEK_SET))
191         {Con_Print("W_LoadTextureWadFile: unable to seek to lump table\n");FS_Close(file);file = NULL;return;}
192
193         if (!wad.hlwads.mempool)
194                 Mem_ExpandableArray_NewArray(&wad.hlwads, cls.permanentmempool, sizeof(mwad_t), 16);
195         w = Mem_ExpandableArray_AllocRecord(&wad.hlwads);
196         w->file = file;
197         w->numlumps = numlumps;
198         w->lumps = Mem_Alloc(cls.permanentmempool, w->numlumps * sizeof(lumpinfo_t));
199
200         if (!w->lumps)
201         {
202                 Con_Print("W_LoadTextureWadFile: unable to allocate temporary memory for lump table\n");
203                 FS_Close(w->file);
204                 w->file = NULL;
205                 w->numlumps = 0;
206                 return;
207         }
208
209         if (FS_Read(file, w->lumps, sizeof(lumpinfo_t) * w->numlumps) != (fs_offset_t)sizeof(lumpinfo_t) * numlumps)
210         {
211                 Con_Print("W_LoadTextureWadFile: unable to read lump table\n");
212                 FS_Close(w->file);
213                 w->file = NULL;
214                 w->numlumps = 0;
215                 Mem_Free(w->lumps);
216                 w->lumps = NULL;
217                 return;
218         }
219
220         W_SwapLumps(w->numlumps, w->lumps);
221
222         // leaves the file open
223 }
224
225 unsigned char *W_ConvertWAD3TextureBGRA(miptex_t *tex)
226 {
227         unsigned char *in, *data, *out, *pal;
228         int d, p;
229
230         in = (unsigned char *)tex + tex->offsets[0];
231         data = out = (unsigned char *)Mem_Alloc(tempmempool, tex->width * tex->height * 4);
232         if (!data)
233                 return NULL;
234         image_width = tex->width;
235         image_height = tex->height;
236         pal = in + (((image_width * image_height) * 85) >> 6);
237         pal += 2;
238         for (d = 0;d < image_width * image_height;d++)
239         {
240                 p = *in++;
241                 if (tex->name[0] == '{' && p == 255)
242                         out[0] = out[1] = out[2] = out[3] = 0;
243                 else
244                 {
245                         p *= 3;
246                         out[2] = pal[p];
247                         out[1] = pal[p+1];
248                         out[0] = pal[p+2];
249                         out[3] = 255;
250                 }
251                 out += 4;
252         }
253         return data;
254 }
255
256 unsigned char *W_GetTextureBGRA(char *name)
257 {
258         unsigned int i, j, k;
259         miptex_t *tex;
260         unsigned char *data;
261         mwad_t *w;
262         char texname[17];
263
264         texname[16] = 0;
265         W_CleanupName(name, texname);
266         if (!wad.hlwads.mempool)
267                 Mem_ExpandableArray_NewArray(&wad.hlwads, cls.permanentmempool, sizeof(mwad_t), 16);
268         for (k = 0;k < Mem_ExpandableArray_IndexRange(&wad.hlwads);k++)
269         {
270                 w = (mwad_t *)Mem_ExpandableArray_RecordAtIndex(&wad.hlwads, k);
271                 if (!w)
272                         continue;
273                 for (i = 0;i < (unsigned int)w->numlumps;i++)
274                 {
275                         if (!strcmp(texname, w->lumps[i].name)) // found it
276                         {
277                                 if (FS_Seek(w->file, w->lumps[i].filepos, SEEK_SET))
278                                 {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;}
279
280                                 tex = (miptex_t *)Mem_Alloc(tempmempool, w->lumps[i].disksize);
281                                 if (!tex)
282                                         return NULL;
283                                 if (FS_Read(w->file, tex, w->lumps[i].size) < w->lumps[i].disksize)
284                                 {Con_Print("W_GetTexture: corrupt WAD3 file\n");return NULL;}
285
286                                 tex->width = LittleLong(tex->width);
287                                 tex->height = LittleLong(tex->height);
288                                 for (j = 0;j < MIPLEVELS;j++)
289                                         tex->offsets[j] = LittleLong(tex->offsets[j]);
290                                 data = W_ConvertWAD3TextureBGRA(tex);
291                                 Mem_Free(tex);
292                                 return data;
293                         }
294                 }
295         }
296         image_width = image_height = 0;
297         return NULL;
298 }
299