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 #include "r_bmaps.h" // [crispy] R_BrightmapForTexName()
35 #include "r_swirl.h" // [crispy] R_DistortedFlat()
36
37
38
39 planefunction_t floorfunc;
40 planefunction_t ceilingfunc;
41
42 //
43 // opening
44 //
45
46 // Here comes the obnoxious "visplane".
47 #define MAXVISPLANES 128
48 visplane_t* visplanes = NULL;
49 visplane_t* lastvisplane;
50 visplane_t* floorplane;
51 visplane_t* ceilingplane;
52 static int numvisplanes;
53
54 // ?
55 #define MAXOPENINGS MAXWIDTH*64*4
56 int openings[MAXOPENINGS]; // [crispy] 32-bit integer math
57 int* lastopening; // [crispy] 32-bit integer math
58
59
60 //
61 // Clip values are the solid pixel bounding the range.
62 // floorclip starts out SCREENHEIGHT
63 // ceilingclip starts out -1
64 //
65 int floorclip[MAXWIDTH]; // [crispy] 32-bit integer math
66 int ceilingclip[MAXWIDTH]; // [crispy] 32-bit integer math
67
68 //
69 // spanstart holds the start of a plane span
70 // initialized to 0 at start
71 //
72 int spanstart[MAXHEIGHT];
73 int spanstop[MAXHEIGHT];
74
75 //
76 // texture mapping
77 //
78 lighttable_t** planezlight;
79 fixed_t planeheight;
80
81 fixed_t* yslope;
82 fixed_t yslopes[LOOKDIRS][MAXHEIGHT];
83 fixed_t distscale[MAXWIDTH];
84 fixed_t basexscale;
85 fixed_t baseyscale;
86
87 fixed_t cachedheight[MAXHEIGHT];
88 fixed_t cacheddistance[MAXHEIGHT];
89 fixed_t cachedxstep[MAXHEIGHT];
90 fixed_t cachedystep[MAXHEIGHT];
91
92
93
94 //
95 // R_InitPlanes
96 // Only at game startup.
97 //
R_InitPlanes(void)98 void R_InitPlanes (void)
99 {
100 // Doh!
101 }
102
103
104 //
105 // R_MapPlane
106 //
107 // Uses global vars:
108 // planeheight
109 // ds_source
110 // basexscale
111 // baseyscale
112 // viewx
113 // viewy
114 //
115 // BASIC PRIMITIVE
116 //
117 void
R_MapPlane(int y,int x1,int x2)118 R_MapPlane
119 ( int y,
120 int x1,
121 int x2 )
122 {
123 // [crispy] see below
124 // angle_t angle;
125 fixed_t distance;
126 // fixed_t length;
127 unsigned index;
128 int dx, dy;
129
130 #ifdef RANGECHECK
131 if (x2 < x1
132 || x1 < 0
133 || x2 >= viewwidth
134 || y > viewheight)
135 {
136 I_Error ("R_MapPlane: %i, %i at %i",x1,x2,y);
137 }
138 #endif
139
140 // [crispy] visplanes with the same flats now match up far better than before
141 // adapted from prboom-plus/src/r_plane.c:191-239, translated to fixed-point math
142
143 if (!(dy = abs(centery - y)))
144 {
145 return;
146 }
147
148 if (planeheight != cachedheight[y])
149 {
150 cachedheight[y] = planeheight;
151 distance = cacheddistance[y] = FixedMul (planeheight, yslope[y]);
152 ds_xstep = cachedxstep[y] = (FixedMul (viewsin, planeheight) / dy) << detailshift;
153 ds_ystep = cachedystep[y] = (FixedMul (viewcos, planeheight) / dy) << detailshift;
154 }
155 else
156 {
157 distance = cacheddistance[y];
158 ds_xstep = cachedxstep[y];
159 ds_ystep = cachedystep[y];
160 }
161
162 dx = x1 - centerx;
163
164 ds_xfrac = viewx + FixedMul(viewcos, distance) + dx * ds_xstep;
165 ds_yfrac = -viewy - FixedMul(viewsin, distance) + dx * ds_ystep;
166
167 if (fixedcolormap)
168 ds_colormap[0] = ds_colormap[1] = fixedcolormap;
169 else
170 {
171 index = distance >> LIGHTZSHIFT;
172
173 if (index >= MAXLIGHTZ )
174 index = MAXLIGHTZ-1;
175
176 ds_colormap[0] = planezlight[index];
177 ds_colormap[1] = zlight[LIGHTLEVELS-1][MAXLIGHTZ-1];
178 }
179
180 ds_y = y;
181 ds_x1 = x1;
182 ds_x2 = x2;
183
184 // high or low detail
185 spanfunc ();
186 }
187
188
189 //
190 // R_ClearPlanes
191 // At begining of frame.
192 //
R_ClearPlanes(void)193 void R_ClearPlanes (void)
194 {
195 int i;
196 angle_t angle;
197
198 // opening / clipping determination
199 for (i=0 ; i<viewwidth ; i++)
200 {
201 floorclip[i] = viewheight;
202 ceilingclip[i] = -1;
203 }
204
205 lastvisplane = visplanes;
206 lastopening = openings;
207
208 // texture calculation
209 memset (cachedheight, 0, sizeof(cachedheight));
210
211 // left to right mapping
212 angle = (viewangle-ANG90)>>ANGLETOFINESHIFT;
213
214 // scale will be unit scale at SCREENWIDTH/2 distance
215 basexscale = FixedDiv (finecosine[angle],centerxfrac);
216 baseyscale = -FixedDiv (finesine[angle],centerxfrac);
217 }
218
219
220
221 // [crispy] remove MAXVISPLANES Vanilla limit
R_RaiseVisplanes(visplane_t ** vp)222 static void R_RaiseVisplanes (visplane_t** vp)
223 {
224 if (lastvisplane - visplanes == numvisplanes)
225 {
226 int numvisplanes_old = numvisplanes;
227 visplane_t* visplanes_old = visplanes;
228
229 numvisplanes = numvisplanes ? 2 * numvisplanes : MAXVISPLANES;
230 visplanes = I_Realloc(visplanes, numvisplanes * sizeof(*visplanes));
231 memset(visplanes + numvisplanes_old, 0, (numvisplanes - numvisplanes_old) * sizeof(*visplanes));
232
233 lastvisplane = visplanes + numvisplanes_old;
234 floorplane = visplanes + (floorplane - visplanes_old);
235 ceilingplane = visplanes + (ceilingplane - visplanes_old);
236
237 if (numvisplanes_old)
238 fprintf(stderr, "R_FindPlane: Hit MAXVISPLANES limit at %d, raised to %d.\n", numvisplanes_old, numvisplanes);
239
240 // keep the pointer passed as argument in relation to the visplanes pointer
241 if (vp)
242 *vp = visplanes + (*vp - visplanes_old);
243 }
244 }
245
246 //
247 // R_FindPlane
248 //
249 visplane_t*
R_FindPlane(fixed_t height,int picnum,int lightlevel)250 R_FindPlane
251 ( fixed_t height,
252 int picnum,
253 int lightlevel )
254 {
255 visplane_t* check;
256
257 // [crispy] add support for MBF sky tranfers
258 if (picnum == skyflatnum || picnum & PL_SKYFLAT)
259 {
260 height = 0; // all skys map together
261 lightlevel = 0;
262 }
263
264 for (check=visplanes; check<lastvisplane; check++)
265 {
266 if (height == check->height
267 && picnum == check->picnum
268 && lightlevel == check->lightlevel)
269 {
270 break;
271 }
272 }
273
274
275 if (check < lastvisplane)
276 return check;
277
278 R_RaiseVisplanes(&check); // [crispy] remove VISPLANES limit
279 if (lastvisplane - visplanes == MAXVISPLANES && false)
280 I_Error ("R_FindPlane: no more visplanes");
281
282 lastvisplane++;
283
284 check->height = height;
285 check->picnum = picnum;
286 check->lightlevel = lightlevel;
287 check->minx = SCREENWIDTH;
288 check->maxx = -1;
289
290 memset (check->top,0xff,sizeof(check->top));
291
292 return check;
293 }
294
295
296 //
297 // R_CheckPlane
298 //
299 visplane_t*
R_CheckPlane(visplane_t * pl,int start,int stop)300 R_CheckPlane
301 ( visplane_t* pl,
302 int start,
303 int stop )
304 {
305 int intrl;
306 int intrh;
307 int unionl;
308 int unionh;
309 int x;
310
311 if (start < pl->minx)
312 {
313 intrl = pl->minx;
314 unionl = start;
315 }
316 else
317 {
318 unionl = pl->minx;
319 intrl = start;
320 }
321
322 if (stop > pl->maxx)
323 {
324 intrh = pl->maxx;
325 unionh = stop;
326 }
327 else
328 {
329 unionh = pl->maxx;
330 intrh = stop;
331 }
332
333 for (x=intrl ; x<= intrh ; x++)
334 if (pl->top[x] != 0xffffffffu) // [crispy] hires / 32-bit integer math
335 break;
336
337 // [crispy] fix HOM if ceilingplane and floorplane are the same
338 // visplane (e.g. both are skies)
339 if (!(pl == floorplane && markceiling && floorplane == ceilingplane))
340 {
341 if (x > intrh)
342 {
343 pl->minx = unionl;
344 pl->maxx = unionh;
345
346 // use the same one
347 return pl;
348 }
349 }
350
351 // make a new visplane
352 R_RaiseVisplanes(&pl); // [crispy] remove VISPLANES limit
353 lastvisplane->height = pl->height;
354 lastvisplane->picnum = pl->picnum;
355 lastvisplane->lightlevel = pl->lightlevel;
356
357 if (lastvisplane - visplanes == MAXVISPLANES && false) // [crispy] remove VISPLANES limit
358 I_Error ("R_CheckPlane: no more visplanes");
359
360 pl = lastvisplane++;
361 pl->minx = start;
362 pl->maxx = stop;
363
364 memset (pl->top,0xff,sizeof(pl->top));
365
366 return pl;
367 }
368
369
370 //
371 // R_MakeSpans
372 //
373 void
R_MakeSpans(int x,unsigned int t1,unsigned int b1,unsigned int t2,unsigned int b2)374 R_MakeSpans
375 ( int x,
376 unsigned int t1, // [crispy] 32-bit integer math
377 unsigned int b1, // [crispy] 32-bit integer math
378 unsigned int t2, // [crispy] 32-bit integer math
379 unsigned int b2 ) // [crispy] 32-bit integer math
380 {
381 while (t1 < t2 && t1<=b1)
382 {
383 R_MapPlane (t1,spanstart[t1],x-1);
384 t1++;
385 }
386 while (b1 > b2 && b1>=t1)
387 {
388 R_MapPlane (b1,spanstart[b1],x-1);
389 b1--;
390 }
391
392 while (t2 < t1 && t2<=b2)
393 {
394 spanstart[t2] = x;
395 t2++;
396 }
397 while (b2 > b1 && b2>=t2)
398 {
399 spanstart[b2] = x;
400 b2--;
401 }
402 }
403
404
405
406 //
407 // R_DrawPlanes
408 // At the end of each frame.
409 //
R_DrawPlanes(void)410 void R_DrawPlanes (void)
411 {
412 visplane_t* pl;
413 int light;
414 int x;
415 int stop;
416 int angle;
417 int lumpnum;
418
419 #ifdef RANGECHECK
420 if (ds_p - drawsegs > numdrawsegs)
421 I_Error ("R_DrawPlanes: drawsegs overflow (%" PRIiPTR ")",
422 ds_p - drawsegs);
423
424 if (lastvisplane - visplanes > numvisplanes)
425 I_Error ("R_DrawPlanes: visplane overflow (%" PRIiPTR ")",
426 lastvisplane - visplanes);
427
428 if (lastopening - openings > MAXOPENINGS)
429 I_Error ("R_DrawPlanes: opening overflow (%" PRIiPTR ")",
430 lastopening - openings);
431 #endif
432
433 for (pl = visplanes ; pl < lastvisplane ; pl++)
434 {
435 boolean swirling;
436
437 if (pl->minx > pl->maxx)
438 continue;
439
440
441 // sky flat
442 // [crispy] add support for MBF sky tranfers
443 if (pl->picnum == skyflatnum || pl->picnum & PL_SKYFLAT)
444 {
445 int texture;
446 angle_t an = viewangle, flip;
447 if (pl->picnum & PL_SKYFLAT)
448 {
449 const line_t *l = &lines[pl->picnum & ~PL_SKYFLAT];
450 const side_t *s = *l->sidenum + sides;
451 texture = texturetranslation[s->toptexture];
452 dc_texturemid = s->rowoffset - 28*FRACUNIT;
453 // [crispy] stretch sky
454 if (crispy->stretchsky)
455 {
456 dc_texturemid = dc_texturemid * (textureheight[texture]>>FRACBITS) / SKYSTRETCH_HEIGHT;
457 }
458 flip = (l->special == 272) ? 0u : ~0u;
459 an += s->textureoffset;
460 }
461 else
462 {
463 texture = skytexture;
464 dc_texturemid = skytexturemid;
465 flip = 0;
466 }
467 dc_iscale = pspriteiscale>>detailshift;
468
469 // Sky is allways drawn full bright,
470 // i.e. colormaps[0] is used.
471 // Because of this hack, sky is not affected
472 // by INVUL inverse mapping.
473 // [crispy] no brightmaps for sky
474 dc_colormap[0] = dc_colormap[1] = colormaps;
475 // dc_texturemid = skytexturemid;
476 dc_texheight = textureheight[texture]>>FRACBITS; // [crispy] Tutti-Frutti fix
477 // [crispy] stretch sky
478 if (crispy->stretchsky)
479 dc_iscale = dc_iscale * dc_texheight / SKYSTRETCH_HEIGHT;
480 for (x=pl->minx ; x <= pl->maxx ; x++)
481 {
482 dc_yl = pl->top[x];
483 dc_yh = pl->bottom[x];
484
485 if ((unsigned) dc_yl <= dc_yh) // [crispy] 32-bit integer math
486 {
487 angle = ((an + xtoviewangle[x])^flip)>>ANGLETOSKYSHIFT;
488 dc_x = x;
489 dc_source = R_GetColumn(texture, angle);
490 colfunc ();
491 }
492 }
493 continue;
494 }
495
496 swirling = (flattranslation[pl->picnum] == -1);
497 // regular flat
498 lumpnum = firstflat + (swirling ? pl->picnum : flattranslation[pl->picnum]);
499 // [crispy] add support for SMMU swirling flats
500 ds_source = swirling ? R_DistortedFlat(lumpnum) : W_CacheLumpNum(lumpnum, PU_STATIC);
501 ds_brightmap = R_BrightmapForFlatNum(lumpnum-firstflat);
502
503 planeheight = abs(pl->height-viewz);
504 light = (pl->lightlevel >> LIGHTSEGSHIFT)+(extralight * LIGHTBRIGHT);
505
506 if (light >= LIGHTLEVELS)
507 light = LIGHTLEVELS-1;
508
509 if (light < 0)
510 light = 0;
511
512 planezlight = zlight[light];
513
514 pl->top[pl->maxx+1] = 0xffffffffu; // [crispy] hires / 32-bit integer math
515 pl->top[pl->minx-1] = 0xffffffffu; // [crispy] hires / 32-bit integer math
516
517 stop = pl->maxx + 1;
518
519 for (x=pl->minx ; x<= stop ; x++)
520 {
521 R_MakeSpans(x,pl->top[x-1],
522 pl->bottom[x-1],
523 pl->top[x],
524 pl->bottom[x]);
525 }
526
527 W_ReleaseLumpNum(lumpnum);
528 }
529 }
530