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 // All the clipping: columns, horizontal spans, sky columns.
17 //
18
19
20
21
22
23
24 #include <stdio.h>
25 #include <stdlib.h>
26
27 #include "i_system.h"
28
29 #include "doomdef.h"
30 #include "doomstat.h"
31
32 #include "r_local.h"
33 #include "r_sky.h"
34
35
36 // OPTIMIZE: closed two sided lines as single sided
37
38 // True if any of the segs textures might be visible.
39 boolean segtextured;
40
41 // False if the back side is the same plane.
42 boolean markfloor;
43 boolean markceiling;
44
45 boolean maskedtexture;
46 int toptexture;
47 int bottomtexture;
48 int midtexture;
49
50
51 angle_t rw_normalangle;
52 // angle to line origin
53 int rw_angle1;
54
55 //
56 // regular wall
57 //
58 int rw_x;
59 int rw_stopx;
60 angle_t rw_centerangle;
61 fixed_t rw_offset;
62 fixed_t rw_distance;
63 fixed_t rw_scale;
64 fixed_t rw_scalestep;
65 fixed_t rw_midtexturemid;
66 fixed_t rw_toptexturemid;
67 fixed_t rw_bottomtexturemid;
68
69 int worldtop;
70 int worldbottom;
71 int worldhigh;
72 int worldlow;
73
74 fixed_t pixhigh;
75 fixed_t pixlow;
76 fixed_t pixhighstep;
77 fixed_t pixlowstep;
78
79 fixed_t topfrac;
80 fixed_t topstep;
81
82 fixed_t bottomfrac;
83 fixed_t bottomstep;
84
85
86 lighttable_t** walllights;
87
88 short* maskedtexturecol;
89
90
91
92 //
93 // R_RenderMaskedSegRange
94 //
95 void
R_RenderMaskedSegRange(drawseg_t * ds,int x1,int x2)96 R_RenderMaskedSegRange
97 ( drawseg_t* ds,
98 int x1,
99 int x2 )
100 {
101 unsigned index;
102 column_t* col;
103 int lightnum;
104 int texnum;
105
106 // Calculate light table.
107 // Use different light tables
108 // for horizontal / vertical / diagonal. Diagonal?
109 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
110 curline = ds->curline;
111 frontsector = curline->frontsector;
112 backsector = curline->backsector;
113 texnum = texturetranslation[curline->sidedef->midtexture];
114
115 lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
116
117 if (curline->v1->y == curline->v2->y)
118 lightnum--;
119 else if (curline->v1->x == curline->v2->x)
120 lightnum++;
121
122 if (lightnum < 0)
123 walllights = scalelight[0];
124 else if (lightnum >= LIGHTLEVELS)
125 walllights = scalelight[LIGHTLEVELS-1];
126 else
127 walllights = scalelight[lightnum];
128
129 maskedtexturecol = ds->maskedtexturecol;
130
131 rw_scalestep = ds->scalestep;
132 spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
133 mfloorclip = ds->sprbottomclip;
134 mceilingclip = ds->sprtopclip;
135
136 // find positioning
137 if (curline->linedef->flags & ML_DONTPEGBOTTOM)
138 {
139 dc_texturemid = frontsector->floorheight > backsector->floorheight
140 ? frontsector->floorheight : backsector->floorheight;
141 dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
142 }
143 else
144 {
145 dc_texturemid =frontsector->ceilingheight<backsector->ceilingheight
146 ? frontsector->ceilingheight : backsector->ceilingheight;
147 dc_texturemid = dc_texturemid - viewz;
148 }
149 dc_texturemid += curline->sidedef->rowoffset;
150
151 if (fixedcolormap)
152 dc_colormap = fixedcolormap;
153
154 // draw the columns
155 for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
156 {
157 // calculate lighting
158 if (maskedtexturecol[dc_x] != SHRT_MAX)
159 {
160 if (!fixedcolormap)
161 {
162 index = spryscale>>LIGHTSCALESHIFT;
163
164 if (index >= MAXLIGHTSCALE )
165 index = MAXLIGHTSCALE-1;
166
167 dc_colormap = walllights[index];
168 }
169
170 sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
171 dc_iscale = 0xffffffffu / (unsigned)spryscale;
172
173 // draw the texture
174 col = (column_t *)(
175 (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
176
177 R_DrawMaskedColumn (col);
178 maskedtexturecol[dc_x] = SHRT_MAX;
179 }
180 spryscale += rw_scalestep;
181 }
182
183 }
184
185
186
187
188 //
189 // R_RenderSegLoop
190 // Draws zero, one, or two textures (and possibly a masked
191 // texture) for walls.
192 // Can draw or mark the starting pixel of floor and ceiling
193 // textures.
194 // CALLED: CORE LOOPING ROUTINE.
195 //
196 #define HEIGHTBITS 12
197 #define HEIGHTUNIT (1<<HEIGHTBITS)
198
R_RenderSegLoop(void)199 void R_RenderSegLoop (void)
200 {
201 angle_t angle;
202 unsigned index;
203 int yl;
204 int yh;
205 int mid;
206 fixed_t texturecolumn;
207 int top;
208 int bottom;
209
210 for ( ; rw_x < rw_stopx ; rw_x++)
211 {
212 // mark floor / ceiling areas
213 yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
214
215 // no space above wall?
216 if (yl < ceilingclip[rw_x]+1)
217 yl = ceilingclip[rw_x]+1;
218
219 if (markceiling)
220 {
221 top = ceilingclip[rw_x]+1;
222 bottom = yl-1;
223
224 if (bottom >= floorclip[rw_x])
225 bottom = floorclip[rw_x]-1;
226
227 if (top <= bottom)
228 {
229 ceilingplane->top[rw_x] = top;
230 ceilingplane->bottom[rw_x] = bottom;
231 }
232 }
233
234 yh = bottomfrac>>HEIGHTBITS;
235
236 if (yh >= floorclip[rw_x])
237 yh = floorclip[rw_x]-1;
238
239 if (markfloor)
240 {
241 top = yh+1;
242 bottom = floorclip[rw_x]-1;
243 if (top <= ceilingclip[rw_x])
244 top = ceilingclip[rw_x]+1;
245 if (top <= bottom)
246 {
247 floorplane->top[rw_x] = top;
248 floorplane->bottom[rw_x] = bottom;
249 }
250 }
251
252 // texturecolumn and lighting are independent of wall tiers
253 if (segtextured)
254 {
255 // calculate texture offset
256 angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
257 texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
258 texturecolumn >>= FRACBITS;
259 // calculate lighting
260 index = rw_scale>>LIGHTSCALESHIFT;
261
262 if (index >= MAXLIGHTSCALE )
263 index = MAXLIGHTSCALE-1;
264
265 dc_colormap = walllights[index];
266 dc_x = rw_x;
267 dc_iscale = 0xffffffffu / (unsigned)rw_scale;
268 }
269 else
270 {
271 // purely to shut up the compiler
272
273 texturecolumn = 0;
274 }
275
276 // draw the wall tiers
277 if (midtexture)
278 {
279 // single sided line
280 dc_yl = yl;
281 dc_yh = yh;
282 dc_texturemid = rw_midtexturemid;
283 dc_source = R_GetColumn(midtexture,texturecolumn);
284 colfunc ();
285 ceilingclip[rw_x] = viewheight;
286 floorclip[rw_x] = -1;
287 }
288 else
289 {
290 // two sided line
291 if (toptexture)
292 {
293 // top wall
294 mid = pixhigh>>HEIGHTBITS;
295 pixhigh += pixhighstep;
296
297 if (mid >= floorclip[rw_x])
298 mid = floorclip[rw_x]-1;
299
300 if (mid >= yl)
301 {
302 dc_yl = yl;
303 dc_yh = mid;
304 dc_texturemid = rw_toptexturemid;
305 dc_source = R_GetColumn(toptexture,texturecolumn);
306 colfunc ();
307 ceilingclip[rw_x] = mid;
308 }
309 else
310 ceilingclip[rw_x] = yl-1;
311 }
312 else
313 {
314 // no top wall
315 if (markceiling)
316 ceilingclip[rw_x] = yl-1;
317 }
318
319 if (bottomtexture)
320 {
321 // bottom wall
322 mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
323 pixlow += pixlowstep;
324
325 // no space above wall?
326 if (mid <= ceilingclip[rw_x])
327 mid = ceilingclip[rw_x]+1;
328
329 if (mid <= yh)
330 {
331 dc_yl = mid;
332 dc_yh = yh;
333 dc_texturemid = rw_bottomtexturemid;
334 dc_source = R_GetColumn(bottomtexture,
335 texturecolumn);
336 colfunc ();
337 floorclip[rw_x] = mid;
338 }
339 else
340 floorclip[rw_x] = yh+1;
341 }
342 else
343 {
344 // no bottom wall
345 if (markfloor)
346 floorclip[rw_x] = yh+1;
347 }
348
349 if (maskedtexture)
350 {
351 // save texturecol
352 // for backdrawing of masked mid texture
353 maskedtexturecol[rw_x] = texturecolumn;
354 }
355 }
356
357 rw_scale += rw_scalestep;
358 topfrac += topstep;
359 bottomfrac += bottomstep;
360 }
361 }
362
363
364
365
366 //
367 // R_StoreWallRange
368 // A wall segment will be drawn
369 // between start and stop pixels (inclusive).
370 //
371 void
R_StoreWallRange(int start,int stop)372 R_StoreWallRange
373 ( int start,
374 int stop )
375 {
376 fixed_t hyp;
377 fixed_t sineval;
378 angle_t distangle, offsetangle;
379 fixed_t vtop;
380 int lightnum;
381
382 // don't overflow and crash
383 if (ds_p == &drawsegs[MAXDRAWSEGS])
384 return;
385
386 #ifdef RANGECHECK
387 if (start >=viewwidth || start > stop)
388 I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
389 #endif
390
391 sidedef = curline->sidedef;
392 linedef = curline->linedef;
393
394 // mark the segment as visible for auto map
395 linedef->flags |= ML_MAPPED;
396
397 // calculate rw_distance for scale calculation
398 rw_normalangle = curline->angle + ANG90;
399 offsetangle = abs(rw_normalangle-rw_angle1);
400
401 if (offsetangle > ANG90)
402 offsetangle = ANG90;
403
404 distangle = ANG90 - offsetangle;
405 hyp = R_PointToDist (curline->v1->x, curline->v1->y);
406 sineval = finesine[distangle>>ANGLETOFINESHIFT];
407 rw_distance = FixedMul (hyp, sineval);
408
409
410 ds_p->x1 = rw_x = start;
411 ds_p->x2 = stop;
412 ds_p->curline = curline;
413 rw_stopx = stop+1;
414
415 // calculate scale at both ends and step
416 ds_p->scale1 = rw_scale =
417 R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
418
419 if (stop > start )
420 {
421 ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
422 ds_p->scalestep = rw_scalestep =
423 (ds_p->scale2 - rw_scale) / (stop-start);
424 }
425 else
426 {
427 // UNUSED: try to fix the stretched line bug
428 #if 0
429 if (rw_distance < FRACUNIT/2)
430 {
431 fixed_t trx,try;
432 fixed_t gxt,gyt;
433
434 trx = curline->v1->x - viewx;
435 try = curline->v1->y - viewy;
436
437 gxt = FixedMul(trx,viewcos);
438 gyt = -FixedMul(try,viewsin);
439 ds_p->scale1 = FixedDiv(projection, gxt-gyt)<<detailshift;
440 }
441 #endif
442 ds_p->scale2 = ds_p->scale1;
443 }
444
445 // calculate texture boundaries
446 // and decide if floor / ceiling marks are needed
447 worldtop = frontsector->ceilingheight - viewz;
448 worldbottom = frontsector->floorheight - viewz;
449
450 midtexture = toptexture = bottomtexture = maskedtexture = 0;
451 ds_p->maskedtexturecol = NULL;
452
453 if (!backsector)
454 {
455 // single sided line
456 midtexture = texturetranslation[sidedef->midtexture];
457 // a single sided line is terminal, so it must mark ends
458 markfloor = markceiling = true;
459 if (linedef->flags & ML_DONTPEGBOTTOM)
460 {
461 vtop = frontsector->floorheight +
462 textureheight[sidedef->midtexture];
463 // bottom of texture at bottom
464 rw_midtexturemid = vtop - viewz;
465 }
466 else
467 {
468 // top of texture at top
469 rw_midtexturemid = worldtop;
470 }
471 rw_midtexturemid += sidedef->rowoffset;
472
473 ds_p->silhouette = SIL_BOTH;
474 ds_p->sprtopclip = screenheightarray;
475 ds_p->sprbottomclip = negonearray;
476 ds_p->bsilheight = INT_MAX;
477 ds_p->tsilheight = INT_MIN;
478 }
479 else
480 {
481 // two sided line
482 ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
483 ds_p->silhouette = 0;
484
485 if (frontsector->floorheight > backsector->floorheight)
486 {
487 ds_p->silhouette = SIL_BOTTOM;
488 ds_p->bsilheight = frontsector->floorheight;
489 }
490 else if (backsector->floorheight > viewz)
491 {
492 ds_p->silhouette = SIL_BOTTOM;
493 ds_p->bsilheight = INT_MAX;
494 // ds_p->sprbottomclip = negonearray;
495 }
496
497 if (frontsector->ceilingheight < backsector->ceilingheight)
498 {
499 ds_p->silhouette |= SIL_TOP;
500 ds_p->tsilheight = frontsector->ceilingheight;
501 }
502 else if (backsector->ceilingheight < viewz)
503 {
504 ds_p->silhouette |= SIL_TOP;
505 ds_p->tsilheight = INT_MIN;
506 // ds_p->sprtopclip = screenheightarray;
507 }
508
509 if (backsector->ceilingheight <= frontsector->floorheight)
510 {
511 ds_p->sprbottomclip = negonearray;
512 ds_p->bsilheight = INT_MAX;
513 ds_p->silhouette |= SIL_BOTTOM;
514 }
515
516 if (backsector->floorheight >= frontsector->ceilingheight)
517 {
518 ds_p->sprtopclip = screenheightarray;
519 ds_p->tsilheight = INT_MIN;
520 ds_p->silhouette |= SIL_TOP;
521 }
522
523 worldhigh = backsector->ceilingheight - viewz;
524 worldlow = backsector->floorheight - viewz;
525
526 // hack to allow height changes in outdoor areas
527 if (frontsector->ceilingpic == skyflatnum
528 && backsector->ceilingpic == skyflatnum)
529 {
530 worldtop = worldhigh;
531 }
532
533
534 if (worldlow != worldbottom
535 || backsector->floorpic != frontsector->floorpic
536 || backsector->lightlevel != frontsector->lightlevel)
537 {
538 markfloor = true;
539 }
540 else
541 {
542 // same plane on both sides
543 markfloor = false;
544 }
545
546
547 if (worldhigh != worldtop
548 || backsector->ceilingpic != frontsector->ceilingpic
549 || backsector->lightlevel != frontsector->lightlevel)
550 {
551 markceiling = true;
552 }
553 else
554 {
555 // same plane on both sides
556 markceiling = false;
557 }
558
559 if (backsector->ceilingheight <= frontsector->floorheight
560 || backsector->floorheight >= frontsector->ceilingheight)
561 {
562 // closed door
563 markceiling = markfloor = true;
564 }
565
566
567 if (worldhigh < worldtop)
568 {
569 // top texture
570 toptexture = texturetranslation[sidedef->toptexture];
571 if (linedef->flags & ML_DONTPEGTOP)
572 {
573 // top of texture at top
574 rw_toptexturemid = worldtop;
575 }
576 else
577 {
578 vtop =
579 backsector->ceilingheight
580 + textureheight[sidedef->toptexture];
581
582 // bottom of texture
583 rw_toptexturemid = vtop - viewz;
584 }
585 }
586 if (worldlow > worldbottom)
587 {
588 // bottom texture
589 bottomtexture = texturetranslation[sidedef->bottomtexture];
590
591 if (linedef->flags & ML_DONTPEGBOTTOM )
592 {
593 // bottom of texture at bottom
594 // top of texture at top
595 rw_bottomtexturemid = worldtop;
596 }
597 else // top of texture at top
598 rw_bottomtexturemid = worldlow;
599 }
600 rw_toptexturemid += sidedef->rowoffset;
601 rw_bottomtexturemid += sidedef->rowoffset;
602
603 // allocate space for masked texture tables
604 if (sidedef->midtexture)
605 {
606 // masked midtexture
607 maskedtexture = true;
608 ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
609 lastopening += rw_stopx - rw_x;
610 }
611 }
612
613 // calculate rw_offset (only needed for textured lines)
614 segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
615
616 if (segtextured)
617 {
618 offsetangle = rw_normalangle-rw_angle1;
619
620 if (offsetangle > ANG180)
621 offsetangle = -offsetangle;
622
623 if (offsetangle > ANG90)
624 offsetangle = ANG90;
625
626 sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
627 rw_offset = FixedMul (hyp, sineval);
628
629 if (rw_normalangle-rw_angle1 < ANG180)
630 rw_offset = -rw_offset;
631
632 rw_offset += sidedef->textureoffset + curline->offset;
633 rw_centerangle = ANG90 + viewangle - rw_normalangle;
634
635 // calculate light table
636 // use different light tables
637 // for horizontal / vertical / diagonal
638 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
639 if (!fixedcolormap)
640 {
641 lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
642
643 if (curline->v1->y == curline->v2->y)
644 lightnum--;
645 else if (curline->v1->x == curline->v2->x)
646 lightnum++;
647
648 if (lightnum < 0)
649 walllights = scalelight[0];
650 else if (lightnum >= LIGHTLEVELS)
651 walllights = scalelight[LIGHTLEVELS-1];
652 else
653 walllights = scalelight[lightnum];
654 }
655 }
656
657 // if a floor / ceiling plane is on the wrong side
658 // of the view plane, it is definitely invisible
659 // and doesn't need to be marked.
660
661
662 if (frontsector->floorheight >= viewz)
663 {
664 // above view plane
665 markfloor = false;
666 }
667
668 if (frontsector->ceilingheight <= viewz
669 && frontsector->ceilingpic != skyflatnum)
670 {
671 // below view plane
672 markceiling = false;
673 }
674
675
676 // calculate incremental stepping values for texture edges
677 worldtop >>= 4;
678 worldbottom >>= 4;
679
680 topstep = -FixedMul (rw_scalestep, worldtop);
681 topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
682
683 bottomstep = -FixedMul (rw_scalestep,worldbottom);
684 bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
685
686 if (backsector)
687 {
688 worldhigh >>= 4;
689 worldlow >>= 4;
690
691 if (worldhigh < worldtop)
692 {
693 pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
694 pixhighstep = -FixedMul (rw_scalestep,worldhigh);
695 }
696
697 if (worldlow > worldbottom)
698 {
699 pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
700 pixlowstep = -FixedMul (rw_scalestep,worldlow);
701 }
702 }
703
704 // render it
705 if (markceiling)
706 ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
707
708 if (markfloor)
709 floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
710
711 R_RenderSegLoop ();
712
713
714 // save sprite clipping info
715 if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture)
716 && !ds_p->sprtopclip)
717 {
718 memcpy (lastopening, ceilingclip+start, sizeof(*lastopening)*(rw_stopx-start));
719 ds_p->sprtopclip = lastopening - start;
720 lastopening += rw_stopx - start;
721 }
722
723 if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture)
724 && !ds_p->sprbottomclip)
725 {
726 memcpy (lastopening, floorclip+start, sizeof(*lastopening)*(rw_stopx-start));
727 ds_p->sprbottomclip = lastopening - start;
728 lastopening += rw_stopx - start;
729 }
730
731 if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
732 {
733 ds_p->silhouette |= SIL_TOP;
734 ds_p->tsilheight = INT_MIN;
735 }
736 if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
737 {
738 ds_p->silhouette |= SIL_BOTTOM;
739 ds_p->bsilheight = INT_MAX;
740 }
741 ds_p++;
742 }
743
744