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