1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 //	Here is a core component: drawing the floors and ceilings,
17 //	 while maintaining a per column clipping list only.
18 //	Moreover, the sky areas have to be determined.
19 //
20 
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 
25 #include "i_system.h"
26 #include "z_zone.h"
27 #include "w_wad.h"
28 
29 #include "doomdef.h"
30 #include "doomstat.h"
31 
32 #include "r_local.h"
33 #include "r_sky.h"
34 #include "r_bmaps.h" // [crispy] R_BrightmapForTexName()
35 #include "r_swirl.h" // [crispy] R_DistortedFlat()
36 
37 
38 
39 planefunction_t		floorfunc;
40 planefunction_t		ceilingfunc;
41 
42 //
43 // opening
44 //
45 
46 // Here comes the obnoxious "visplane".
47 #define MAXVISPLANES	128
48 visplane_t*		visplanes = NULL;
49 visplane_t*		lastvisplane;
50 visplane_t*		floorplane;
51 visplane_t*		ceilingplane;
52 static int		numvisplanes;
53 
54 // ?
55 #define MAXOPENINGS	MAXWIDTH*64*4
56 int			openings[MAXOPENINGS]; // [crispy] 32-bit integer math
57 int*			lastopening; // [crispy] 32-bit integer math
58 
59 
60 //
61 // Clip values are the solid pixel bounding the range.
62 //  floorclip starts out SCREENHEIGHT
63 //  ceilingclip starts out -1
64 //
65 int			floorclip[MAXWIDTH]; // [crispy] 32-bit integer math
66 int			ceilingclip[MAXWIDTH]; // [crispy] 32-bit integer math
67 
68 //
69 // spanstart holds the start of a plane span
70 // initialized to 0 at start
71 //
72 int			spanstart[MAXHEIGHT];
73 int			spanstop[MAXHEIGHT];
74 
75 //
76 // texture mapping
77 //
78 lighttable_t**		planezlight;
79 fixed_t			planeheight;
80 
81 fixed_t*			yslope;
82 fixed_t			yslopes[LOOKDIRS][MAXHEIGHT];
83 fixed_t			distscale[MAXWIDTH];
84 fixed_t			basexscale;
85 fixed_t			baseyscale;
86 
87 fixed_t			cachedheight[MAXHEIGHT];
88 fixed_t			cacheddistance[MAXHEIGHT];
89 fixed_t			cachedxstep[MAXHEIGHT];
90 fixed_t			cachedystep[MAXHEIGHT];
91 
92 
93 
94 //
95 // R_InitPlanes
96 // Only at game startup.
97 //
R_InitPlanes(void)98 void R_InitPlanes (void)
99 {
100   // Doh!
101 }
102 
103 
104 //
105 // R_MapPlane
106 //
107 // Uses global vars:
108 //  planeheight
109 //  ds_source
110 //  basexscale
111 //  baseyscale
112 //  viewx
113 //  viewy
114 //
115 // BASIC PRIMITIVE
116 //
117 void
R_MapPlane(int y,int x1,int x2)118 R_MapPlane
119 ( int		y,
120   int		x1,
121   int		x2 )
122 {
123 // [crispy] see below
124 //  angle_t	angle;
125     fixed_t	distance;
126 //  fixed_t	length;
127     unsigned	index;
128     int dx, dy;
129 
130 #ifdef RANGECHECK
131     if (x2 < x1
132      || x1 < 0
133      || x2 >= viewwidth
134      || y > viewheight)
135     {
136 	I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
137     }
138 #endif
139 
140 // [crispy] visplanes with the same flats now match up far better than before
141 // adapted from prboom-plus/src/r_plane.c:191-239, translated to fixed-point math
142 
143     if (!(dy = abs(centery - y)))
144     {
145 	return;
146     }
147 
148     if (planeheight != cachedheight[y])
149     {
150 	cachedheight[y] = planeheight;
151 	distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
152 	ds_xstep = cachedxstep[y] = (FixedMul (viewsin, planeheight) / dy) << detailshift;
153 	ds_ystep = cachedystep[y] = (FixedMul (viewcos, planeheight) / dy) << detailshift;
154     }
155     else
156     {
157 	distance = cacheddistance[y];
158 	ds_xstep = cachedxstep[y];
159 	ds_ystep = cachedystep[y];
160     }
161 
162     dx = x1 - centerx;
163 
164     ds_xfrac = viewx + FixedMul(viewcos, distance) + dx * ds_xstep;
165     ds_yfrac = -viewy - FixedMul(viewsin, distance) + dx * ds_ystep;
166 
167     if (fixedcolormap)
168 	ds_colormap[0] = ds_colormap[1] = fixedcolormap;
169     else
170     {
171 	index = distance >> LIGHTZSHIFT;
172 
173 	if (index >= MAXLIGHTZ )
174 	    index = MAXLIGHTZ-1;
175 
176 	ds_colormap[0] = planezlight[index];
177 	ds_colormap[1] = zlight[LIGHTLEVELS-1][MAXLIGHTZ-1];
178     }
179 
180     ds_y = y;
181     ds_x1 = x1;
182     ds_x2 = x2;
183 
184     // high or low detail
185     spanfunc ();
186 }
187 
188 
189 //
190 // R_ClearPlanes
191 // At begining of frame.
192 //
R_ClearPlanes(void)193 void R_ClearPlanes (void)
194 {
195     int		i;
196     angle_t	angle;
197 
198     // opening / clipping determination
199     for (i=0 ; i<viewwidth ; i++)
200     {
201 	floorclip[i] = viewheight;
202 	ceilingclip[i] = -1;
203     }
204 
205     lastvisplane = visplanes;
206     lastopening = openings;
207 
208     // texture calculation
209     memset (cachedheight, 0, sizeof(cachedheight));
210 
211     // left to right mapping
212     angle = (viewangle-ANG90)>>ANGLETOFINESHIFT;
213 
214     // scale will be unit scale at SCREENWIDTH/2 distance
215     basexscale = FixedDiv (finecosine[angle],centerxfrac);
216     baseyscale = -FixedDiv (finesine[angle],centerxfrac);
217 }
218 
219 
220 
221 // [crispy] remove MAXVISPLANES Vanilla limit
R_RaiseVisplanes(visplane_t ** vp)222 static void R_RaiseVisplanes (visplane_t** vp)
223 {
224     if (lastvisplane - visplanes == numvisplanes)
225     {
226 	int numvisplanes_old = numvisplanes;
227 	visplane_t* visplanes_old = visplanes;
228 
229 	numvisplanes = numvisplanes ? 2 * numvisplanes : MAXVISPLANES;
230 	visplanes = I_Realloc(visplanes, numvisplanes * sizeof(*visplanes));
231 	memset(visplanes + numvisplanes_old, 0, (numvisplanes - numvisplanes_old) * sizeof(*visplanes));
232 
233 	lastvisplane = visplanes + numvisplanes_old;
234 	floorplane = visplanes + (floorplane - visplanes_old);
235 	ceilingplane = visplanes + (ceilingplane - visplanes_old);
236 
237 	if (numvisplanes_old)
238 	    fprintf(stderr, "R_FindPlane: Hit MAXVISPLANES limit at %d, raised to %d.\n", numvisplanes_old, numvisplanes);
239 
240 	// keep the pointer passed as argument in relation to the visplanes pointer
241 	if (vp)
242 	    *vp = visplanes + (*vp - visplanes_old);
243     }
244 }
245 
246 //
247 // R_FindPlane
248 //
249 visplane_t*
R_FindPlane(fixed_t height,int picnum,int lightlevel)250 R_FindPlane
251 ( fixed_t	height,
252   int		picnum,
253   int		lightlevel )
254 {
255     visplane_t*	check;
256 
257     // [crispy] add support for MBF sky tranfers
258     if (picnum == skyflatnum || picnum & PL_SKYFLAT)
259     {
260 	height = 0;			// all skys map together
261 	lightlevel = 0;
262     }
263 
264     for (check=visplanes; check<lastvisplane; check++)
265     {
266 	if (height == check->height
267 	    && picnum == check->picnum
268 	    && lightlevel == check->lightlevel)
269 	{
270 	    break;
271 	}
272     }
273 
274 
275     if (check < lastvisplane)
276 	return check;
277 
278     R_RaiseVisplanes(&check); // [crispy] remove VISPLANES limit
279     if (lastvisplane - visplanes == MAXVISPLANES && false)
280 	I_Error ("R_FindPlane: no more visplanes");
281 
282     lastvisplane++;
283 
284     check->height = height;
285     check->picnum = picnum;
286     check->lightlevel = lightlevel;
287     check->minx = SCREENWIDTH;
288     check->maxx = -1;
289 
290     memset (check->top,0xff,sizeof(check->top));
291 
292     return check;
293 }
294 
295 
296 //
297 // R_CheckPlane
298 //
299 visplane_t*
R_CheckPlane(visplane_t * pl,int start,int stop)300 R_CheckPlane
301 ( visplane_t*	pl,
302   int		start,
303   int		stop )
304 {
305     int		intrl;
306     int		intrh;
307     int		unionl;
308     int		unionh;
309     int		x;
310 
311     if (start < pl->minx)
312     {
313 	intrl = pl->minx;
314 	unionl = start;
315     }
316     else
317     {
318 	unionl = pl->minx;
319 	intrl = start;
320     }
321 
322     if (stop > pl->maxx)
323     {
324 	intrh = pl->maxx;
325 	unionh = stop;
326     }
327     else
328     {
329 	unionh = pl->maxx;
330 	intrh = stop;
331     }
332 
333     for (x=intrl ; x<= intrh ; x++)
334 	if (pl->top[x] != 0xffffffffu) // [crispy] hires / 32-bit integer math
335 	    break;
336 
337   // [crispy] fix HOM if ceilingplane and floorplane are the same
338   // visplane (e.g. both are skies)
339   if (!(pl == floorplane && markceiling && floorplane == ceilingplane))
340   {
341     if (x > intrh)
342     {
343 	pl->minx = unionl;
344 	pl->maxx = unionh;
345 
346 	// use the same one
347 	return pl;
348     }
349   }
350 
351     // make a new visplane
352     R_RaiseVisplanes(&pl); // [crispy] remove VISPLANES limit
353     lastvisplane->height = pl->height;
354     lastvisplane->picnum = pl->picnum;
355     lastvisplane->lightlevel = pl->lightlevel;
356 
357     if (lastvisplane - visplanes == MAXVISPLANES && false) // [crispy] remove VISPLANES limit
358 	I_Error ("R_CheckPlane: no more visplanes");
359 
360     pl = lastvisplane++;
361     pl->minx = start;
362     pl->maxx = stop;
363 
364     memset (pl->top,0xff,sizeof(pl->top));
365 
366     return pl;
367 }
368 
369 
370 //
371 // R_MakeSpans
372 //
373 void
R_MakeSpans(int x,unsigned int t1,unsigned int b1,unsigned int t2,unsigned int b2)374 R_MakeSpans
375 ( int		x,
376   unsigned int		t1, // [crispy] 32-bit integer math
377   unsigned int		b1, // [crispy] 32-bit integer math
378   unsigned int		t2, // [crispy] 32-bit integer math
379   unsigned int		b2 ) // [crispy] 32-bit integer math
380 {
381     while (t1 < t2 && t1<=b1)
382     {
383 	R_MapPlane (t1,spanstart[t1],x-1);
384 	t1++;
385     }
386     while (b1 > b2 && b1>=t1)
387     {
388 	R_MapPlane (b1,spanstart[b1],x-1);
389 	b1--;
390     }
391 
392     while (t2 < t1 && t2<=b2)
393     {
394 	spanstart[t2] = x;
395 	t2++;
396     }
397     while (b2 > b1 && b2>=t2)
398     {
399 	spanstart[b2] = x;
400 	b2--;
401     }
402 }
403 
404 
405 
406 //
407 // R_DrawPlanes
408 // At the end of each frame.
409 //
R_DrawPlanes(void)410 void R_DrawPlanes (void)
411 {
412     visplane_t*		pl;
413     int			light;
414     int			x;
415     int			stop;
416     int			angle;
417     int                 lumpnum;
418 
419 #ifdef RANGECHECK
420     if (ds_p - drawsegs > numdrawsegs)
421 	I_Error ("R_DrawPlanes: drawsegs overflow (%" PRIiPTR ")",
422 		 ds_p - drawsegs);
423 
424     if (lastvisplane - visplanes > numvisplanes)
425 	I_Error ("R_DrawPlanes: visplane overflow (%" PRIiPTR ")",
426 		 lastvisplane - visplanes);
427 
428     if (lastopening - openings > MAXOPENINGS)
429 	I_Error ("R_DrawPlanes: opening overflow (%" PRIiPTR ")",
430 		 lastopening - openings);
431 #endif
432 
433     for (pl = visplanes ; pl < lastvisplane ; pl++)
434     {
435 	boolean swirling;
436 
437 	if (pl->minx > pl->maxx)
438 	    continue;
439 
440 
441 	// sky flat
442 	// [crispy] add support for MBF sky tranfers
443 	if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT)
444 	{
445 	    int texture;
446 	    angle_t an = viewangle, flip;
447 	    if (pl->picnum & PL_SKYFLAT)
448 	    {
449 		const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT];
450 		const side_t *s = *l->sidenum + sides;
451 		texture = texturetranslation[s->toptexture];
452 		dc_texturemid = s->rowoffset - 28*FRACUNIT;
453 		// [crispy] stretch sky
454 		if (crispy->stretchsky)
455 		{
456 		    dc_texturemid = dc_texturemid * (textureheight[texture]>>FRACBITS) / SKYSTRETCH_HEIGHT;
457 		}
458 		flip = (l->special == 272) ? 0u : ~0u;
459 		an += s->textureoffset;
460 	    }
461 	    else
462 	    {
463 		texture = skytexture;
464 		dc_texturemid = skytexturemid;
465 		flip = 0;
466 	    }
467 	    dc_iscale = pspriteiscale>>detailshift;
468 
469 	    // Sky is allways drawn full bright,
470 	    //  i.e. colormaps[0] is used.
471 	    // Because of this hack, sky is not affected
472 	    //  by INVUL inverse mapping.
473 	    // [crispy] no brightmaps for sky
474 	    dc_colormap[0] = dc_colormap[1] = colormaps;
475 //	    dc_texturemid = skytexturemid;
476 	    dc_texheight = textureheight[texture]>>FRACBITS; // [crispy] Tutti-Frutti fix
477 	    // [crispy] stretch sky
478 	    if (crispy->stretchsky)
479 	        dc_iscale = dc_iscale * dc_texheight / SKYSTRETCH_HEIGHT;
480 	    for (x=pl->minx ; x <= pl->maxx ; x++)
481 	    {
482 		dc_yl = pl->top[x];
483 		dc_yh = pl->bottom[x];
484 
485 		if ((unsigned) dc_yl <= dc_yh) // [crispy] 32-bit integer math
486 		{
487 		    angle = ((an + xtoviewangle[x])^flip)>>ANGLETOSKYSHIFT;
488 		    dc_x = x;
489 		    dc_source = R_GetColumn(texture, angle);
490 		    colfunc ();
491 		}
492 	    }
493 	    continue;
494 	}
495 
496 	swirling = (flattranslation[pl->picnum] == -1);
497 	// regular flat
498         lumpnum = firstflat + (swirling ? pl->picnum : flattranslation[pl->picnum]);
499 	// [crispy] add support for SMMU swirling flats
500 	ds_source = swirling ? R_DistortedFlat(lumpnum) : W_CacheLumpNum(lumpnum, PU_STATIC);
501 	ds_brightmap = R_BrightmapForFlatNum(lumpnum-firstflat);
502 
503 	planeheight = abs(pl->height-viewz);
504 	light = (pl->lightlevel >> LIGHTSEGSHIFT)+(extralight * LIGHTBRIGHT);
505 
506 	if (light >= LIGHTLEVELS)
507 	    light = LIGHTLEVELS-1;
508 
509 	if (light < 0)
510 	    light = 0;
511 
512 	planezlight = zlight[light];
513 
514 	pl->top[pl->maxx+1] = 0xffffffffu; // [crispy] hires / 32-bit integer math
515 	pl->top[pl->minx-1] = 0xffffffffu; // [crispy] hires / 32-bit integer math
516 
517 	stop = pl->maxx + 1;
518 
519 	for (x=pl->minx ; x<= stop ; x++)
520 	{
521 	    R_MakeSpans(x,pl->top[x-1],
522 			pl->bottom[x-1],
523 			pl->top[x],
524 			pl->bottom[x]);
525 	}
526 
527         W_ReleaseLumpNum(lumpnum);
528     }
529 }
530