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 
17 
18 // HEADER FILES ------------------------------------------------------------
19 
20 #include "h2def.h"
21 #include "i_system.h"
22 #include "r_local.h"
23 
24 // MACROS ------------------------------------------------------------------
25 
26 // TYPES -------------------------------------------------------------------
27 
28 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
29 
30 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
31 
32 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
33 
34 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
35 
36 extern fixed_t Sky1ScrollDelta;
37 extern fixed_t Sky2ScrollDelta;
38 
39 // PUBLIC DATA DEFINITIONS -------------------------------------------------
40 
41 int Sky1Texture;
42 int Sky2Texture;
43 fixed_t Sky1ColumnOffset;
44 fixed_t Sky2ColumnOffset;
45 int skyflatnum;
46 int skytexturemid;
47 fixed_t skyiscale;
48 boolean DoubleSky;
49 planefunction_t floorfunc, ceilingfunc;
50 
51 // Opening
52 visplane_t visplanes[MAXVISPLANES], *lastvisplane;
53 visplane_t *floorplane, *ceilingplane;
54 short openings[MAXOPENINGS], *lastopening;
55 
56 // Clip values are the solid pixel bounding the range.
57 // floorclip start out SCREENHEIGHT
58 // ceilingclip starts out -1
59 short floorclip[SCREENWIDTH];
60 short ceilingclip[SCREENWIDTH];
61 
62 // spanstart holds the start of a plane span, initialized to 0
63 int spanstart[SCREENHEIGHT];
64 int spanstop[SCREENHEIGHT];
65 
66 // Texture mapping
67 lighttable_t **planezlight;
68 fixed_t planeheight;
69 fixed_t yslope[SCREENHEIGHT];
70 fixed_t distscale[SCREENWIDTH];
71 fixed_t basexscale, baseyscale;
72 fixed_t cachedheight[SCREENHEIGHT];
73 fixed_t cacheddistance[SCREENHEIGHT];
74 fixed_t cachedxstep[SCREENHEIGHT];
75 fixed_t cachedystep[SCREENHEIGHT];
76 
77 // PRIVATE DATA DEFINITIONS ------------------------------------------------
78 
79 // CODE --------------------------------------------------------------------
80 
81 //==========================================================================
82 //
83 // R_InitSky
84 //
85 // Called at level load.
86 //
87 //==========================================================================
88 
R_InitSky(int map)89 void R_InitSky(int map)
90 {
91     Sky1Texture = P_GetMapSky1Texture(map);
92     Sky2Texture = P_GetMapSky2Texture(map);
93     Sky1ScrollDelta = P_GetMapSky1ScrollDelta(map);
94     Sky2ScrollDelta = P_GetMapSky2ScrollDelta(map);
95     Sky1ColumnOffset = 0;
96     Sky2ColumnOffset = 0;
97     DoubleSky = P_GetMapDoubleSky(map);
98 }
99 
100 //==========================================================================
101 //
102 // R_InitSkyMap
103 //
104 // Called whenever the view size changes.
105 //
106 //==========================================================================
107 
R_InitSkyMap(void)108 void R_InitSkyMap(void)
109 {
110     skyflatnum = R_FlatNumForName("F_SKY");
111     skytexturemid = 200 * FRACUNIT;
112     skyiscale = FRACUNIT;
113 }
114 
115 //==========================================================================
116 //
117 // R_InitPlanes
118 //
119 // Called at game startup.
120 //
121 //==========================================================================
122 
R_InitPlanes(void)123 void R_InitPlanes(void)
124 {
125 }
126 
127 //==========================================================================
128 //
129 // R_MapPlane
130 //
131 // Globals used: planeheight, ds_source, basexscale, baseyscale,
132 // viewx, viewy.
133 //
134 //==========================================================================
135 
R_MapPlane(int y,int x1,int x2)136 void R_MapPlane(int y, int x1, int x2)
137 {
138     angle_t angle;
139     fixed_t distance, length;
140     unsigned index;
141 
142 #ifdef RANGECHECK
143     if (x2 < x1 || x1 < 0 || x2 >= viewwidth || (unsigned) y > viewheight)
144     {
145         I_Error("R_MapPlane: %i, %i at %i", x1, x2, y);
146     }
147 #endif
148 
149     if (planeheight != cachedheight[y])
150     {
151         cachedheight[y] = planeheight;
152         distance = cacheddistance[y] = FixedMul(planeheight, yslope[y]);
153         ds_xstep = cachedxstep[y] = FixedMul(distance, basexscale);
154         ds_ystep = cachedystep[y] = FixedMul(distance, baseyscale);
155     }
156     else
157     {
158         distance = cacheddistance[y];
159         ds_xstep = cachedxstep[y];
160         ds_ystep = cachedystep[y];
161     }
162 
163     length = FixedMul(distance, distscale[x1]);
164     angle = (viewangle + xtoviewangle[x1]) >> ANGLETOFINESHIFT;
165     ds_xfrac = viewx + FixedMul(finecosine[angle], length);
166     ds_yfrac = -viewy - FixedMul(finesine[angle], length);
167 
168     if (fixedcolormap)
169     {
170         ds_colormap = fixedcolormap;
171     }
172     else
173     {
174         index = distance >> LIGHTZSHIFT;
175         if (index >= MAXLIGHTZ)
176         {
177             index = MAXLIGHTZ - 1;
178         }
179         ds_colormap = planezlight[index];
180     }
181 
182     ds_y = y;
183     ds_x1 = x1;
184     ds_x2 = x2;
185 
186     spanfunc();                 // High or low detail
187 }
188 
189 //==========================================================================
190 //
191 // R_ClearPlanes
192 //
193 // Called at the beginning of each frame.
194 //
195 //==========================================================================
196 
R_ClearPlanes(void)197 void R_ClearPlanes(void)
198 {
199     int i;
200     angle_t angle;
201 
202     // Opening / clipping determination
203     for (i = 0; i < viewwidth; i++)
204     {
205         floorclip[i] = viewheight;
206         ceilingclip[i] = -1;
207     }
208 
209     lastvisplane = visplanes;
210     lastopening = openings;
211 
212     // Texture calculation
213     memset(cachedheight, 0, sizeof(cachedheight));
214     angle = (viewangle - ANG90) >> ANGLETOFINESHIFT;    // left to right mapping
215     // Scale will be unit scale at SCREENWIDTH/2 distance
216     basexscale = FixedDiv(finecosine[angle], centerxfrac);
217     baseyscale = -FixedDiv(finesine[angle], centerxfrac);
218 }
219 
220 //==========================================================================
221 //
222 // R_FindPlane
223 //
224 //==========================================================================
225 
R_FindPlane(fixed_t height,int picnum,int lightlevel,int special)226 visplane_t *R_FindPlane(fixed_t height, int picnum,
227                         int lightlevel, int special)
228 {
229     visplane_t *check;
230 
231     if (special < 150)
232     {                           // Don't let low specials affect search
233         special = 0;
234     }
235 
236     if (picnum == skyflatnum)
237     {                           // All skies map together
238         height = 0;
239         lightlevel = 0;
240     }
241 
242     for (check = visplanes; check < lastvisplane; check++)
243     {
244         if (height == check->height
245             && picnum == check->picnum
246             && lightlevel == check->lightlevel && special == check->special)
247             break;
248     }
249 
250     if (check < lastvisplane)
251     {
252         return (check);
253     }
254 
255     if (lastvisplane - visplanes == MAXVISPLANES)
256     {
257         I_Error("R_FindPlane: no more visplanes");
258     }
259 
260     lastvisplane++;
261     check->height = height;
262     check->picnum = picnum;
263     check->lightlevel = lightlevel;
264     check->special = special;
265     check->minx = SCREENWIDTH;
266     check->maxx = -1;
267     memset(check->top, 0xff, sizeof(check->top));
268     return (check);
269 }
270 
271 //==========================================================================
272 //
273 // R_CheckPlane
274 //
275 //==========================================================================
276 
R_CheckPlane(visplane_t * pl,int start,int stop)277 visplane_t *R_CheckPlane(visplane_t * pl, int start, int stop)
278 {
279     int intrl, intrh;
280     int unionl, unionh;
281     int x;
282 
283     if (start < pl->minx)
284     {
285         intrl = pl->minx;
286         unionl = start;
287     }
288     else
289     {
290         unionl = pl->minx;
291         intrl = start;
292     }
293     if (stop > pl->maxx)
294     {
295         intrh = pl->maxx;
296         unionh = stop;
297     }
298     else
299     {
300         unionh = pl->maxx;
301         intrh = stop;
302     }
303 
304     for (x = intrl; x <= intrh; x++)
305     {
306         if (pl->top[x] != 0xff)
307         {
308             break;
309         }
310     }
311 
312     if (x > intrh)
313     {
314         pl->minx = unionl;
315         pl->maxx = unionh;
316         return pl;              // use the same visplane
317     }
318 
319     // Make a new visplane
320     lastvisplane->height = pl->height;
321     lastvisplane->picnum = pl->picnum;
322     lastvisplane->lightlevel = pl->lightlevel;
323     lastvisplane->special = pl->special;
324     pl = lastvisplane++;
325     pl->minx = start;
326     pl->maxx = stop;
327     memset(pl->top, 0xff, sizeof(pl->top));
328 
329     return pl;
330 }
331 
332 //==========================================================================
333 //
334 // R_MakeSpans
335 //
336 //==========================================================================
337 
R_MakeSpans(int x,int t1,int b1,int t2,int b2)338 void R_MakeSpans(int x, int t1, int b1, int t2, int b2)
339 {
340     while (t1 < t2 && t1 <= b1)
341     {
342         R_MapPlane(t1, spanstart[t1], x - 1);
343         t1++;
344     }
345     while (b1 > b2 && b1 >= t1)
346     {
347         R_MapPlane(b1, spanstart[b1], x - 1);
348         b1--;
349     }
350     while (t2 < t1 && t2 <= b2)
351     {
352         spanstart[t2] = x;
353         t2++;
354     }
355     while (b2 > b1 && b2 >= t2)
356     {
357         spanstart[b2] = x;
358         b2--;
359     }
360 }
361 
362 //==========================================================================
363 //
364 // R_DrawPlanes
365 //
366 //==========================================================================
367 
368 #define SKYTEXTUREMIDSHIFTED 200
369 
R_DrawPlanes(void)370 void R_DrawPlanes(void)
371 {
372     visplane_t *pl;
373     int light;
374     int x, stop;
375     int angle;
376     byte *tempSource;
377     byte *source;
378     byte *source2;
379     byte *dest;
380     int count;
381     int offset;
382     int skyTexture;
383     int offset2;
384     int skyTexture2;
385     int scrollOffset;
386 
387     extern byte *ylookup[MAXHEIGHT];
388     extern int columnofs[MAXWIDTH];
389 
390 #ifdef RANGECHECK
391     if (ds_p - drawsegs > MAXDRAWSEGS)
392     {
393         I_Error("R_DrawPlanes: drawsegs overflow (%i)", ds_p - drawsegs);
394     }
395     if (lastvisplane - visplanes > MAXVISPLANES)
396     {
397         I_Error("R_DrawPlanes: visplane overflow (%i)",
398                 lastvisplane - visplanes);
399     }
400     if (lastopening - openings > MAXOPENINGS)
401     {
402         I_Error("R_DrawPlanes: opening overflow (%i)",
403                 lastopening - openings);
404     }
405 #endif
406 
407     for (pl = visplanes; pl < lastvisplane; pl++)
408     {
409         if (pl->minx > pl->maxx)
410         {
411             continue;
412         }
413         if (pl->picnum == skyflatnum)
414         {                       // Sky flat
415             if (DoubleSky)
416             {                   // Render 2 layers, sky 1 in front
417                 offset = Sky1ColumnOffset >> 16;
418                 skyTexture = texturetranslation[Sky1Texture];
419                 offset2 = Sky2ColumnOffset >> 16;
420                 skyTexture2 = texturetranslation[Sky2Texture];
421                 for (x = pl->minx; x <= pl->maxx; x++)
422                 {
423                     dc_yl = pl->top[x];
424                     dc_yh = pl->bottom[x];
425                     if (dc_yl <= dc_yh)
426                     {
427                         count = dc_yh - dc_yl;
428                         if (count < 0)
429                         {
430                             return;
431                         }
432                         angle = (viewangle + xtoviewangle[x])
433                             >> ANGLETOSKYSHIFT;
434                         source = R_GetColumn(skyTexture, angle + offset)
435                             + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
436                         source2 = R_GetColumn(skyTexture2, angle + offset2)
437                             + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
438                         dest = ylookup[dc_yl] + columnofs[x];
439                         do
440                         {
441                             if (*source)
442                             {
443                                 *dest = *source++;
444                                 source2++;
445                             }
446                             else
447                             {
448                                 *dest = *source2++;
449                                 source++;
450                             }
451                             dest += SCREENWIDTH;
452                         }
453                         while (count--);
454                     }
455                 }
456                 continue;       // Next visplane
457             }
458             else
459             {                   // Render single layer
460                 if (pl->special == 200)
461                 {               // Use sky 2
462                     offset = Sky2ColumnOffset >> 16;
463                     skyTexture = texturetranslation[Sky2Texture];
464                 }
465                 else
466                 {               // Use sky 1
467                     offset = Sky1ColumnOffset >> 16;
468                     skyTexture = texturetranslation[Sky1Texture];
469                 }
470                 for (x = pl->minx; x <= pl->maxx; x++)
471                 {
472                     dc_yl = pl->top[x];
473                     dc_yh = pl->bottom[x];
474                     if (dc_yl <= dc_yh)
475                     {
476                         count = dc_yh - dc_yl;
477                         if (count < 0)
478                         {
479                             return;
480                         }
481                         angle = (viewangle + xtoviewangle[x])
482                             >> ANGLETOSKYSHIFT;
483                         source = R_GetColumn(skyTexture, angle + offset)
484                             + SKYTEXTUREMIDSHIFTED + (dc_yl - centery);
485                         dest = ylookup[dc_yl] + columnofs[x];
486                         do
487                         {
488                             *dest = *source++;
489                             dest += SCREENWIDTH;
490                         }
491                         while (count--);
492                     }
493                 }
494                 continue;       // Next visplane
495             }
496         }
497         // Regular flat
498         tempSource = W_CacheLumpNum(firstflat +
499                                     flattranslation[pl->picnum], PU_STATIC);
500         scrollOffset = leveltime >> 1 & 63;
501         switch (pl->special)
502         {                       // Handle scrolling flats
503             case 201:
504             case 202:
505             case 203:          // Scroll_North_xxx
506                 ds_source = tempSource + ((scrollOffset
507                                            << (pl->special - 201) & 63) << 6);
508                 break;
509             case 204:
510             case 205:
511             case 206:          // Scroll_East_xxx
512                 ds_source = tempSource + ((63 - scrollOffset)
513                                           << (pl->special - 204) & 63);
514                 break;
515             case 207:
516             case 208:
517             case 209:          // Scroll_South_xxx
518                 ds_source = tempSource + (((63 - scrollOffset)
519                                            << (pl->special - 207) & 63) << 6);
520                 break;
521             case 210:
522             case 211:
523             case 212:          // Scroll_West_xxx
524                 ds_source = tempSource + (scrollOffset
525                                           << (pl->special - 210) & 63);
526                 break;
527             case 213:
528             case 214:
529             case 215:          // Scroll_NorthWest_xxx
530                 ds_source = tempSource + (scrollOffset
531                                           << (pl->special - 213) & 63) +
532                     ((scrollOffset << (pl->special - 213) & 63) << 6);
533                 break;
534             case 216:
535             case 217:
536             case 218:          // Scroll_NorthEast_xxx
537                 ds_source = tempSource + ((63 - scrollOffset)
538                                           << (pl->special - 216) & 63) +
539                     ((scrollOffset << (pl->special - 216) & 63) << 6);
540                 break;
541             case 219:
542             case 220:
543             case 221:          // Scroll_SouthEast_xxx
544                 ds_source = tempSource + ((63 - scrollOffset)
545                                           << (pl->special - 219) & 63) +
546                     (((63 - scrollOffset) << (pl->special - 219) & 63) << 6);
547                 break;
548             case 222:
549             case 223:
550             case 224:          // Scroll_SouthWest_xxx
551                 ds_source = tempSource + (scrollOffset
552                                           << (pl->special - 222) & 63) +
553                     (((63 - scrollOffset) << (pl->special - 222) & 63) << 6);
554                 break;
555             default:
556                 ds_source = tempSource;
557                 break;
558         }
559         planeheight = abs(pl->height - viewz);
560         light = (pl->lightlevel >> LIGHTSEGSHIFT) + extralight;
561         if (light >= LIGHTLEVELS)
562         {
563             light = LIGHTLEVELS - 1;
564         }
565         if (light < 0)
566         {
567             light = 0;
568         }
569         planezlight = zlight[light];
570 
571         pl->top[pl->maxx + 1] = 0xff;
572         pl->top[pl->minx - 1] = 0xff;
573 
574         stop = pl->maxx + 1;
575         for (x = pl->minx; x <= stop; x++)
576         {
577             R_MakeSpans(x, pl->top[x - 1], pl->bottom[x - 1],
578                         pl->top[x], pl->bottom[x]);
579         }
580         W_ReleaseLumpNum(firstflat + flattranslation[pl->picnum]);
581     }
582 }
583