1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
4 // Copyright(C) 1993-1996 Id Software, Inc.
5 // Copyright(C) 2005 Simon Howard
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
23 // All the clipping: columns, horizontal spans, sky columns.
25 //-----------------------------------------------------------------------------
44 // OPTIMIZE: closed two sided lines as single sided
46 // True if any of the segs textures might be visible.
49 // False if the back side is the same plane.
53 boolean maskedtexture
;
59 angle_t rw_normalangle
;
60 // angle to line origin
68 angle_t rw_centerangle
;
73 fixed_t rw_midtexturemid
;
74 fixed_t rw_toptexturemid
;
75 fixed_t rw_bottomtexturemid
;
94 lighttable_t
** walllights
;
96 short* maskedtexturecol
;
101 // R_RenderMaskedSegRange
104 R_RenderMaskedSegRange
114 // Calculate light table.
115 // Use different light tables
116 // for horizontal / vertical / diagonal. Diagonal?
117 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
118 curline
= ds
->curline
;
119 frontsector
= curline
->frontsector
;
120 backsector
= curline
->backsector
;
121 texnum
= texturetranslation
[curline
->sidedef
->midtexture
];
123 lightnum
= (frontsector
->lightlevel
>> LIGHTSEGSHIFT
)+extralight
;
125 if (curline
->v1
->y
== curline
->v2
->y
)
127 else if (curline
->v1
->x
== curline
->v2
->x
)
131 walllights
= scalelight
[0];
132 else if (lightnum
>= LIGHTLEVELS
)
133 walllights
= scalelight
[LIGHTLEVELS
-1];
135 walllights
= scalelight
[lightnum
];
137 maskedtexturecol
= ds
->maskedtexturecol
;
139 rw_scalestep
= ds
->scalestep
;
140 spryscale
= ds
->scale1
+ (x1
- ds
->x1
)*rw_scalestep
;
141 mfloorclip
= ds
->sprbottomclip
;
142 mceilingclip
= ds
->sprtopclip
;
145 if (curline
->linedef
->flags
& ML_DONTPEGBOTTOM
)
147 dc_texturemid
= frontsector
->floorheight
> backsector
->floorheight
148 ? frontsector
->floorheight
: backsector
->floorheight
;
149 dc_texturemid
= dc_texturemid
+ textureheight
[texnum
] - viewz
;
153 dc_texturemid
=frontsector
->ceilingheight
<backsector
->ceilingheight
154 ? frontsector
->ceilingheight
: backsector
->ceilingheight
;
155 dc_texturemid
= dc_texturemid
- viewz
;
157 dc_texturemid
+= curline
->sidedef
->rowoffset
;
160 dc_colormap
= fixedcolormap
;
163 for (dc_x
= x1
; dc_x
<= x2
; dc_x
++)
165 // calculate lighting
166 if (maskedtexturecol
[dc_x
] != SHRT_MAX
)
170 index
= spryscale
>>LIGHTSCALESHIFT
;
172 if (index
>= MAXLIGHTSCALE
)
173 index
= MAXLIGHTSCALE
-1;
175 dc_colormap
= walllights
[index
];
178 sprtopscreen
= centeryfrac
- FixedMul(dc_texturemid
, spryscale
);
179 dc_iscale
= 0xffffffffu
/ (unsigned)spryscale
;
183 (byte
*)R_GetColumn(texnum
,maskedtexturecol
[dc_x
]) -3);
185 R_DrawMaskedColumn (col
);
186 maskedtexturecol
[dc_x
] = SHRT_MAX
;
188 spryscale
+= rw_scalestep
;
198 // Draws zero, one, or two textures (and possibly a masked
199 // texture) for walls.
200 // Can draw or mark the starting pixel of floor and ceiling
202 // CALLED: CORE LOOPING ROUTINE.
204 #define HEIGHTBITS 12
205 #define HEIGHTUNIT (1<<HEIGHTBITS)
207 void R_RenderSegLoop (void)
214 fixed_t texturecolumn
;
218 for ( ; rw_x
< rw_stopx
; rw_x
++)
220 // mark floor / ceiling areas
221 yl
= (topfrac
+HEIGHTUNIT
-1)>>HEIGHTBITS
;
223 // no space above wall?
224 if (yl
< ceilingclip
[rw_x
]+1)
225 yl
= ceilingclip
[rw_x
]+1;
229 top
= ceilingclip
[rw_x
]+1;
232 if (bottom
>= floorclip
[rw_x
])
233 bottom
= floorclip
[rw_x
]-1;
237 ceilingplane
->top
[rw_x
] = top
;
238 ceilingplane
->bottom
[rw_x
] = bottom
;
242 yh
= bottomfrac
>>HEIGHTBITS
;
244 if (yh
>= floorclip
[rw_x
])
245 yh
= floorclip
[rw_x
]-1;
250 bottom
= floorclip
[rw_x
]-1;
251 if (top
<= ceilingclip
[rw_x
])
252 top
= ceilingclip
[rw_x
]+1;
255 floorplane
->top
[rw_x
] = top
;
256 floorplane
->bottom
[rw_x
] = bottom
;
260 // texturecolumn and lighting are independent of wall tiers
263 // calculate texture offset
264 angle
= (rw_centerangle
+ xtoviewangle
[rw_x
])>>ANGLETOFINESHIFT
;
265 texturecolumn
= rw_offset
-FixedMul(finetangent
[angle
],rw_distance
);
266 texturecolumn
>>= FRACBITS
;
267 // calculate lighting
268 index
= rw_scale
>>LIGHTSCALESHIFT
;
270 if (index
>= MAXLIGHTSCALE
)
271 index
= MAXLIGHTSCALE
-1;
273 dc_colormap
= walllights
[index
];
275 dc_iscale
= 0xffffffffu
/ (unsigned)rw_scale
;
279 // purely to shut up the compiler
284 // draw the wall tiers
290 dc_texturemid
= rw_midtexturemid
;
291 dc_source
= R_GetColumn(midtexture
,texturecolumn
);
293 ceilingclip
[rw_x
] = viewheight
;
294 floorclip
[rw_x
] = -1;
302 mid
= pixhigh
>>HEIGHTBITS
;
303 pixhigh
+= pixhighstep
;
305 if (mid
>= floorclip
[rw_x
])
306 mid
= floorclip
[rw_x
]-1;
312 dc_texturemid
= rw_toptexturemid
;
313 dc_source
= R_GetColumn(toptexture
,texturecolumn
);
315 ceilingclip
[rw_x
] = mid
;
318 ceilingclip
[rw_x
] = yl
-1;
324 ceilingclip
[rw_x
] = yl
-1;
330 mid
= (pixlow
+HEIGHTUNIT
-1)>>HEIGHTBITS
;
331 pixlow
+= pixlowstep
;
333 // no space above wall?
334 if (mid
<= ceilingclip
[rw_x
])
335 mid
= ceilingclip
[rw_x
]+1;
341 dc_texturemid
= rw_bottomtexturemid
;
342 dc_source
= R_GetColumn(bottomtexture
,
345 floorclip
[rw_x
] = mid
;
348 floorclip
[rw_x
] = yh
+1;
354 floorclip
[rw_x
] = yh
+1;
360 // for backdrawing of masked mid texture
361 maskedtexturecol
[rw_x
] = texturecolumn
;
365 rw_scale
+= rw_scalestep
;
367 bottomfrac
+= bottomstep
;
376 // A wall segment will be drawn
377 // between start and stop pixels (inclusive).
386 angle_t distangle
, offsetangle
;
390 // don't overflow and crash
391 if (ds_p
== &drawsegs
[MAXDRAWSEGS
])
395 if (start
>=viewwidth
|| start
> stop
)
396 I_Error ("Bad R_RenderWallRange: %i to %i", start
, stop
);
399 sidedef
= curline
->sidedef
;
400 linedef
= curline
->linedef
;
402 // mark the segment as visible for auto map
403 linedef
->flags
|= ML_MAPPED
;
405 // calculate rw_distance for scale calculation
406 rw_normalangle
= curline
->angle
+ ANG90
;
407 offsetangle
= abs(rw_normalangle
-rw_angle1
);
409 if (offsetangle
> ANG90
)
412 distangle
= ANG90
- offsetangle
;
413 hyp
= R_PointToDist (curline
->v1
->x
, curline
->v1
->y
);
414 sineval
= finesine
[distangle
>>ANGLETOFINESHIFT
];
415 rw_distance
= FixedMul (hyp
, sineval
);
418 ds_p
->x1
= rw_x
= start
;
420 ds_p
->curline
= curline
;
423 // calculate scale at both ends and step
424 ds_p
->scale1
= rw_scale
=
425 R_ScaleFromGlobalAngle (viewangle
+ xtoviewangle
[start
]);
429 ds_p
->scale2
= R_ScaleFromGlobalAngle (viewangle
+ xtoviewangle
[stop
]);
430 ds_p
->scalestep
= rw_scalestep
=
431 (ds_p
->scale2
- rw_scale
) / (stop
-start
);
435 // UNUSED: try to fix the stretched line bug
437 if (rw_distance
< FRACUNIT
/2)
442 trx
= curline
->v1
->x
- viewx
;
443 try = curline
->v1
->y
- viewy
;
445 gxt
= FixedMul(trx
,viewcos
);
446 gyt
= -FixedMul(try,viewsin
);
447 ds_p
->scale1
= FixedDiv(projection
, gxt
-gyt
)<<detailshift
;
450 ds_p
->scale2
= ds_p
->scale1
;
453 // calculate texture boundaries
454 // and decide if floor / ceiling marks are needed
455 worldtop
= frontsector
->ceilingheight
- viewz
;
456 worldbottom
= frontsector
->floorheight
- viewz
;
458 midtexture
= toptexture
= bottomtexture
= maskedtexture
= 0;
459 ds_p
->maskedtexturecol
= NULL
;
464 midtexture
= texturetranslation
[sidedef
->midtexture
];
465 // a single sided line is terminal, so it must mark ends
466 markfloor
= markceiling
= true;
467 if (linedef
->flags
& ML_DONTPEGBOTTOM
)
469 vtop
= frontsector
->floorheight
+
470 textureheight
[sidedef
->midtexture
];
471 // bottom of texture at bottom
472 rw_midtexturemid
= vtop
- viewz
;
476 // top of texture at top
477 rw_midtexturemid
= worldtop
;
479 rw_midtexturemid
+= sidedef
->rowoffset
;
481 ds_p
->silhouette
= SIL_BOTH
;
482 ds_p
->sprtopclip
= screenheightarray
;
483 ds_p
->sprbottomclip
= negonearray
;
484 ds_p
->bsilheight
= INT_MAX
;
485 ds_p
->tsilheight
= INT_MIN
;
490 ds_p
->sprtopclip
= ds_p
->sprbottomclip
= NULL
;
491 ds_p
->silhouette
= 0;
493 if (frontsector
->floorheight
> backsector
->floorheight
)
495 ds_p
->silhouette
= SIL_BOTTOM
;
496 ds_p
->bsilheight
= frontsector
->floorheight
;
498 else if (backsector
->floorheight
> viewz
)
500 ds_p
->silhouette
= SIL_BOTTOM
;
501 ds_p
->bsilheight
= INT_MAX
;
502 // ds_p->sprbottomclip = negonearray;
505 if (frontsector
->ceilingheight
< backsector
->ceilingheight
)
507 ds_p
->silhouette
|= SIL_TOP
;
508 ds_p
->tsilheight
= frontsector
->ceilingheight
;
510 else if (backsector
->ceilingheight
< viewz
)
512 ds_p
->silhouette
|= SIL_TOP
;
513 ds_p
->tsilheight
= INT_MIN
;
514 // ds_p->sprtopclip = screenheightarray;
517 if (backsector
->ceilingheight
<= frontsector
->floorheight
)
519 ds_p
->sprbottomclip
= negonearray
;
520 ds_p
->bsilheight
= INT_MAX
;
521 ds_p
->silhouette
|= SIL_BOTTOM
;
524 if (backsector
->floorheight
>= frontsector
->ceilingheight
)
526 ds_p
->sprtopclip
= screenheightarray
;
527 ds_p
->tsilheight
= INT_MIN
;
528 ds_p
->silhouette
|= SIL_TOP
;
531 worldhigh
= backsector
->ceilingheight
- viewz
;
532 worldlow
= backsector
->floorheight
- viewz
;
534 // hack to allow height changes in outdoor areas
535 if (frontsector
->ceilingpic
== skyflatnum
536 && backsector
->ceilingpic
== skyflatnum
)
538 worldtop
= worldhigh
;
542 if (worldlow
!= worldbottom
543 || backsector
->floorpic
!= frontsector
->floorpic
544 || backsector
->lightlevel
!= frontsector
->lightlevel
)
550 // same plane on both sides
555 if (worldhigh
!= worldtop
556 || backsector
->ceilingpic
!= frontsector
->ceilingpic
557 || backsector
->lightlevel
!= frontsector
->lightlevel
)
563 // same plane on both sides
567 if (backsector
->ceilingheight
<= frontsector
->floorheight
568 || backsector
->floorheight
>= frontsector
->ceilingheight
)
571 markceiling
= markfloor
= true;
575 if (worldhigh
< worldtop
)
578 toptexture
= texturetranslation
[sidedef
->toptexture
];
579 if (linedef
->flags
& ML_DONTPEGTOP
)
581 // top of texture at top
582 rw_toptexturemid
= worldtop
;
587 backsector
->ceilingheight
588 + textureheight
[sidedef
->toptexture
];
591 rw_toptexturemid
= vtop
- viewz
;
594 if (worldlow
> worldbottom
)
597 bottomtexture
= texturetranslation
[sidedef
->bottomtexture
];
599 if (linedef
->flags
& ML_DONTPEGBOTTOM
)
601 // bottom of texture at bottom
602 // top of texture at top
603 rw_bottomtexturemid
= worldtop
;
605 else // top of texture at top
606 rw_bottomtexturemid
= worldlow
;
608 rw_toptexturemid
+= sidedef
->rowoffset
;
609 rw_bottomtexturemid
+= sidedef
->rowoffset
;
611 // allocate space for masked texture tables
612 if (sidedef
->midtexture
)
615 maskedtexture
= true;
616 ds_p
->maskedtexturecol
= maskedtexturecol
= lastopening
- rw_x
;
617 lastopening
+= rw_stopx
- rw_x
;
621 // calculate rw_offset (only needed for textured lines)
622 segtextured
= midtexture
| toptexture
| bottomtexture
| maskedtexture
;
626 offsetangle
= rw_normalangle
-rw_angle1
;
628 if (offsetangle
> ANG180
)
629 offsetangle
= -offsetangle
;
631 if (offsetangle
> ANG90
)
634 sineval
= finesine
[offsetangle
>>ANGLETOFINESHIFT
];
635 rw_offset
= FixedMul (hyp
, sineval
);
637 if (rw_normalangle
-rw_angle1
< ANG180
)
638 rw_offset
= -rw_offset
;
640 rw_offset
+= sidedef
->textureoffset
+ curline
->offset
;
641 rw_centerangle
= ANG90
+ viewangle
- rw_normalangle
;
643 // calculate light table
644 // use different light tables
645 // for horizontal / vertical / diagonal
646 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
649 lightnum
= (frontsector
->lightlevel
>> LIGHTSEGSHIFT
)+extralight
;
651 if (curline
->v1
->y
== curline
->v2
->y
)
653 else if (curline
->v1
->x
== curline
->v2
->x
)
657 walllights
= scalelight
[0];
658 else if (lightnum
>= LIGHTLEVELS
)
659 walllights
= scalelight
[LIGHTLEVELS
-1];
661 walllights
= scalelight
[lightnum
];
665 // if a floor / ceiling plane is on the wrong side
666 // of the view plane, it is definitely invisible
667 // and doesn't need to be marked.
670 if (frontsector
->floorheight
>= viewz
)
676 if (frontsector
->ceilingheight
<= viewz
677 && frontsector
->ceilingpic
!= skyflatnum
)
684 // calculate incremental stepping values for texture edges
688 topstep
= -FixedMul (rw_scalestep
, worldtop
);
689 topfrac
= (centeryfrac
>>4) - FixedMul (worldtop
, rw_scale
);
691 bottomstep
= -FixedMul (rw_scalestep
,worldbottom
);
692 bottomfrac
= (centeryfrac
>>4) - FixedMul (worldbottom
, rw_scale
);
699 if (worldhigh
< worldtop
)
701 pixhigh
= (centeryfrac
>>4) - FixedMul (worldhigh
, rw_scale
);
702 pixhighstep
= -FixedMul (rw_scalestep
,worldhigh
);
705 if (worldlow
> worldbottom
)
707 pixlow
= (centeryfrac
>>4) - FixedMul (worldlow
, rw_scale
);
708 pixlowstep
= -FixedMul (rw_scalestep
,worldlow
);
714 ceilingplane
= R_CheckPlane (ceilingplane
, rw_x
, rw_stopx
-1);
717 floorplane
= R_CheckPlane (floorplane
, rw_x
, rw_stopx
-1);
722 // save sprite clipping info
723 if ( ((ds_p
->silhouette
& SIL_TOP
) || maskedtexture
)
724 && !ds_p
->sprtopclip
)
726 memcpy (lastopening
, ceilingclip
+start
, 2*(rw_stopx
-start
));
727 ds_p
->sprtopclip
= lastopening
- start
;
728 lastopening
+= rw_stopx
- start
;
731 if ( ((ds_p
->silhouette
& SIL_BOTTOM
) || maskedtexture
)
732 && !ds_p
->sprbottomclip
)
734 memcpy (lastopening
, floorclip
+start
, 2*(rw_stopx
-start
));
735 ds_p
->sprbottomclip
= lastopening
- start
;
736 lastopening
+= rw_stopx
- start
;
739 if (maskedtexture
&& !(ds_p
->silhouette
&SIL_TOP
))
741 ds_p
->silhouette
|= SIL_TOP
;
742 ds_p
->tsilheight
= INT_MIN
;
744 if (maskedtexture
&& !(ds_p
->silhouette
&SIL_BOTTOM
))
746 ds_p
->silhouette
|= SIL_BOTTOM
;
747 ds_p
->bsilheight
= INT_MAX
;