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 
35 
36 
37 planefunction_t		floorfunc;
38 planefunction_t		ceilingfunc;
39 
40 //
41 // opening
42 //
43 
44 // Here comes the obnoxious "visplane".
45 // haleyjd 08/29/10: [STRIFE] MAXVISPLANES increased to 200
46 #define MAXVISPLANES	200
47 visplane_t		visplanes[MAXVISPLANES];
48 visplane_t*		lastvisplane;
49 visplane_t*		floorplane;
50 visplane_t*		ceilingplane;
51 
52 // ?
53 #define MAXOPENINGS	SCREENWIDTH*64
54 short			openings[MAXOPENINGS];
55 short*			lastopening;
56 
57 
58 //
59 // Clip values are the solid pixel bounding the range.
60 //  floorclip starts out SCREENHEIGHT
61 //  ceilingclip starts out -1
62 //
63 short			floorclip[SCREENWIDTH];
64 short			ceilingclip[SCREENWIDTH];
65 
66 //
67 // spanstart holds the start of a plane span
68 // initialized to 0 at start
69 //
70 int			spanstart[SCREENHEIGHT];
71 int			spanstop[SCREENHEIGHT];
72 
73 //
74 // texture mapping
75 //
76 lighttable_t**		planezlight;
77 fixed_t			planeheight;
78 
79 fixed_t			yslope[SCREENHEIGHT];
80 fixed_t			distscale[SCREENWIDTH];
81 fixed_t			basexscale;
82 fixed_t			baseyscale;
83 
84 fixed_t			cachedheight[SCREENHEIGHT];
85 fixed_t			cacheddistance[SCREENHEIGHT];
86 fixed_t			cachedxstep[SCREENHEIGHT];
87 fixed_t			cachedystep[SCREENHEIGHT];
88 
89 
90 
91 //
92 // R_InitPlanes
93 // Only at game startup.
94 //
R_InitPlanes(void)95 void R_InitPlanes (void)
96 {
97   // Doh!
98 }
99 
100 
101 //
102 // R_MapPlane
103 //
104 // Uses global vars:
105 //  planeheight
106 //  ds_source
107 //  basexscale
108 //  baseyscale
109 //  viewx
110 //  viewy
111 //
112 // BASIC PRIMITIVE
113 //
114 void
R_MapPlane(int y,int x1,int x2)115 R_MapPlane
116 ( int		y,
117   int		x1,
118   int		x2 )
119 {
120     angle_t	angle;
121     fixed_t	distance;
122     fixed_t	length;
123     unsigned	index;
124 
125 #ifdef RANGECHECK
126     if (x2 < x1
127      || x1 < 0
128      || x2 >= viewwidth
129      || y > viewheight)
130     {
131 	I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
132     }
133 #endif
134 
135     if (planeheight != cachedheight[y])
136     {
137 	cachedheight[y] = planeheight;
138 	distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
139 	ds_xstep = cachedxstep[y] = FixedMul (distance,basexscale);
140 	ds_ystep = cachedystep[y] = FixedMul (distance,baseyscale);
141     }
142     else
143     {
144 	distance = cacheddistance[y];
145 	ds_xstep = cachedxstep[y];
146 	ds_ystep = cachedystep[y];
147     }
148 
149     length = FixedMul (distance,distscale[x1]);
150     angle = (viewangle + xtoviewangle[x1])>>ANGLETOFINESHIFT;
151     ds_xfrac = viewx + FixedMul(finecosine[angle], length);
152     ds_yfrac = -viewy - FixedMul(finesine[angle], length);
153 
154     if (fixedcolormap)
155 	ds_colormap = fixedcolormap;
156     else
157     {
158 	index = distance >> LIGHTZSHIFT;
159 
160 	if (index >= MAXLIGHTZ )
161 	    index = MAXLIGHTZ-1;
162 
163 	ds_colormap = planezlight[index];
164     }
165 
166     ds_y = y;
167     ds_x1 = x1;
168     ds_x2 = x2;
169 
170     // high or low detail
171     spanfunc ();
172 }
173 
174 
175 //
176 // R_ClearPlanes
177 // At begining of frame.
178 //
R_ClearPlanes(void)179 void R_ClearPlanes (void)
180 {
181     int		i;
182     angle_t	angle;
183 
184     // opening / clipping determination
185     for (i=0 ; i<viewwidth ; i++)
186     {
187 	floorclip[i] = viewheight;
188 	ceilingclip[i] = -1;
189     }
190 
191     lastvisplane = visplanes;
192     lastopening = openings;
193 
194     // texture calculation
195     memset (cachedheight, 0, sizeof(cachedheight));
196 
197     // left to right mapping
198     angle = (viewangle-ANG90)>>ANGLETOFINESHIFT;
199 
200     // scale will be unit scale at SCREENWIDTH/2 distance
201     basexscale = FixedDiv (finecosine[angle],centerxfrac);
202     baseyscale = -FixedDiv (finesine[angle],centerxfrac);
203 }
204 
205 
206 
207 
208 //
209 // R_FindPlane
210 //
211 visplane_t*
R_FindPlane(fixed_t height,int picnum,int lightlevel)212 R_FindPlane
213 ( fixed_t	height,
214   int		picnum,
215   int		lightlevel )
216 {
217     visplane_t*	check;
218 
219     if (picnum == skyflatnum)
220     {
221 	height = 0;			// all skys map together
222 	lightlevel = 0;
223     }
224 
225     for (check=visplanes; check<lastvisplane; check++)
226     {
227 	if (height == check->height
228 	    && picnum == check->picnum
229 	    && lightlevel == check->lightlevel)
230 	{
231 	    break;
232 	}
233     }
234 
235 
236     if (check < lastvisplane)
237 	return check;
238 
239     if (lastvisplane - visplanes == MAXVISPLANES)
240 	I_Error ("R_FindPlane: no more visplanes");
241 
242     lastvisplane++;
243 
244     check->height = height;
245     check->picnum = picnum;
246     check->lightlevel = lightlevel;
247     check->minx = SCREENWIDTH;
248     check->maxx = -1;
249 
250     memset (check->top,0xff,sizeof(check->top));
251 
252     return check;
253 }
254 
255 
256 //
257 // R_CheckPlane
258 //
259 visplane_t*
R_CheckPlane(visplane_t * pl,int start,int stop)260 R_CheckPlane
261 ( visplane_t*	pl,
262   int		start,
263   int		stop )
264 {
265     int		intrl;
266     int		intrh;
267     int		unionl;
268     int		unionh;
269     int		x;
270 
271     if (start < pl->minx)
272     {
273 	intrl = pl->minx;
274 	unionl = start;
275     }
276     else
277     {
278 	unionl = pl->minx;
279 	intrl = start;
280     }
281 
282     if (stop > pl->maxx)
283     {
284 	intrh = pl->maxx;
285 	unionh = stop;
286     }
287     else
288     {
289 	unionh = pl->maxx;
290 	intrh = stop;
291     }
292 
293     for (x=intrl ; x<= intrh ; x++)
294 	if (pl->top[x] != 0xff)
295 	    break;
296 
297     if (x > intrh)
298     {
299 	pl->minx = unionl;
300 	pl->maxx = unionh;
301 
302 	// use the same one
303 	return pl;
304     }
305 
306     // make a new visplane
307     lastvisplane->height = pl->height;
308     lastvisplane->picnum = pl->picnum;
309     lastvisplane->lightlevel = pl->lightlevel;
310 
311     pl = lastvisplane++;
312     pl->minx = start;
313     pl->maxx = stop;
314 
315     memset (pl->top,0xff,sizeof(pl->top));
316 
317     return pl;
318 }
319 
320 
321 //
322 // R_MakeSpans
323 //
324 void
R_MakeSpans(int x,int t1,int b1,int t2,int b2)325 R_MakeSpans
326 ( int		x,
327   int		t1,
328   int		b1,
329   int		t2,
330   int		b2 )
331 {
332     while (t1 < t2 && t1<=b1)
333     {
334 	R_MapPlane (t1,spanstart[t1],x-1);
335 	t1++;
336     }
337     while (b1 > b2 && b1>=t1)
338     {
339 	R_MapPlane (b1,spanstart[b1],x-1);
340 	b1--;
341     }
342 
343     while (t2 < t1 && t2<=b2)
344     {
345 	spanstart[t2] = x;
346 	t2++;
347     }
348     while (b2 > b1 && b2>=t2)
349     {
350 	spanstart[b2] = x;
351 	b2--;
352     }
353 }
354 
355 
356 
357 //
358 // R_DrawPlanes
359 // At the end of each frame.
360 //
R_DrawPlanes(void)361 void R_DrawPlanes (void)
362 {
363     visplane_t*		pl;
364     int			light;
365     int			x;
366     int			stop;
367     int			angle;
368     int                 lumpnum;
369 
370 #ifdef RANGECHECK
371     if (ds_p - drawsegs > MAXDRAWSEGS)
372 	I_Error ("R_DrawPlanes: drawsegs overflow (%i)",
373 		 ds_p - drawsegs);
374 
375     if (lastvisplane - visplanes > MAXVISPLANES)
376 	I_Error ("R_DrawPlanes: visplane overflow (%i)",
377 		 lastvisplane - visplanes);
378 
379     if (lastopening - openings > MAXOPENINGS)
380 	I_Error ("R_DrawPlanes: opening overflow (%i)",
381 		 lastopening - openings);
382 #endif
383 
384     for (pl = visplanes ; pl < lastvisplane ; pl++)
385     {
386 	if (pl->minx > pl->maxx)
387 	    continue;
388 
389 
390 	// sky flat
391 	if (pl->picnum == skyflatnum)
392 	{
393 	    dc_iscale = pspriteiscale>>detailshift;
394 
395 	    // Sky is allways drawn full bright,
396 	    //  i.e. colormaps[0] is used.
397 	    // Because of this hack, sky is not affected
398 	    //  by INVUL inverse mapping.
399 	    dc_colormap = colormaps;
400 	    dc_texturemid = skytexturemid;
401 	    for (x=pl->minx ; x <= pl->maxx ; x++)
402 	    {
403 		dc_yl = pl->top[x];
404 		dc_yh = pl->bottom[x];
405 
406 		if (dc_yl <= dc_yh)
407 		{
408 		    angle = (viewangle + xtoviewangle[x])>>ANGLETOSKYSHIFT;
409 		    dc_x = x;
410 		    dc_source = R_GetColumn(skytexture, angle);
411 		    colfunc ();
412 		}
413 	    }
414 	    continue;
415 	}
416 
417 	// regular flat
418         lumpnum = firstflat + flattranslation[pl->picnum];
419 	ds_source = W_CacheLumpNum(lumpnum, PU_STATIC);
420 
421 	planeheight = abs(pl->height-viewz);
422 	light = (pl->lightlevel >> LIGHTSEGSHIFT)+extralight;
423 
424 	if (light >= LIGHTLEVELS)
425 	    light = LIGHTLEVELS-1;
426 
427 	if (light < 0)
428 	    light = 0;
429 
430 	planezlight = zlight[light];
431 
432 	pl->top[pl->maxx+1] = 0xff;
433 	pl->top[pl->minx-1] = 0xff;
434 
435 	stop = pl->maxx + 1;
436 
437 	for (x=pl->minx ; x<= stop ; x++)
438 	{
439 	    R_MakeSpans(x,pl->top[x-1],
440 			pl->bottom[x-1],
441 			pl->top[x],
442 			pl->bottom[x]);
443 	}
444 
445         W_ReleaseLumpNum(lumpnum);
446     }
447 }
448