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