]> git.lizzy.rs Git - plan9front.git/blob - sys/src/games/doom/r_things.c
bring games/swar from 1ed sources.
[plan9front.git] / sys / src / games / doom / r_things.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 //      Refresh of things, i.e. objects represented by sprites.
21 //
22 //-----------------------------------------------------------------------------
23
24
25 static const char
26 rcsid[] = "$Id: r_things.c,v 1.5 1997/02/03 16:47:56 b1 Exp $";
27
28 #include "doomdef.h"
29 #include "m_swap.h"
30
31 #include "i_system.h"
32 #include "z_zone.h"
33 #include "w_wad.h"
34
35 #include "r_local.h"
36
37 #include "doomstat.h"
38
39
40
41 #define MINZ                            (FRACUNIT*4)
42 #define BASEYCENTER                     100
43
44 //void R_DrawColumn (void);
45 //void R_DrawFuzzColumn (void);
46
47
48
49 typedef struct
50 {
51         int     x1;
52         int     x2;
53
54         int     column;
55         int     topclip;
56         int     bottomclip;
57 } maskdraw_t;
58
59
60
61 //
62 // Sprite rotation 0 is facing the viewer,
63 //  rotation 1 is one angle turn CLOCKWISE around the axis.
64 // This is not the same as the angle,
65 //  which increases counter clockwise (protractor).
66 // There was a lot of stuff grabbed wrong, so I changed it...
67 //
68 fixed_t         pspritescale;
69 fixed_t         pspriteiscale;
70
71 lighttable_t**  spritelights;
72
73 // constant arrays
74 //  used for psprite clipping and initializing clipping
75 short           negonearray[SCREENWIDTH];
76 short           screenheightarray[SCREENWIDTH];
77
78
79 //
80 // INITIALIZATION FUNCTIONS
81 //
82
83 // variables used to look up
84 //  and range check thing_t sprites patches
85 spritedef_t*    sprites;
86 int             numsprites;
87
88 spriteframe_t   sprtemp[29];
89 int             maxframe;
90 char*           spritename;
91
92
93
94
95 //
96 // R_InstallSpriteLump
97 // Local function for R_InitSprites.
98 //
99 void
100 R_InstallSpriteLump
101 ( int           lump,
102   unsigned      frame,
103   unsigned      rotation,
104   boolean       flipped )
105 {
106     int         r;
107         
108     if (frame >= 29 || rotation > 8)
109         I_Error("R_InstallSpriteLump: "
110                 "Bad frame characters in lump %i", lump);
111         
112     if ((int)frame > maxframe)
113         maxframe = frame;
114                 
115     if (rotation == 0)
116     {
117         // the lump should be used for all rotations
118         if (sprtemp[frame].rotate == false)
119             I_Error ("R_InitSprites: Sprite %s frame %c has "
120                      "multip rot=0 lump", spritename, 'A'+frame);
121
122         if (sprtemp[frame].rotate == true)
123             I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
124                      "and a rot=0 lump", spritename, 'A'+frame);
125                         
126         sprtemp[frame].rotate = false;
127         for (r=0 ; r<8 ; r++)
128         {
129             sprtemp[frame].lump[r] = lump - firstspritelump;
130             sprtemp[frame].flip[r] = (byte)flipped;
131         }
132         return;
133     }
134         
135     // the lump is only used for one rotation
136     if (sprtemp[frame].rotate == false)
137         I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
138                  "and a rot=0 lump", spritename, 'A'+frame);
139                 
140     sprtemp[frame].rotate = true;
141
142     // make 0 based
143     rotation--;         
144     if (sprtemp[frame].lump[rotation] != -1)
145         I_Error ("R_InitSprites: Sprite %s : %c : %c "
146                  "has two lumps mapped to it",
147                  spritename, 'A'+frame, '1'+rotation);
148                 
149     sprtemp[frame].lump[rotation] = lump - firstspritelump;
150     sprtemp[frame].flip[rotation] = (byte)flipped;
151 }
152
153
154
155
156 //
157 // R_InitSpriteDefs
158 // Pass a null terminated list of sprite names
159 //  (4 chars exactly) to be used.
160 // Builds the sprite rotation matrixes to account
161 //  for horizontally flipped sprites.
162 // Will report an error if the lumps are inconsistant. 
163 // Only called at startup.
164 //
165 // Sprite lump names are 4 characters for the actor,
166 //  a letter for the frame, and a number for the rotation.
167 // A sprite that is flippable will have an additional
168 //  letter/number appended.
169 // The rotation character can be 0 to signify no rotations.
170 //
171 void R_InitSpriteDefs (char** namelist) 
172
173 /*    char**    check; */
174     int         i;
175     int         l;
176     int         frame;
177     int         rotation;
178     int         start;
179     int         end;
180     int         patched;
181     char*       name;
182
183 /* BUG
184    This would work if the namelist was NULL terminated which it is not.
185    The array comes from info.c which is limited to NUMSPRITES, so simply
186    use NUMSPRITES for numsprites.. simple.
187
188    This is left here in case a decision is made to make it NULL terminated.
189
190     // count the number of sprite names
191     check = namelist;
192     while (*check != NULL)
193         check++;
194
195     numsprites = check-namelist;
196
197     if (!numsprites)
198         return;
199 */
200 numsprites = NUMSPRITES;
201                 
202     sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
203         
204     start = firstspritelump-1;
205     end = lastspritelump+1;
206         
207     // scan all the lump names for each of the names,
208     //  noting the highest frame letter.
209     // Just compare 4 characters as ints
210     for (i=0 ; i<numsprites ; i++)
211     {
212         spritename = namelist[i];
213         memset (sprtemp,-1, sizeof(sprtemp));
214                 
215         maxframe = -1;
216         name = namelist[i];
217         
218         // scan the lumps,
219         //  filling in the frames for whatever is found
220         for (l=start+1 ; l<end ; l++)
221         {
222             if (memcmp(lumpinfo[l].name, name, 4) == 0)
223             {
224                 frame = lumpinfo[l].name[4] - 'A';
225                 rotation = lumpinfo[l].name[5] - '0';
226
227                 if (modifiedgame)
228                     patched = W_GetNumForName (lumpinfo[l].name);
229                 else
230                     patched = l;
231
232                 R_InstallSpriteLump (patched, frame, rotation, false);
233
234                 if (lumpinfo[l].name[6])
235                 {
236                     frame = lumpinfo[l].name[6] - 'A';
237                     rotation = lumpinfo[l].name[7] - '0';
238                     R_InstallSpriteLump (l, frame, rotation, true);
239                 }
240             }
241         }
242         
243         // check the frames that were found for completeness
244         if (maxframe == -1)
245         {
246             sprites[i].numframes = 0;
247             continue;
248         }
249                 
250         maxframe++;
251         
252         for (frame = 0 ; frame < maxframe ; frame++)
253         {
254             switch ((int)sprtemp[frame].rotate)
255             {
256               case -1:
257                 // no rotations were found for that frame at all
258                 I_Error ("R_InitSprites: No patches found "
259                          "for %s frame %c", namelist[i], frame+'A');
260                 break;
261                 
262               case 0:
263                 // only the first rotation is needed
264                 break;
265                         
266               case 1:
267                 // must have all 8 frames
268                 for (rotation=0 ; rotation<8 ; rotation++)
269                     if (sprtemp[frame].lump[rotation] == -1)
270                         I_Error ("R_InitSprites: Sprite %s frame %c "
271                                  "is missing rotations",
272                                  namelist[i], frame+'A');
273                 break;
274             }
275         }
276         
277         // allocate space for the frames present and copy sprtemp to it
278         sprites[i].numframes = maxframe;
279         sprites[i].spriteframes = 
280             Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
281         memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
282     }
283
284 }
285
286
287
288
289 //
290 // GAME FUNCTIONS
291 //
292 vissprite_t     vissprites[MAXVISSPRITES];
293 vissprite_t*    vissprite_p;
294 int             newvissprite;
295
296
297
298 //
299 // R_InitSprites
300 // Called at program start.
301 //
302 void R_InitSprites (char** namelist)
303 {
304     int         i;
305         
306     for (i=0 ; i<SCREENWIDTH ; i++)
307     {
308         negonearray[i] = -1;
309     }
310         
311     R_InitSpriteDefs (namelist);
312 }
313
314
315
316 //
317 // R_ClearSprites
318 // Called at frame start.
319 //
320 void R_ClearSprites (void)
321 {
322     vissprite_p = vissprites;
323 }
324
325
326 //
327 // R_NewVisSprite
328 //
329 vissprite_t     overflowsprite;
330
331 vissprite_t* R_NewVisSprite (void)
332 {
333     if (vissprite_p == &vissprites[MAXVISSPRITES])
334         return &overflowsprite;
335     
336     vissprite_p++;
337     return vissprite_p-1;
338 }
339
340
341
342 //
343 // R_DrawMaskedColumn
344 // Used for sprites and masked mid textures.
345 // Masked means: partly transparent, i.e. stored
346 //  in posts/runs of opaque pixels.
347 //
348 short*          mfloorclip;
349 short*          mceilingclip;
350
351 fixed_t         spryscale;
352 fixed_t         sprtopscreen;
353
354 void R_DrawMaskedColumn (column_t* column)
355 {
356     int         topscreen;
357     int         bottomscreen;
358     fixed_t     basetexturemid;
359         
360     basetexturemid = dc_texturemid;
361         
362     for ( ; column->topdelta != 0xff ; ) 
363     {
364         // calculate unclipped screen coordinates
365         //  for post
366         topscreen = sprtopscreen + spryscale*column->topdelta;
367         bottomscreen = topscreen + spryscale*column->length;
368
369         dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
370         dc_yh = (bottomscreen-1)>>FRACBITS;
371                 
372         if (dc_yh >= mfloorclip[dc_x])
373             dc_yh = mfloorclip[dc_x]-1;
374         if (dc_yl <= mceilingclip[dc_x])
375             dc_yl = mceilingclip[dc_x]+1;
376
377         if (dc_yl <= dc_yh)
378         {
379             dc_source = (byte *)column + 3;
380             dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
381             // dc_source = (byte *)column + 3 - column->topdelta;
382
383             // Drawn by either R_DrawColumn
384             //  or (SHADOW) R_DrawFuzzColumn.
385             colfunc (); 
386         }
387         column = (column_t *)(  (byte *)column + column->length + 4);
388     }
389         
390     dc_texturemid = basetexturemid;
391 }
392
393
394
395 //
396 // R_DrawVisSprite
397 //  mfloorclip and mceilingclip should also be set.
398 //
399 void
400 R_DrawVisSprite
401 ( vissprite_t*          vis,
402   int                   /*x1*/,
403   int                   /*x2*/ )
404 {
405     column_t*           column;
406     int                 texturecolumn;
407     fixed_t             frac;
408     patch_t*            patch;
409         
410         
411     patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE);
412
413     dc_colormap = vis->colormap;
414     
415     if (!dc_colormap)
416     {
417         // NULL colormap = shadow draw
418         colfunc = fuzzcolfunc;
419     }
420     else if (vis->mobjflags & MF_TRANSLATION)
421     {
422         colfunc = R_DrawTranslatedColumn;
423         dc_translation = translationtables - 256 +
424             ( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
425     }
426         
427     dc_iscale = abs(vis->xiscale)>>detailshift;
428     dc_texturemid = vis->texturemid;
429     frac = vis->startfrac;
430     spryscale = vis->scale;
431     sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
432         
433     for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale)
434     {
435         texturecolumn = frac>>FRACBITS;
436 #ifdef RANGECHECK
437         if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
438             I_Error ("R_DrawSpriteRange: bad texturecolumn");
439 #endif
440         column = (column_t *) ((byte *)patch +
441                                LONG(patch->columnofs[texturecolumn]));
442         R_DrawMaskedColumn (column);
443     }
444
445     colfunc = basecolfunc;
446 }
447
448
449
450 //
451 // R_ProjectSprite
452 // Generates a vissprite for a thing
453 //  if it might be visible.
454 //
455 void R_ProjectSprite (mobj_t* thing)
456 {
457     fixed_t             tr_x;
458     fixed_t             tr_y;
459     
460     fixed_t             gxt;
461     fixed_t             gyt;
462     
463     fixed_t             tx;
464     fixed_t             tz;
465
466     fixed_t             xscale;
467     
468     int                 x1;
469     int                 x2;
470
471     spritedef_t*        sprdef;
472     spriteframe_t*      sprframe;
473     int                 lump;
474     
475     unsigned            rot;
476     boolean             flip;
477     
478     int                 index;
479
480     vissprite_t*        vis;
481     
482     angle_t             ang;
483     fixed_t             iscale;
484     
485     // transform the origin point
486     tr_x = thing->x - viewx;
487     tr_y = thing->y - viewy;
488         
489     gxt = FixedMul(tr_x,viewcos); 
490     gyt = -FixedMul(tr_y,viewsin);
491     
492     tz = gxt-gyt; 
493
494     // thing is behind view plane?
495     if (tz < MINZ)
496         return;
497     
498     xscale = FixedDiv(projection, tz);
499         
500     gxt = -FixedMul(tr_x,viewsin); 
501     gyt = FixedMul(tr_y,viewcos); 
502     tx = -(gyt+gxt); 
503
504     // too far off the side?
505     if (abs(tx)>(tz<<2))
506         return;
507     
508     // decide which patch to use for sprite relative to player
509 #ifdef RANGECHECK
510     if ((unsigned)thing->sprite >= numsprites)
511         I_Error ("R_ProjectSprite: invalid sprite number %i ",
512                  thing->sprite);
513 #endif
514     sprdef = &sprites[thing->sprite];
515 #ifdef RANGECHECK
516     if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes )
517         I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
518                  thing->sprite, thing->frame);
519 #endif
520     sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
521
522     if (sprframe->rotate)
523     {
524         // choose a different rotation based on player view
525         ang = R_PointToAngle (thing->x, thing->y);
526         rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
527         lump = sprframe->lump[rot];
528         flip = (boolean)sprframe->flip[rot];
529     }
530     else
531     {
532         // use single rotation for all views
533         lump = sprframe->lump[0];
534         flip = (boolean)sprframe->flip[0];
535     }
536     
537     // calculate edges of the shape
538     tx -= spriteoffset[lump];   
539     x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
540
541     // off the right side?
542     if (x1 > viewwidth)
543         return;
544     
545     tx +=  spritewidth[lump];
546     x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
547
548     // off the left side
549     if (x2 < 0)
550         return;
551     
552     // store information in a vissprite
553     vis = R_NewVisSprite ();
554     vis->mobjflags = thing->flags;
555     vis->scale = xscale<<detailshift;
556     vis->gx = thing->x;
557     vis->gy = thing->y;
558     vis->gz = thing->z;
559     vis->gzt = thing->z + spritetopoffset[lump];
560     vis->texturemid = vis->gzt - viewz;
561     vis->x1 = x1 < 0 ? 0 : x1;
562     vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;       
563     iscale = FixedDiv (FRACUNIT, xscale);
564
565     if (flip)
566     {
567         vis->startfrac = spritewidth[lump]-1;
568         vis->xiscale = -iscale;
569     }
570     else
571     {
572         vis->startfrac = 0;
573         vis->xiscale = iscale;
574     }
575
576     if (vis->x1 > x1)
577         vis->startfrac += vis->xiscale*(vis->x1-x1);
578     vis->patch = lump;
579     
580     // get light level
581     if (thing->flags & MF_SHADOW)
582     {
583         // shadow draw
584         vis->colormap = NULL;
585     }
586     else if (fixedcolormap)
587     {
588         // fixed map
589         vis->colormap = fixedcolormap;
590     }
591     else if (thing->frame & FF_FULLBRIGHT)
592     {
593         // full bright
594         vis->colormap = colormaps;
595     }
596     
597     else
598     {
599         // diminished light
600         index = xscale>>(LIGHTSCALESHIFT-detailshift);
601
602         if (index >= MAXLIGHTSCALE) 
603             index = MAXLIGHTSCALE-1;
604
605         vis->colormap = spritelights[index];
606     }   
607 }
608
609
610
611
612 //
613 // R_AddSprites
614 // During BSP traversal, this adds sprites by sector.
615 //
616 void R_AddSprites (sector_t* sec)
617 {
618     mobj_t*             thing;
619     int                 lightnum;
620
621     // BSP is traversed by subsector.
622     // A sector might have been split into several
623     //  subsectors during BSP building.
624     // Thus we check whether its already added.
625     if (sec->validcount == validcount)
626         return;         
627
628     // Well, now it will be done.
629     sec->validcount = validcount;
630         
631     lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight;
632
633     if (lightnum < 0)           
634         spritelights = scalelight[0];
635     else if (lightnum >= LIGHTLEVELS)
636         spritelights = scalelight[LIGHTLEVELS-1];
637     else
638         spritelights = scalelight[lightnum];
639
640     // Handle all things in sector.
641     for (thing = sec->thinglist ; thing ; thing = thing->snext)
642         R_ProjectSprite (thing);
643 }
644
645
646 //
647 // R_DrawPSprite
648 //
649 void R_DrawPSprite (pspdef_t* psp)
650 {
651     fixed_t             tx;
652     int                 x1;
653     int                 x2;
654     spritedef_t*        sprdef;
655     spriteframe_t*      sprframe;
656     int                 lump;
657     boolean             flip;
658     vissprite_t*        vis;
659     vissprite_t         avis;
660     
661     // decide which patch to use
662 #ifdef RANGECHECK
663     if ( (unsigned)psp->state->sprite >= numsprites)
664         I_Error ("R_ProjectSprite: invalid sprite number %i ",
665                  psp->state->sprite);
666 #endif
667     sprdef = &sprites[psp->state->sprite];
668 #ifdef RANGECHECK
669     if ( (psp->state->frame & FF_FRAMEMASK)  >= sprdef->numframes)
670         I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
671                  psp->state->sprite, psp->state->frame);
672 #endif
673     sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
674
675     lump = sprframe->lump[0];
676     flip = (boolean)sprframe->flip[0];
677     
678     // calculate edges of the shape
679     tx = psp->sx-160*FRACUNIT;
680         
681     tx -= spriteoffset[lump];   
682     x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS;
683
684     // off the right side
685     if (x1 > viewwidth)
686         return;         
687
688     tx +=  spritewidth[lump];
689     x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
690
691     // off the left side
692     if (x2 < 0)
693         return;
694     
695     // store information in a vissprite
696     vis = &avis;
697     vis->mobjflags = 0;
698     vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2-(psp->sy-spritetopoffset[lump]);
699     vis->x1 = x1 < 0 ? 0 : x1;
700     vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;       
701     vis->scale = pspritescale<<detailshift;
702     
703     if (flip)
704     {
705         vis->xiscale = -pspriteiscale;
706         vis->startfrac = spritewidth[lump]-1;
707     }
708     else
709     {
710         vis->xiscale = pspriteiscale;
711         vis->startfrac = 0;
712     }
713     
714     if (vis->x1 > x1)
715         vis->startfrac += vis->xiscale*(vis->x1-x1);
716
717     vis->patch = lump;
718
719     if (viewplayer->powers[pw_invisibility] > 4*32
720         || viewplayer->powers[pw_invisibility] & 8)
721     {
722         // shadow draw
723         vis->colormap = NULL;
724     }
725     else if (fixedcolormap)
726     {
727         // fixed color
728         vis->colormap = fixedcolormap;
729     }
730     else if (psp->state->frame & FF_FULLBRIGHT)
731     {
732         // full bright
733         vis->colormap = colormaps;
734     }
735     else
736     {
737         // local light
738         vis->colormap = spritelights[MAXLIGHTSCALE-1];
739     }
740         
741     R_DrawVisSprite (vis, vis->x1, vis->x2);
742 }
743
744
745
746 //
747 // R_DrawPlayerSprites
748 //
749 void R_DrawPlayerSprites (void)
750 {
751     int         i;
752     int         lightnum;
753     pspdef_t*   psp;
754     
755     // get light level
756     lightnum =
757         (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT) 
758         +extralight;
759
760     if (lightnum < 0)           
761         spritelights = scalelight[0];
762     else if (lightnum >= LIGHTLEVELS)
763         spritelights = scalelight[LIGHTLEVELS-1];
764     else
765         spritelights = scalelight[lightnum];
766     
767     // clip to screen bounds
768     mfloorclip = screenheightarray;
769     mceilingclip = negonearray;
770     
771     // add all active psprites
772     for (i=0, psp=viewplayer->psprites;
773          i<NUMPSPRITES;
774          i++,psp++)
775     {
776         if (psp->state)
777             R_DrawPSprite (psp);
778     }
779 }
780
781
782
783
784 //
785 // R_SortVisSprites
786 //
787 vissprite_t     vsprsortedhead;
788
789
790 void R_SortVisSprites (void)
791 {
792     int                 i;
793     int                 count;
794     vissprite_t*        ds;
795     vissprite_t*        best;
796     vissprite_t         unsorted;
797     fixed_t             bestscale;
798
799     count = vissprite_p - vissprites;
800         
801     unsorted.next = unsorted.prev = &unsorted;
802
803     if (!count)
804         return;
805                 
806     for (ds=vissprites ; ds<vissprite_p ; ds++)
807     {
808         ds->next = ds+1;
809         ds->prev = ds-1;
810     }
811     
812     vissprites[0].prev = &unsorted;
813     unsorted.next = &vissprites[0];
814     (vissprite_p-1)->next = &unsorted;
815     unsorted.prev = vissprite_p-1;
816     
817     // pull the vissprites out by scale
818     vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
819     for (best=nil,i=0 ; i<count ; i++)
820     {
821         bestscale = MAXINT;
822         for (ds=unsorted.next ; ds!= &unsorted ; ds=ds->next)
823         {
824             if (ds->scale < bestscale)
825             {
826                 bestscale = ds->scale;
827                 best = ds;
828             }
829         }
830         best->next->prev = best->prev;
831         best->prev->next = best->next;
832         best->next = &vsprsortedhead;
833         best->prev = vsprsortedhead.prev;
834         vsprsortedhead.prev->next = best;
835         vsprsortedhead.prev = best;
836     }
837 }
838
839
840
841 //
842 // R_DrawSprite
843 //
844 void R_DrawSprite (vissprite_t* spr)
845 {
846     drawseg_t*          ds;
847     short               clipbot[SCREENWIDTH];
848     short               cliptop[SCREENWIDTH];
849     int                 x;
850     int                 r1;
851     int                 r2;
852     fixed_t             scale;
853     fixed_t             lowscale;
854     int                 silhouette;
855                 
856     for (x = spr->x1 ; x<=spr->x2 ; x++)
857         clipbot[x] = cliptop[x] = -2;
858     
859     // Scan drawsegs from end to start for obscuring segs.
860     // The first drawseg that has a greater scale
861     //  is the clip seg.
862     for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
863     {
864         // determine if the drawseg obscures the sprite
865         if (ds->x1 > spr->x2
866             || ds->x2 < spr->x1
867             || (!ds->silhouette
868                 && !ds->maskedtexturecol) )
869         {
870             // does not cover sprite
871             continue;
872         }
873                         
874         r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
875         r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
876
877         if (ds->scale1 > ds->scale2)
878         {
879             lowscale = ds->scale2;
880             scale = ds->scale1;
881         }
882         else
883         {
884             lowscale = ds->scale1;
885             scale = ds->scale2;
886         }
887                 
888         if (scale < spr->scale
889             || ( lowscale < spr->scale
890                  && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline) ) )
891         {
892             // masked mid texture?
893             if (ds->maskedtexturecol)   
894                 R_RenderMaskedSegRange (ds, r1, r2);
895             // seg is behind sprite
896             continue;                   
897         }
898
899         
900         // clip this piece of the sprite
901         silhouette = ds->silhouette;
902         
903         if (spr->gz >= ds->bsilheight)
904             silhouette &= ~SIL_BOTTOM;
905
906         if (spr->gzt <= ds->tsilheight)
907             silhouette &= ~SIL_TOP;
908                         
909         if (silhouette == 1)
910         {
911             // bottom sil
912             for (x=r1 ; x<=r2 ; x++)
913                 if (clipbot[x] == -2)
914                     clipbot[x] = ds->sprbottomclip[x];
915         }
916         else if (silhouette == 2)
917         {
918             // top sil
919             for (x=r1 ; x<=r2 ; x++)
920                 if (cliptop[x] == -2)
921                     cliptop[x] = ds->sprtopclip[x];
922         }
923         else if (silhouette == 3)
924         {
925             // both
926             for (x=r1 ; x<=r2 ; x++)
927             {
928                 if (clipbot[x] == -2)
929                     clipbot[x] = ds->sprbottomclip[x];
930                 if (cliptop[x] == -2)
931                     cliptop[x] = ds->sprtopclip[x];
932             }
933         }
934                 
935     }
936     
937     // all clipping has been performed, so draw the sprite
938
939     // check for unclipped columns
940     for (x = spr->x1 ; x<=spr->x2 ; x++)
941     {
942         if (clipbot[x] == -2)           
943             clipbot[x] = viewheight;
944
945         if (cliptop[x] == -2)
946             cliptop[x] = -1;
947     }
948                 
949     mfloorclip = clipbot;
950     mceilingclip = cliptop;
951     R_DrawVisSprite (spr, spr->x1, spr->x2);
952 }
953
954
955
956
957 //
958 // R_DrawMasked
959 //
960 void R_DrawMasked (void)
961 {
962     vissprite_t*        spr;
963     drawseg_t*          ds;
964         
965     R_SortVisSprites ();
966
967     if (vissprite_p > vissprites)
968     {
969         // draw all vissprites back to front
970         for (spr = vsprsortedhead.next ;
971              spr != &vsprsortedhead ;
972              spr=spr->next)
973         {
974             
975             R_DrawSprite (spr);
976         }
977     }
978     
979     // render any remaining masked mid textures
980     for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
981         if (ds->maskedtexturecol)
982             R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
983     
984     // draw the psprites on top of everything
985     //  but does not draw on side views
986     if (!viewangleoffset)               
987         R_DrawPlayerSprites ();
988 }
989
990
991