1 //----------------------------------------------------------------------------
2 //  EDGE Rendering Data Handling 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 // -ACB- 1998/09/09 Reformatted File Layout.
27 // -KM- 1998/09/27 Colourmaps can be dynamically changed.
28 // -ES- 2000/02/12 Moved most of this module to w_texture.c.
29 
30 #include "i_defs.h"
31 
32 #include "e_search.h"
33 #include "dm_state.h"
34 #include "dm_defs.h"
35 #include "m_argv.h"
36 #include "m_misc.h"
37 #include "p_local.h"
38 #include "r_image.h"
39 #include "r_sky.h"
40 #include "w_flat.h"
41 #include "w_model.h"
42 #include "w_sprite.h"
43 #include "w_wad.h"
44 #include "w_texture.h"
45 #include "z_zone.h"
46 
47 
48 cvar_c r_precache_tex;
49 cvar_c r_precache_sprite;
50 cvar_c r_precache_model;
51 
52 
53 //
54 // R_AddFlatAnim
55 //
56 // Here are the rules for flats, they get a bit hairy, but are the
57 // simplest thing which achieves expected behaviour:
58 //
59 // 1. When two flats in different wads have the same name, the flat
60 //    in the _later_ wad overrides the flat in the earlier wad.  This
61 //    allows pwads to replace iwad flats -- as is usual.  For general
62 //    use of flats (e.g. in levels) their order is not an issue.
63 //
64 // 2. The flat animation sequence is determined by the _earliest_ wad
65 //    which contains _both_ the start and the end flat.  The sequence
66 //    contained in that wad becomes the animation sequence (the list
67 //    of flat names).  These names are then looked up normally, so
68 //    flats in newer wads will get used if their name matches one in
69 //    the sequence.
70 //
71 // -AJA- 2001/01/28: reworked flat animations.
72 //
R_AddFlatAnim(animdef_c * anim)73 void R_AddFlatAnim(animdef_c *anim)
74 {
75 	if (anim->pics.GetSize() == 0)  // old way
76 	{
77 		int start = W_CheckNumForName(anim->startname);
78 		int end   = W_CheckNumForName(anim->endname);
79 
80 		int file;
81 		int s_offset, e_offset;
82 
83 		int i;
84 
85 		if (start == -1 || end == -1)
86 		{
87 			// sequence not valid.  Maybe it is the DOOM 1 IWAD.
88 			return;
89 		}
90 
91 		file = W_FindFlatSequence(anim->startname, anim->endname,
92 				&s_offset, &e_offset);
93 
94 		if (file < 0)
95 		{
96 			I_Warning("Missing flat animation: %s-%s not in any wad.\n",
97 					(const char*)anim->startname, (const char*)anim->endname);
98 			return;
99 		}
100 
101 		epi::u32array_c& lumps = W_GetListLumps(file, LMPLST_Flats);
102 		int total = lumps.GetSize();
103 
104 		SYS_ASSERT(s_offset <= e_offset);
105 		SYS_ASSERT(e_offset < total);
106 
107 		// determine animation sequence
108 		total = e_offset - s_offset + 1;
109 
110 		const image_c **flats = new const image_c* [total];
111 
112 		// lookup each flat
113 		for (i=0; i < total; i++)
114 		{
115 			const char *name = W_GetLumpName(lumps[s_offset + i]);
116 
117 			// Note we use W_ImageFromFlat() here.  It might seem like a good
118 			// optimisation to use the lump number directly, but we can't do
119 			// that -- the lump list does NOT take overriding flats (in newer
120 			// pwads) into account.
121 
122 			flats[i] = W_ImageLookup(name, INS_Flat, ILF_Null|ILF_Exact|ILF_NoNew);
123 		}
124 
125 		W_AnimateImageSet(flats, total, anim->speed);
126 		delete[] flats;
127 	}
128 
129 	// -AJA- 2004/10/27: new SEQUENCE command for anims
130 
131 	int total = anim->pics.GetSize();
132 
133 	if (total == 1)
134 		return;
135 
136 	const image_c **flats = new const image_c* [total];
137 
138 	for (int i = 0; i < total; i++)
139 	{
140 		flats[i] = W_ImageLookup(anim->pics[i], INS_Flat, ILF_Null|ILF_Exact);
141 	}
142 
143 	W_AnimateImageSet(flats, total, anim->speed);
144 	delete[] flats;
145 }
146 
147 //
148 // R_AddTextureAnim
149 //
150 // Here are the rules for textures:
151 //
152 // 1. The TEXTURE1/2 lumps require a PNAMES lump to complete their
153 //    meaning.  Some wads have the TEXTURE1/2 lump(s) but lack a
154 //    PNAMES lump -- in this case the next oldest PNAMES lump is used
155 //    (e.g. the one in the IWAD).
156 //
157 // 2. When two textures in different wads have the same name, the
158 //    texture in the _later_ wad overrides the one in the earlier wad,
159 //    as is usual.  For general use of textures (e.g. in levels),
160 //    their ordering is not an issue.
161 //
162 // 3. The texture animation sequence is determined by the _latest_ wad
163 //    whose TEXTURE1/2 lump contains _both_ the start and the end
164 //    texture.  The sequence within that lump becomes the animation
165 //    sequence (the list of texture names).  These names are then
166 //    looked up normally, so textures in newer wads can get used if
167 //    their name matches one in the sequence.
168 //
169 // -AJA- 2001/06/17: reworked texture animations.
170 //
R_AddTextureAnim(animdef_c * anim)171 void R_AddTextureAnim(animdef_c *anim)
172 {
173 	if (anim->pics.GetSize() == 0)  // old way
174 	{
175 		int set, s_offset, e_offset;
176 
177 		set = W_FindTextureSequence(anim->startname, anim->endname,
178 				&s_offset, &e_offset);
179 
180 		if (set < 0)
181 		{
182 			// sequence not valid.  Maybe it is the DOOM 1 IWAD.
183 			return;
184 		}
185 
186 		SYS_ASSERT(s_offset <= e_offset);
187 
188 		int total = e_offset - s_offset + 1;
189 		const image_c **texs = new const image_c* [total];
190 
191 		// lookup each texture
192 		for (int i = 0; i < total; i++)
193 		{
194 			const char *name = W_TextureNameInSet(set, s_offset + i);
195 			texs[i] = W_ImageLookup(name, INS_Texture, ILF_Null|ILF_Exact|ILF_NoNew);
196 		}
197 
198 		W_AnimateImageSet(texs, total, anim->speed);
199 		delete[] texs;
200 
201 		return;
202 	}
203 
204 	// -AJA- 2004/10/27: new SEQUENCE command for anims
205 
206 	int total = anim->pics.GetSize();
207 
208 	if (total == 1)
209 		return;
210 
211 	const image_c **texs = new const image_c* [total];
212 
213 	for (int i = 0; i < total; i++)
214 	{
215 		texs[i] = W_ImageLookup(anim->pics[i], INS_Texture, ILF_Null|ILF_Exact);
216 	}
217 
218 	W_AnimateImageSet(texs, total, anim->speed);
219 	delete[] texs;
220 }
221 
222 //
223 // R_AddGraphicAnim
224 //
R_AddGraphicAnim(animdef_c * anim)225 void R_AddGraphicAnim(animdef_c *anim)
226 {
227 	int total = anim->pics.GetSize();
228 
229 	SYS_ASSERT(total != 0);
230 
231 	if (total == 1)
232 		return;
233 
234 	const image_c **users = new const image_c* [total];
235 
236 	for (int i = 0; i < total; i++)
237 	{
238 		users[i] = W_ImageLookup(anim->pics[i], INS_Graphic, ILF_Null|ILF_Exact);
239 	}
240 
241 	W_AnimateImageSet(users, total, anim->speed);
242 	delete[] users;
243 }
244 
245 //
246 // W_InitFlats
247 //
W_InitFlats(void)248 void W_InitFlats(void)
249 {
250 	int max_file = W_GetNumFiles();
251 	int j, file;
252 
253 	int *F_lumps = NULL;
254 	int numflats = 0;
255 
256 	I_Printf("W_InitFlats...\n");
257 
258 	// iterate over each file, creating our big array of flats
259 
260 	for (file=0; file < max_file; file++)
261 	{
262 		epi::u32array_c& lumps = W_GetListLumps(file, LMPLST_Flats);
263 		int lumpnum = lumps.GetSize();
264 
265 		if (lumpnum == 0)
266 			continue;
267 
268 		Z_Resize(F_lumps, int, numflats + lumpnum);
269 
270 		for (j=0; j < lumpnum; j++, numflats++)
271 			F_lumps[numflats] = lumps[j];
272 	}
273 
274 	if (numflats == 0)
275 		I_Error("No flats found !  Make sure the chosen IWAD is valid.\n");
276 
277 	// now sort the flats, primarily by increasing name, secondarily by
278 	// increasing lump number (a measure of newness).
279 
280 #define CMP(a, b)  \
281 	(strcmp(W_GetLumpName(a), W_GetLumpName(b)) < 0 || \
282 	 (strcmp(W_GetLumpName(a), W_GetLumpName(b)) == 0 && a < b))
283 		QSORT(int, F_lumps, numflats, CUTOFF);
284 #undef CMP
285 
286 	// remove duplicate names.  We rely on the fact that newer lumps
287 	// have greater lump values than older ones.  Because the QSORT took
288 	// newness into account, only the last entry in a run of identically
289 	// named flats needs to be kept.
290 
291 	for (j=1; j < numflats; j++)
292 	{
293 		int a = F_lumps[j - 1];
294 		int b = F_lumps[j];
295 
296 		if (strcmp(W_GetLumpName(a), W_GetLumpName(b)) == 0)
297 			F_lumps[j - 1] = -1;
298 	}
299 
300 #if 0  // DEBUGGING
301 	for (j=0; j < numflats; j++)
302 	{
303 		L_WriteDebug("FLAT #%d:  lump=%d  name=[%s]\n", j,
304 				F_lumps[j], W_GetLumpName(F_lumps[j]));
305 	}
306 #endif
307 
308 	W_ImageCreateFlats(F_lumps, numflats);
309 	Z_Free(F_lumps);
310 }
311 
312 //
313 // W_InitPicAnims
314 //
W_InitPicAnims(void)315 void W_InitPicAnims(void)
316 {
317 	epi::array_iterator_c it;
318 	animdef_c *A;
319 
320 	// loop through animdefs, and add relevant anims.
321 	// Note: reverse order, give priority to newer anims.
322 	for (it = animdefs.GetTailIterator(); it.IsValid(); it--)
323 	{
324 		A = ITERATOR_TO_TYPE(it, animdef_c*);
325 
326 		SYS_ASSERT(A);
327 
328 		switch (A->type)
329 		{
330 			case animdef_c::A_Texture:
331 				R_AddTextureAnim(A);
332 				break;
333 
334 			case animdef_c::A_Flat:
335 				R_AddFlatAnim(A);
336 				break;
337 
338 			case animdef_c::A_Graphic:
339 				R_AddGraphicAnim(A);
340 				break;
341 		}
342 	}
343 }
344 
345 
W_PrecacheTextures(void)346 void W_PrecacheTextures(void)
347 {
348 	int i;
349 
350 	// maximum possible images
351 	int max_image = 1 + 3 * numsides + 2 * numsectors;
352 	int count = 0;
353 
354 	const image_c ** images = new const image_c* [max_image];
355 
356 	// Sky texture is always present.
357 	images[count++] = sky_image;
358 
359 	// add in sidedefs
360 	for (i=0; i < numsides; i++)
361 	{
362 		if (sides[i].top.image)
363 			images[count++] = sides[i].top.image;
364 
365 		if (sides[i].middle.image)
366 			images[count++] = sides[i].middle.image;
367 
368 		if (sides[i].bottom.image)
369 			images[count++] = sides[i].bottom.image;
370 	}
371 
372 	SYS_ASSERT(count <= max_image);
373 
374 	// add in planes
375 	for (i=0; i < numsectors; i++)
376 	{
377 		if (sectors[i].floor.image)
378 			images[count++] = sectors[i].floor.image;
379 
380 		if (sectors[i].ceil.image)
381 			images[count++] = sectors[i].ceil.image;
382 	}
383 
384 	SYS_ASSERT(count <= max_image);
385 
386 	// Sort the images, so we can ignore the duplicates
387 
388 #define CMP(a, b)  (a < b)
389 	QSORT(const image_c *, images, count, CUTOFF);
390 #undef CMP
391 
392 	for (i=0; i < count; i++)
393 	{
394 		SYS_ASSERT(images[i]);
395 
396 		if (i+1 < count && images[i] == images[i + 1])
397 			continue;
398 
399 		if (images[i] == skyflatimage)
400 			continue;
401 
402 		W_ImagePreCache(images[i]);
403 	}
404 
405 	delete[] images;
406 }
407 
408 
409 //
410 // W_PrecacheLevel
411 //
412 // Preloads all relevant graphics for the level.
413 //
414 // -AJA- 2001/06/18: Reworked for image system.
415 //
W_PrecacheLevel(void)416 void W_PrecacheLevel(void)
417 {
418 	if (r_precache_sprite.d)
419 		W_PrecacheSprites();
420 
421 	if (r_precache_tex.d)
422 		W_PrecacheTextures();
423 
424 	if (r_precache_model.d)
425 		W_PrecacheModels();
426 
427 	RGL_PreCacheSky();
428 }
429 
430 //--- editor settings ---
431 // vi:ts=4:sw=4:noexpandtab
432