Add key bindings for pause, message refresh.
[chocolate-doom.git] / src / r_segs.c
blob5150b6947672131012f88c9b6ace4700529ef42e
1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // Copyright(C) 1993-1996 Id Software, Inc.
5 // Copyright(C) 2005 Simon Howard
6 //
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
20 // 02111-1307, USA.
22 // DESCRIPTION:
23 // All the clipping: columns, horizontal spans, sky columns.
25 //-----------------------------------------------------------------------------
33 #include <stdlib.h>
35 #include "i_system.h"
37 #include "doomdef.h"
38 #include "doomstat.h"
40 #include "r_local.h"
41 #include "r_sky.h"
44 // OPTIMIZE: closed two sided lines as single sided
46 // True if any of the segs textures might be visible.
47 boolean segtextured;
49 // False if the back side is the same plane.
50 boolean markfloor;
51 boolean markceiling;
53 boolean maskedtexture;
54 int toptexture;
55 int bottomtexture;
56 int midtexture;
59 angle_t rw_normalangle;
60 // angle to line origin
61 int rw_angle1;
64 // regular wall
66 int rw_x;
67 int rw_stopx;
68 angle_t rw_centerangle;
69 fixed_t rw_offset;
70 fixed_t rw_distance;
71 fixed_t rw_scale;
72 fixed_t rw_scalestep;
73 fixed_t rw_midtexturemid;
74 fixed_t rw_toptexturemid;
75 fixed_t rw_bottomtexturemid;
77 int worldtop;
78 int worldbottom;
79 int worldhigh;
80 int worldlow;
82 fixed_t pixhigh;
83 fixed_t pixlow;
84 fixed_t pixhighstep;
85 fixed_t pixlowstep;
87 fixed_t topfrac;
88 fixed_t topstep;
90 fixed_t bottomfrac;
91 fixed_t bottomstep;
94 lighttable_t** walllights;
96 short* maskedtexturecol;
101 // R_RenderMaskedSegRange
103 void
104 R_RenderMaskedSegRange
105 ( drawseg_t* ds,
106 int x1,
107 int x2 )
109 unsigned index;
110 column_t* col;
111 int lightnum;
112 int texnum;
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)
126 lightnum--;
127 else if (curline->v1->x == curline->v2->x)
128 lightnum++;
130 if (lightnum < 0)
131 walllights = scalelight[0];
132 else if (lightnum >= LIGHTLEVELS)
133 walllights = scalelight[LIGHTLEVELS-1];
134 else
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;
144 // find positioning
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;
151 else
153 dc_texturemid =frontsector->ceilingheight<backsector->ceilingheight
154 ? frontsector->ceilingheight : backsector->ceilingheight;
155 dc_texturemid = dc_texturemid - viewz;
157 dc_texturemid += curline->sidedef->rowoffset;
159 if (fixedcolormap)
160 dc_colormap = fixedcolormap;
162 // draw the columns
163 for (dc_x = x1 ; dc_x <= x2 ; dc_x++)
165 // calculate lighting
166 if (maskedtexturecol[dc_x] != SHRT_MAX)
168 if (!fixedcolormap)
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;
181 // draw the texture
182 col = (column_t *)(
183 (byte *)R_GetColumn(texnum,maskedtexturecol[dc_x]) -3);
185 R_DrawMaskedColumn (col);
186 maskedtexturecol[dc_x] = SHRT_MAX;
188 spryscale += rw_scalestep;
197 // R_RenderSegLoop
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
201 // textures.
202 // CALLED: CORE LOOPING ROUTINE.
204 #define HEIGHTBITS 12
205 #define HEIGHTUNIT (1<<HEIGHTBITS)
207 void R_RenderSegLoop (void)
209 angle_t angle;
210 unsigned index;
211 int yl;
212 int yh;
213 int mid;
214 fixed_t texturecolumn;
215 int top;
216 int bottom;
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;
227 if (markceiling)
229 top = ceilingclip[rw_x]+1;
230 bottom = yl-1;
232 if (bottom >= floorclip[rw_x])
233 bottom = floorclip[rw_x]-1;
235 if (top <= bottom)
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;
247 if (markfloor)
249 top = yh+1;
250 bottom = floorclip[rw_x]-1;
251 if (top <= ceilingclip[rw_x])
252 top = ceilingclip[rw_x]+1;
253 if (top <= bottom)
255 floorplane->top[rw_x] = top;
256 floorplane->bottom[rw_x] = bottom;
260 // texturecolumn and lighting are independent of wall tiers
261 if (segtextured)
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];
274 dc_x = rw_x;
275 dc_iscale = 0xffffffffu / (unsigned)rw_scale;
277 else
279 // purely to shut up the compiler
281 texturecolumn = 0;
284 // draw the wall tiers
285 if (midtexture)
287 // single sided line
288 dc_yl = yl;
289 dc_yh = yh;
290 dc_texturemid = rw_midtexturemid;
291 dc_source = R_GetColumn(midtexture,texturecolumn);
292 colfunc ();
293 ceilingclip[rw_x] = viewheight;
294 floorclip[rw_x] = -1;
296 else
298 // two sided line
299 if (toptexture)
301 // top wall
302 mid = pixhigh>>HEIGHTBITS;
303 pixhigh += pixhighstep;
305 if (mid >= floorclip[rw_x])
306 mid = floorclip[rw_x]-1;
308 if (mid >= yl)
310 dc_yl = yl;
311 dc_yh = mid;
312 dc_texturemid = rw_toptexturemid;
313 dc_source = R_GetColumn(toptexture,texturecolumn);
314 colfunc ();
315 ceilingclip[rw_x] = mid;
317 else
318 ceilingclip[rw_x] = yl-1;
320 else
322 // no top wall
323 if (markceiling)
324 ceilingclip[rw_x] = yl-1;
327 if (bottomtexture)
329 // bottom wall
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;
337 if (mid <= yh)
339 dc_yl = mid;
340 dc_yh = yh;
341 dc_texturemid = rw_bottomtexturemid;
342 dc_source = R_GetColumn(bottomtexture,
343 texturecolumn);
344 colfunc ();
345 floorclip[rw_x] = mid;
347 else
348 floorclip[rw_x] = yh+1;
350 else
352 // no bottom wall
353 if (markfloor)
354 floorclip[rw_x] = yh+1;
357 if (maskedtexture)
359 // save texturecol
360 // for backdrawing of masked mid texture
361 maskedtexturecol[rw_x] = texturecolumn;
365 rw_scale += rw_scalestep;
366 topfrac += topstep;
367 bottomfrac += bottomstep;
375 // R_StoreWallRange
376 // A wall segment will be drawn
377 // between start and stop pixels (inclusive).
379 void
380 R_StoreWallRange
381 ( int start,
382 int stop )
384 fixed_t hyp;
385 fixed_t sineval;
386 angle_t distangle, offsetangle;
387 fixed_t vtop;
388 int lightnum;
390 // don't overflow and crash
391 if (ds_p == &drawsegs[MAXDRAWSEGS])
392 return;
394 #ifdef RANGECHECK
395 if (start >=viewwidth || start > stop)
396 I_Error ("Bad R_RenderWallRange: %i to %i", start , stop);
397 #endif
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)
410 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;
419 ds_p->x2 = stop;
420 ds_p->curline = curline;
421 rw_stopx = stop+1;
423 // calculate scale at both ends and step
424 ds_p->scale1 = rw_scale =
425 R_ScaleFromGlobalAngle (viewangle + xtoviewangle[start]);
427 if (stop > start )
429 ds_p->scale2 = R_ScaleFromGlobalAngle (viewangle + xtoviewangle[stop]);
430 ds_p->scalestep = rw_scalestep =
431 (ds_p->scale2 - rw_scale) / (stop-start);
433 else
435 // UNUSED: try to fix the stretched line bug
436 #if 0
437 if (rw_distance < FRACUNIT/2)
439 fixed_t trx,try;
440 fixed_t gxt,gyt;
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;
449 #endif
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;
461 if (!backsector)
463 // single sided line
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;
474 else
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;
487 else
489 // two sided line
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)
546 markfloor = true;
548 else
550 // same plane on both sides
551 markfloor = false;
555 if (worldhigh != worldtop
556 || backsector->ceilingpic != frontsector->ceilingpic
557 || backsector->lightlevel != frontsector->lightlevel)
559 markceiling = true;
561 else
563 // same plane on both sides
564 markceiling = false;
567 if (backsector->ceilingheight <= frontsector->floorheight
568 || backsector->floorheight >= frontsector->ceilingheight)
570 // closed door
571 markceiling = markfloor = true;
575 if (worldhigh < worldtop)
577 // top texture
578 toptexture = texturetranslation[sidedef->toptexture];
579 if (linedef->flags & ML_DONTPEGTOP)
581 // top of texture at top
582 rw_toptexturemid = worldtop;
584 else
586 vtop =
587 backsector->ceilingheight
588 + textureheight[sidedef->toptexture];
590 // bottom of texture
591 rw_toptexturemid = vtop - viewz;
594 if (worldlow > worldbottom)
596 // bottom texture
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)
614 // masked 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;
624 if (segtextured)
626 offsetangle = rw_normalangle-rw_angle1;
628 if (offsetangle > ANG180)
629 offsetangle = -offsetangle;
631 if (offsetangle > ANG90)
632 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
647 if (!fixedcolormap)
649 lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight;
651 if (curline->v1->y == curline->v2->y)
652 lightnum--;
653 else if (curline->v1->x == curline->v2->x)
654 lightnum++;
656 if (lightnum < 0)
657 walllights = scalelight[0];
658 else if (lightnum >= LIGHTLEVELS)
659 walllights = scalelight[LIGHTLEVELS-1];
660 else
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)
672 // above view plane
673 markfloor = false;
676 if (frontsector->ceilingheight <= viewz
677 && frontsector->ceilingpic != skyflatnum)
679 // below view plane
680 markceiling = false;
684 // calculate incremental stepping values for texture edges
685 worldtop >>= 4;
686 worldbottom >>= 4;
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);
694 if (backsector)
696 worldhigh >>= 4;
697 worldlow >>= 4;
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);
712 // render it
713 if (markceiling)
714 ceilingplane = R_CheckPlane (ceilingplane, rw_x, rw_stopx-1);
716 if (markfloor)
717 floorplane = R_CheckPlane (floorplane, rw_x, rw_stopx-1);
719 R_RenderSegLoop ();
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;
749 ds_p++;