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