1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
20 // All the clipping: columns, horizontal spans, sky columns.
22 //-----------------------------------------------------------------------------
26 rcsid[] = "$Id: r_segs.c,v 1.3 1997/01/29 20:10:19 b1 Exp $";
38 // OPTIMIZE: closed two sided lines as single sided
40 // True if any of the segs textures might be visible.
43 // False if the back side is the same plane.
47 boolean maskedtexture;
53 angle_t rw_normalangle;
54 // angle to line origin
62 angle_t rw_centerangle;
67 fixed_t rw_midtexturemid;
68 fixed_t rw_toptexturemid;
69 fixed_t rw_bottomtexturemid;
88 lighttable_t** walllights;
90 short* maskedtexturecol;
95 // R_RenderMaskedSegRange
98 R_RenderMaskedSegRange
108 // Calculate light table.
109 // Use different light tables
110 // for horizontal / vertical / diagonal. Diagonal?
111 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
112 curline = ds->curline;
113 frontsector = curline->frontsector;
114 backsector = curline->backsector;
115 texnum = texturetranslation[curline->sidedef->midtexture];
117 lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
119 if (curline->v1->y == curline->v2->y)
121 else if (curline->v1->x == curline->v2->x)
125 walllights = scalelight[0];
126 else if (lightnum >= LIGHTLEVELS)
127 walllights = scalelight[LIGHTLEVELS-1];
129 walllights = scalelight[lightnum];
131 maskedtexturecol = ds->maskedtexturecol;
133 rw_scalestep = ds->scalestep;
134 spryscale = ds->scale1 + (x1 - ds->x1)*rw_scalestep;
135 mfloorclip = ds->sprbottomclip;
136 mceilingclip = ds->sprtopclip;
139 if (curline->linedef->flags & ML_DONTPEGBOTTOM)
141 dc_texturemid = frontsector->floorheight > backsector->floorheight
142 ? frontsector->floorheight : backsector->floorheight;
143 dc_texturemid = dc_texturemid + textureheight[texnum] - viewz;
147 dc_texturemid =frontsector->ceilingheight<backsector->ceilingheight
148 ? frontsector->ceilingheight : backsector->ceilingheight;
149 dc_texturemid = dc_texturemid - viewz;
151 dc_texturemid += curline->sidedef->rowoffset;
154 dc_colormap = fixedcolormap;
157 for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
159 // calculate lighting
160 if (maskedtexturecol[dc_x] != MAXSHORT)
164 index = spryscale>>LIGHTSCALESHIFT;
166 if (index >= MAXLIGHTSCALE )
167 index = MAXLIGHTSCALE-1;
169 dc_colormap = walllights[index];
172 sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
173 dc_iscale = 0xffffffffu / (unsigned)spryscale;
177 (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
179 R_DrawMaskedColumn (col);
180 maskedtexturecol[dc_x] = MAXSHORT;
182 spryscale += rw_scalestep;
192 // Draws zero, one, or two textures (and possibly a masked
193 // texture) for walls.
194 // Can draw or mark the starting pixel of floor and ceiling
196 // CALLED: CORE LOOPING ROUTINE.
198 #define HEIGHTBITS 12
199 #define HEIGHTUNIT (1<<HEIGHTBITS)
201 void R_RenderSegLoop (void)
208 fixed_t texturecolumn;
212 texturecolumn = 0; // shut up compiler warning
214 for ( ; rw_x < rw_stopx ; rw_x++)
216 // mark floor / ceiling areas
217 yl = (topfrac+HEIGHTUNIT-1)>>HEIGHTBITS;
219 // no space above wall?
220 if (yl < ceilingclip[rw_x]+1)
221 yl = ceilingclip[rw_x]+1;
225 top = ceilingclip[rw_x]+1;
228 if (bottom >= floorclip[rw_x])
229 bottom = floorclip[rw_x]-1;
233 ceilingplane->top[rw_x] = top;
234 ceilingplane->bottom[rw_x] = bottom;
238 yh = bottomfrac>>HEIGHTBITS;
240 if (yh >= floorclip[rw_x])
241 yh = floorclip[rw_x]-1;
246 bottom = floorclip[rw_x]-1;
247 if (top <= ceilingclip[rw_x])
248 top = ceilingclip[rw_x]+1;
251 floorplane->top[rw_x] = top;
252 floorplane->bottom[rw_x] = bottom;
256 // texturecolumn and lighting are independent of wall tiers
259 // calculate texture offset
260 angle = (rw_centerangle + xtoviewangle[rw_x])>>ANGLETOFINESHIFT;
261 texturecolumn = rw_offset-FixedMul(finetangent[angle],rw_distance);
262 texturecolumn >>= FRACBITS;
263 // calculate lighting
264 index = rw_scale>>LIGHTSCALESHIFT;
266 if (index >= MAXLIGHTSCALE )
267 index = MAXLIGHTSCALE-1;
269 dc_colormap = walllights[index];
271 dc_iscale = 0xffffffffu / (unsigned)rw_scale;
274 // draw the wall tiers
280 dc_texturemid = rw_midtexturemid;
281 dc_source = R_GetColumn(midtexture,texturecolumn);
283 ceilingclip[rw_x] = viewheight;
284 floorclip[rw_x] = -1;
292 mid = pixhigh>>HEIGHTBITS;
293 pixhigh += pixhighstep;
295 if (mid >= floorclip[rw_x])
296 mid = floorclip[rw_x]-1;
302 dc_texturemid = rw_toptexturemid;
303 dc_source = R_GetColumn(toptexture,texturecolumn);
305 ceilingclip[rw_x] = mid;
308 ceilingclip[rw_x] = yl-1;
314 ceilingclip[rw_x] = yl-1;
320 mid = (pixlow+HEIGHTUNIT-1)>>HEIGHTBITS;
321 pixlow += pixlowstep;
323 // no space above wall?
324 if (mid <= ceilingclip[rw_x])
325 mid = ceilingclip[rw_x]+1;
331 dc_texturemid = rw_bottomtexturemid;
332 dc_source = R_GetColumn(bottomtexture,
335 floorclip[rw_x] = mid;
338 floorclip[rw_x] = yh+1;
344 floorclip[rw_x] = yh+1;
350 // for backdrawing of masked mid texture
351 maskedtexturecol[rw_x] = texturecolumn;
355 rw_scale += rw_scalestep;
357 bottomfrac += bottomstep;
366 // A wall segment will be drawn
367 // between start and stop pixels (inclusive).
376 angle_t distangle, offsetangle;
380 // don't overflow and crash
381 if (ds_p == &drawsegs[MAXDRAWSEGS])
385 if (start >=viewwidth || start > stop)
386 I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
389 sidedef = curline->sidedef;
390 linedef = curline->linedef;
392 // mark the segment as visible for auto map
393 linedef->flags |= ML_MAPPED;
395 // calculate rw_distance for scale calculation
396 rw_normalangle = curline->angle + ANG90;
397 offsetangle = abs(rw_normalangle-rw_angle1);
399 if (offsetangle > ANG90)
402 distangle = ANG90 - offsetangle;
403 hyp = R_PointToDist (curline->v1->x, curline->v1->y);
404 sineval = finesine[distangle>>ANGLETOFINESHIFT];
405 rw_distance = FixedMul (hyp, sineval);
408 ds_p->x1 = rw_x = start;
410 ds_p->curline = curline;
413 // calculate scale at both ends and step
414 ds_p->scale1 = rw_scale =
415 R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
419 ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
420 ds_p->scalestep = rw_scalestep =
421 (ds_p->scale2 - rw_scale) / (stop-start);
425 ds_p->scale2 = ds_p->scale1;
428 // calculate texture boundaries
429 // and decide if floor / ceiling marks are needed
430 worldtop = frontsector->ceilingheight - viewz;
431 worldbottom = frontsector->floorheight - viewz;
433 midtexture = toptexture = bottomtexture = maskedtexture = 0;
434 ds_p->maskedtexturecol = NULL;
439 midtexture = texturetranslation[sidedef->midtexture];
440 // a single sided line is terminal, so it must mark ends
441 markfloor = markceiling = true;
442 if (linedef->flags & ML_DONTPEGBOTTOM)
444 vtop = frontsector->floorheight +
445 textureheight[sidedef->midtexture];
446 // bottom of texture at bottom
447 rw_midtexturemid = vtop - viewz;
451 // top of texture at top
452 rw_midtexturemid = worldtop;
454 rw_midtexturemid += sidedef->rowoffset;
456 ds_p->silhouette = SIL_BOTH;
457 ds_p->sprtopclip = screenheightarray;
458 ds_p->sprbottomclip = negonearray;
459 ds_p->bsilheight = MAXINT;
460 ds_p->tsilheight = MININT;
465 ds_p->sprtopclip = ds_p->sprbottomclip = NULL;
466 ds_p->silhouette = 0;
468 if (frontsector->floorheight > backsector->floorheight)
470 ds_p->silhouette = SIL_BOTTOM;
471 ds_p->bsilheight = frontsector->floorheight;
473 else if (backsector->floorheight > viewz)
475 ds_p->silhouette = SIL_BOTTOM;
476 ds_p->bsilheight = MAXINT;
477 // ds_p->sprbottomclip = negonearray;
480 if (frontsector->ceilingheight < backsector->ceilingheight)
482 ds_p->silhouette |= SIL_TOP;
483 ds_p->tsilheight = frontsector->ceilingheight;
485 else if (backsector->ceilingheight < viewz)
487 ds_p->silhouette |= SIL_TOP;
488 ds_p->tsilheight = MININT;
489 // ds_p->sprtopclip = screenheightarray;
492 if (backsector->ceilingheight <= frontsector->floorheight)
494 ds_p->sprbottomclip = negonearray;
495 ds_p->bsilheight = MAXINT;
496 ds_p->silhouette |= SIL_BOTTOM;
499 if (backsector->floorheight >= frontsector->ceilingheight)
501 ds_p->sprtopclip = screenheightarray;
502 ds_p->tsilheight = MININT;
503 ds_p->silhouette |= SIL_TOP;
506 worldhigh = backsector->ceilingheight - viewz;
507 worldlow = backsector->floorheight - viewz;
509 // hack to allow height changes in outdoor areas
510 if (frontsector->ceilingpic == skyflatnum
511 && backsector->ceilingpic == skyflatnum)
513 worldtop = worldhigh;
517 if (worldlow != worldbottom
518 || backsector->floorpic != frontsector->floorpic
519 || backsector->lightlevel != frontsector->lightlevel)
525 // same plane on both sides
530 if (worldhigh != worldtop
531 || backsector->ceilingpic != frontsector->ceilingpic
532 || backsector->lightlevel != frontsector->lightlevel)
538 // same plane on both sides
542 if (backsector->ceilingheight <= frontsector->floorheight
543 || backsector->floorheight >= frontsector->ceilingheight)
546 markceiling = markfloor = true;
550 if (worldhigh < worldtop)
553 toptexture = texturetranslation[sidedef->toptexture];
554 if (linedef->flags & ML_DONTPEGTOP)
556 // top of texture at top
557 rw_toptexturemid = worldtop;
562 backsector->ceilingheight
563 + textureheight[sidedef->toptexture];
566 rw_toptexturemid = vtop - viewz;
569 if (worldlow > worldbottom)
572 bottomtexture = texturetranslation[sidedef->bottomtexture];
574 if (linedef->flags & ML_DONTPEGBOTTOM )
576 // bottom of texture at bottom
577 // top of texture at top
578 rw_bottomtexturemid = worldtop;
580 else // top of texture at top
581 rw_bottomtexturemid = worldlow;
583 rw_toptexturemid += sidedef->rowoffset;
584 rw_bottomtexturemid += sidedef->rowoffset;
586 // allocate space for masked texture tables
587 if (sidedef->midtexture)
590 maskedtexture = true;
591 ds_p->maskedtexturecol = maskedtexturecol = lastopening - rw_x;
592 lastopening += rw_stopx - rw_x;
596 // calculate rw_offset (only needed for textured lines)
597 segtextured = midtexture | toptexture | bottomtexture | maskedtexture;
601 offsetangle = rw_normalangle-rw_angle1;
603 if (offsetangle > ANG180)
604 offsetangle = -offsetangle;
606 if (offsetangle > ANG90)
609 sineval = finesine[offsetangle >>ANGLETOFINESHIFT];
610 rw_offset = FixedMul (hyp, sineval);
612 if (rw_normalangle-rw_angle1 < ANG180)
613 rw_offset = -rw_offset;
615 rw_offset += sidedef->textureoffset + curline->offset;
616 rw_centerangle = ANG90 + viewangle - rw_normalangle;
618 // calculate light table
619 // use different light tables
620 // for horizontal / vertical / diagonal
621 // OPTIMIZE: get rid of LIGHTSEGSHIFT globally
624 lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
626 if (curline->v1->y == curline->v2->y)
628 else if (curline->v1->x == curline->v2->x)
632 walllights = scalelight[0];
633 else if (lightnum >= LIGHTLEVELS)
634 walllights = scalelight[LIGHTLEVELS-1];
636 walllights = scalelight[lightnum];
640 // if a floor / ceiling plane is on the wrong side
641 // of the view plane, it is definitely invisible
642 // and doesn't need to be marked.
645 if (frontsector->floorheight >= viewz)
651 if (frontsector->ceilingheight <= viewz
652 && frontsector->ceilingpic != skyflatnum)
659 // calculate incremental stepping values for texture edges
663 topstep = -FixedMul (rw_scalestep, worldtop);
664 topfrac = (centeryfrac>>4) - FixedMul (worldtop, rw_scale);
666 bottomstep = -FixedMul (rw_scalestep,worldbottom);
667 bottomfrac = (centeryfrac>>4) - FixedMul (worldbottom, rw_scale);
674 if (worldhigh < worldtop)
676 pixhigh = (centeryfrac>>4) - FixedMul (worldhigh, rw_scale);
677 pixhighstep = -FixedMul (rw_scalestep,worldhigh);
680 if (worldlow > worldbottom)
682 pixlow = (centeryfrac>>4) - FixedMul (worldlow, rw_scale);
683 pixlowstep = -FixedMul (rw_scalestep,worldlow);
689 ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
692 floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
697 // save sprite clipping info
698 if ( ((ds_p->silhouette & SIL_TOP) || maskedtexture)
699 && !ds_p->sprtopclip)
701 memcpy (lastopening, ceilingclip+start, 2*(rw_stopx-start));
702 ds_p->sprtopclip = lastopening - start;
703 lastopening += rw_stopx - start;
706 if ( ((ds_p->silhouette & SIL_BOTTOM) || maskedtexture)
707 && !ds_p->sprbottomclip)
709 memcpy (lastopening, floorclip+start, 2*(rw_stopx-start));
710 ds_p->sprbottomclip = lastopening - start;
711 lastopening += rw_stopx - start;
714 if (maskedtexture && !(ds_p->silhouette&SIL_TOP))
716 ds_p->silhouette |= SIL_TOP;
717 ds_p->tsilheight = MININT;
719 if (maskedtexture && !(ds_p->silhouette&SIL_BOTTOM))
721 ds_p->silhouette |= SIL_BOTTOM;
722 ds_p->bsilheight = MAXINT;