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