1 /* Emacs style mode select   -*- C++ -*-
2  *-----------------------------------------------------------------------------
3  *
4  *
5  *  PrBoom: a Doom port merged with LxDoom and LSDLDoom
6  *  based on BOOM, a modified and improved DOOM engine
7  *  Copyright (C) 1999 by
8  *  id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9  *  Copyright (C) 1999-2000 by
10  *  Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11  *  Copyright 2005, 2006 by
12  *  Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13  *
14  *  This program is free software; you can redistribute it and/or
15  *  modify it under the terms of the GNU General Public License
16  *  as published by the Free Software Foundation; either version 2
17  *  of the License, or (at your option) any later version.
18  *
19  *  This program is distributed in the hope that it will be useful,
20  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  *  GNU General Public License for more details.
23  *
24  *  You should have received a copy of the GNU General Public License
25  *  along with this program; if not, write to the Free Software
26  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27  *  02111-1307, USA.
28  *
29  * DESCRIPTION:
30  *  Refresh of things, i.e. objects represented by sprites.
31  *
32  *-----------------------------------------------------------------------------*/
33 
34 #include "doomstat.h"
35 #include "w_wad.h"
36 #include "r_main.h"
37 #include "r_bsp.h"
38 #include "r_segs.h"
39 #include "r_draw.h"
40 #include "r_things.h"
41 #include "r_fps.h"
42 #include "v_video.h"
43 #include "lprintf.h"
44 
45 #define MINZ        (FRACUNIT*4)
46 #define BASEYCENTER 100
47 
48 typedef struct {
49   int x1;
50   int x2;
51   int column;
52   int topclip;
53   int bottomclip;
54 } maskdraw_t;
55 
56 //
57 // Sprite rotation 0 is facing the viewer,
58 //  rotation 1 is one angle turn CLOCKWISE around the axis.
59 // This is not the same as the angle,
60 //  which increases counter clockwise (protractor).
61 // There was a lot of stuff grabbed wrong, so I changed it...
62 //
63 
64 fixed_t pspritescale;
65 fixed_t pspriteiscale;
66 // proff 11/06/98: Added for high-res
67 fixed_t pspriteyscale;
68 
69 // constant arrays
70 //  used for psprite clipping and initializing clipping
71 
72 int negonearray[MAX_SCREENWIDTH];        // killough 2/8/98: // dropoff overflow
73 int screenheightarray[MAX_SCREENWIDTH];  // change to MAX_* // dropoff overflow
74 
75 //
76 // INITIALIZATION FUNCTIONS
77 //
78 
79 // variables used to look up and range check thing_t sprites patches
80 
81 spritedef_t *sprites;
82 int numsprites;
83 
84 #define MAX_SPRITE_FRAMES 29          /* Macroized -- killough 1/25/98 */
85 
86 static spriteframe_t sprtemp[MAX_SPRITE_FRAMES];
87 static int maxframe;
88 
89 //
90 // R_InstallSpriteLump
91 // Local function for R_InitSprites.
92 //
93 
R_InstallSpriteLump(int lump,unsigned frame,unsigned rotation,dbool flipped)94 static void R_InstallSpriteLump(int lump, unsigned frame,
95                                 unsigned rotation, dbool   flipped)
96 {
97    if (frame >= MAX_SPRITE_FRAMES || rotation > 8)
98       I_Error("R_InstallSpriteLump: Bad frame characters in lump %i", lump);
99 
100    if ((int) frame > maxframe)
101       maxframe = frame;
102 
103    if (rotation == 0)
104    {    // the lump should be used for all rotations
105       int r;
106       for (r=0 ; r<8 ; r++)
107          if (sprtemp[frame].lump[r]==-1)
108          {
109             sprtemp[frame].lump[r] = lump - firstspritelump;
110             sprtemp[frame].flip[r] = (uint8_t) flipped;
111             sprtemp[frame].rotate = FALSE; //jff 4/24/98 if any subbed, rotless
112          }
113       return;
114    }
115 
116    // the lump is only used for one rotation
117 
118    if (sprtemp[frame].lump[--rotation] == -1)
119    {
120       sprtemp[frame].lump[rotation] = lump - firstspritelump;
121       sprtemp[frame].flip[rotation] = (uint8_t) flipped;
122       sprtemp[frame].rotate = TRUE; //jff 4/24/98 only change if rot used
123    }
124 }
125 
126 //
127 // R_InitSpriteDefs
128 // Pass a null terminated list of sprite names
129 // (4 chars exactly) to be used.
130 //
131 // Builds the sprite rotation matrixes to account
132 // for horizontally flipped sprites.
133 //
134 // Will report an error if the lumps are inconsistent.
135 // Only called at startup.
136 //
137 // Sprite lump names are 4 characters for the actor,
138 //  a letter for the frame, and a number for the rotation.
139 //
140 // A sprite that is flippable will have an additional
141 //  letter/number appended.
142 //
143 // The rotation character can be 0 to signify no rotations.
144 //
145 // 1/25/98, 1/31/98 killough : Rewritten for performance
146 //
147 // Empirically verified to have excellent hash
148 // properties across standard Doom sprites:
149 
150 #define R_SpriteNameHash(s) ((unsigned)((s)[0]-((s)[1]*3-(s)[3]*2-(s)[2])*2))
151 
R_InitSpriteDefs(const char * const * namelist)152 static void R_InitSpriteDefs(const char * const * namelist)
153 {
154    size_t numentries = lastspritelump-firstspritelump+1;
155    struct { int index, next; } *hash;
156    int i;
157 
158    if (!numentries || !*namelist)
159       return;
160 
161    // count the number of sprite names
162    for (i=0; namelist[i]; i++)
163       ;
164 
165    numsprites = i;
166 
167    sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
168 
169    // Create hash table based on just the first four letters of each sprite
170    // killough 1/31/98
171 
172    hash = malloc(sizeof(*hash)*numentries); // allocate hash table
173 
174    for (i=0; (size_t)i<numentries; i++)             // initialize hash table as empty
175       hash[i].index = -1;
176 
177    for (i=0; (size_t)i<numentries; i++)             // Prepend each sprite to hash chain
178    {                                      // prepend so that later ones win
179       int j = R_SpriteNameHash(lumpinfo[i+firstspritelump].name) % numentries;
180       hash[i].next = hash[j].index;
181       hash[j].index = i;
182    }
183 
184    // scan all the lump names for each of the names,
185    //  noting the highest frame letter.
186 
187    for (i=0 ; i<numsprites ; i++)
188    {
189       const char *spritename = namelist[i];
190       int j = hash[R_SpriteNameHash(spritename) % numentries].index;
191 
192       if (j >= 0)
193       {
194          memset(sprtemp, -1, sizeof(sprtemp));
195          maxframe = -1;
196          do
197          {
198             register lumpinfo_t *lump = lumpinfo + j + firstspritelump;
199 
200             // Fast portable comparison -- killough
201             // (using int pointer cast is nonportable):
202 
203             if (!((lump->name[0] ^ spritename[0]) |
204                      (lump->name[1] ^ spritename[1]) |
205                      (lump->name[2] ^ spritename[2]) |
206                      (lump->name[3] ^ spritename[3])))
207             {
208                R_InstallSpriteLump(j+firstspritelump,
209                      lump->name[4] - 'A',
210                      lump->name[5] - '0',
211                      FALSE);
212                if (lump->name[6])
213                   R_InstallSpriteLump(j+firstspritelump,
214                         lump->name[6] - 'A',
215                         lump->name[7] - '0',
216                         TRUE);
217             }
218          }
219          while ((j = hash[j].next) >= 0);
220 
221          // check the frames that were found for completeness
222          if ((sprites[i].numframes = ++maxframe))  // killough 1/31/98
223          {
224             int frame;
225             for (frame = 0; frame < maxframe; frame++)
226                switch ((int) sprtemp[frame].rotate)
227                {
228                   case -1:
229                      // no rotations were found for that frame at all
230                      I_Error ("R_InitSprites: No patches found "
231                            "for %.8s frame %c", namelist[i], frame+'A');
232                      break;
233 
234                   case 0:
235                      // only the first rotation is needed
236                      break;
237 
238                   case 1:
239                      // must have all 8 frames
240                      {
241                         int rotation;
242                         for (rotation=0 ; rotation<8 ; rotation++)
243                            if (sprtemp[frame].lump[rotation] == -1)
244                               I_Error ("R_InitSprites: Sprite %.8s frame %c "
245                                     "is missing rotations",
246                                     namelist[i], frame+'A');
247                         break;
248                      }
249                }
250             // allocate space for the frames present and copy sprtemp to it
251             sprites[i].spriteframes =
252                Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
253             memcpy (sprites[i].spriteframes, sprtemp,
254                   maxframe*sizeof(spriteframe_t));
255          }
256       }
257    }
258    free(hash);             // free hash table
259 }
260 
261 //
262 // GAME FUNCTIONS
263 //
264 
265 static vissprite_t *vissprites, **vissprite_ptrs;  // killough
266 static size_t num_vissprite, num_vissprite_alloc, num_vissprite_ptrs;
267 
268 //
269 // R_InitSprites
270 // Called at program start.
271 //
272 
R_InitSprites(const char * const * namelist)273 void R_InitSprites(const char * const *namelist)
274 {
275    int i;
276    for (i=0; i<MAX_SCREENWIDTH; i++)    // killough 2/8/98
277       negonearray[i] = -1;
278    R_InitSpriteDefs(namelist);
279 }
280 
281 //
282 // R_ClearSprites
283 // Called at frame start.
284 //
285 
R_ClearSprites(void)286 void R_ClearSprites (void)
287 {
288    num_vissprite = 0;            // killough
289 }
290 
291 //
292 // R_NewVisSprite
293 //
294 
R_NewVisSprite(void)295 static vissprite_t *R_NewVisSprite(void)
296 {
297    if (num_vissprite >= num_vissprite_alloc)             // killough
298    {
299       size_t num_vissprite_alloc_prev = num_vissprite_alloc;
300 
301       num_vissprite_alloc = num_vissprite_alloc ? num_vissprite_alloc*2 : 128;
302       vissprites = realloc(vissprites,num_vissprite_alloc*sizeof(*vissprites));
303 
304       //e6y: set all fields to zero
305       memset(vissprites + num_vissprite_alloc_prev, 0,
306             (num_vissprite_alloc - num_vissprite_alloc_prev)*sizeof(*vissprites));
307    }
308    return vissprites + num_vissprite++;
309 }
310 
311 //
312 // R_DrawMaskedColumn
313 // Used for sprites and masked mid textures.
314 // Masked means: partly transparent, i.e. stored
315 //  in posts/runs of opaque pixels.
316 //
317 
318 int   *mfloorclip;   // dropoff overflow
319 int   *mceilingclip; // dropoff overflow
320 fixed_t spryscale;
321 fixed_t sprtopscreen;
322 
R_DrawMaskedColumn(const rpatch_t * patch,R_DrawColumn_f colfunc,draw_column_vars_t * dcvars,const rcolumn_t * column,const rcolumn_t * prevcolumn,const rcolumn_t * nextcolumn)323 void R_DrawMaskedColumn(
324       const rpatch_t *patch,
325       R_DrawColumn_f colfunc,
326       draw_column_vars_t *dcvars,
327       const rcolumn_t *column,
328       const rcolumn_t *prevcolumn,
329       const rcolumn_t *nextcolumn
330       )
331 {
332   int     i;
333   int     topscreen;
334   int     bottomscreen;
335   fixed_t basetexturemid = dcvars->texturemid;
336 
337   dcvars->texheight = patch->height; // killough 11/98
338   for (i=0; i<column->numPosts; i++) {
339     const rpost_t *post = &column->posts[i];
340 
341     // calculate unclipped screen coordinates for post
342     topscreen = sprtopscreen + spryscale*post->topdelta;
343     bottomscreen = topscreen + spryscale*post->length;
344 
345     dcvars->yl = (topscreen+FRACUNIT-1)>>FRACBITS;
346     dcvars->yh = (bottomscreen-1)>>FRACBITS;
347 
348     if (dcvars->yh >= mfloorclip[dcvars->x])
349       dcvars->yh = mfloorclip[dcvars->x]-1;
350 
351     if (dcvars->yl <= mceilingclip[dcvars->x])
352       dcvars->yl = mceilingclip[dcvars->x]+1;
353 
354     // killough 3/2/98, 3/27/98: Failsafe against overflow/crash:
355     if (dcvars->yl <= dcvars->yh && dcvars->yh < viewheight)
356     {
357       dcvars->source = column->pixels + post->topdelta;
358       dcvars->prevsource = prevcolumn->pixels + post->topdelta;
359       dcvars->nextsource = nextcolumn->pixels + post->topdelta;
360 
361       dcvars->texturemid = basetexturemid - (post->topdelta<<FRACBITS);
362 
363       dcvars->edgeslope = post->slope;
364       // Drawn by either R_DrawColumn
365       //  or (SHADOW) R_DrawFuzzColumn.
366       dcvars->drawingmasked = 1; // POPE
367       colfunc (dcvars);
368       dcvars->drawingmasked = 0; // POPE
369     }
370   }
371   dcvars->texturemid = basetexturemid;
372 }
373 
374 //
375 // R_DrawVisSprite
376 //  mfloorclip and mceilingclip should also be set.
377 //
378 // CPhipps - new wad lump handling, *'s to const*'s
R_DrawVisSprite(vissprite_t * vis,int x1,int x2)379 static void R_DrawVisSprite(vissprite_t *vis, int x1, int x2)
380 {
381   int      texturecolumn;
382   fixed_t  frac;
383   const rpatch_t *patch = R_CachePatchNum(vis->patch+firstspritelump);
384   R_DrawColumn_f colfunc;
385   draw_column_vars_t dcvars;
386   enum draw_filter_type_e filter;
387   enum draw_filter_type_e filterz;
388 
389   R_SetDefaultDrawColumnVars(&dcvars);
390   if (vis->mobjflags & MF_PLAYERSPRITE) {
391     dcvars.edgetype = drawvars.patch_edges;
392     filter = drawvars.filterpatch;
393     filterz = RDRAW_FILTER_POINT;
394   } else {
395     dcvars.edgetype = drawvars.sprite_edges;
396     filter = drawvars.filtersprite;
397     filterz = drawvars.filterz;
398   }
399 
400   dcvars.colormap = vis->colormap;
401   dcvars.nextcolormap = dcvars.colormap; // for filtering -- POPE
402 
403   // killough 4/11/98: rearrange and handle translucent sprites
404   // mixed with translucent/non-translucenct 2s normals
405 
406   if (!dcvars.colormap)   // NULL colormap = shadow draw
407     colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_FUZZ, filter, filterz);    // killough 3/14/98
408   else
409     if (vis->mobjflags & MF_TRANSLATION)
410     {
411       colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLATED, filter, filterz);
412       dcvars.translation = translationtables - 256 +
413         ((vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
414     }
415     else
416       colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, filter, filterz); // killough 3/14/98, 4/11/98
417 
418   // proff 11/06/98: Changed for high-res
419   dcvars.iscale = FixedDiv (FRACUNIT, vis->scale);
420   dcvars.texturemid = vis->texturemid;
421   frac = vis->startfrac;
422   if (filter == RDRAW_FILTER_LINEAR)
423     frac -= (FRACUNIT>>1);
424   spryscale = vis->scale;
425   sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid,spryscale);
426 
427   // make sure the player weapon is in a static position on the screen
428   if(vis->mobjflags & MF_PLAYERSPRITE)
429   {
430     dcvars.texturemid += FixedMul(((centery - viewheight/2)<<FRACBITS), dcvars.iscale);
431     sprtopscreen += (viewheight/2 - centery)<<FRACBITS;
432   }
433 
434   for (dcvars.x=vis->x1 ; dcvars.x<=vis->x2 ; dcvars.x++, frac += vis->xiscale)
435   {
436     texturecolumn = frac>>FRACBITS;
437     dcvars.texu = frac;
438 
439     R_DrawMaskedColumn(
440       patch,
441       colfunc,
442       &dcvars,
443       R_GetPatchColumnClamped(patch, texturecolumn),
444       R_GetPatchColumnClamped(patch, texturecolumn-1),
445       R_GetPatchColumnClamped(patch, texturecolumn+1)
446     );
447   }
448   R_UnlockPatchNum(vis->patch+firstspritelump); // cph - release lump
449 }
450 
451 //
452 // R_ProjectSprite
453 // Generates a vissprite for a thing if it might be visible.
454 //
455 
R_ProjectSprite(mobj_t * thing,int lightlevel)456 static void R_ProjectSprite (mobj_t* thing, int lightlevel)
457 {
458    fixed_t   gzt;               // killough 3/27/98
459    fixed_t   tx;
460    fixed_t   xscale;
461    int       x1;
462    int       x2;
463    spritedef_t   *sprdef;
464    spriteframe_t *sprframe;
465    int       lump;
466    dbool     flip;
467    vissprite_t *vis;
468    fixed_t   iscale;
469    int heightsec;      // killough 3/27/98
470 
471    // transform the origin point
472    fixed_t tr_x, tr_y;
473    fixed_t fx, fy, fz;
474    fixed_t gxt, gyt;
475    fixed_t tz;
476    int width;
477 
478    if (movement_smooth)
479    {
480       fx = thing->PrevX + FixedMul (tic_vars.frac, thing->x - thing->PrevX);
481       fy = thing->PrevY + FixedMul (tic_vars.frac, thing->y - thing->PrevY);
482       fz = thing->PrevZ + FixedMul (tic_vars.frac, thing->z - thing->PrevZ);
483    }
484    else
485    {
486       fx = thing->x;
487       fy = thing->y;
488       fz = thing->z;
489    }
490    tr_x = fx - viewx;
491    tr_y = fy - viewy;
492 
493    gxt = FixedMul(tr_x,viewcos);
494    gyt = -FixedMul(tr_y,viewsin);
495 
496    tz = gxt-gyt;
497 
498    // thing is behind view plane?
499    if (tz < MINZ)
500       return;
501 
502    xscale = FixedDiv(projection, tz);
503 
504    gxt = -FixedMul(tr_x,viewsin);
505    gyt = FixedMul(tr_y,viewcos);
506    tx = -(gyt+gxt);
507 
508    // too far off the side?
509    if (D_abs(tx)>(tz<<2))
510       return;
511 
512    // Do not attempt to render special TNT1 invisible sprite
513    if (thing->sprite == SPR_TNT1) return;
514 
515    // decide which patch to use for sprite relative to player
516    sprdef = &sprites[thing->sprite];
517 
518    if (!sprdef->numframes)
519    {
520       const spritenum_t fallback = states[S_NULL].sprite; // Use the sprite from the dummy state
521       I_Error ("R_ProjectSprite: Using fallback '%s' for sprite '%s' (%i) with missing spriteframes!",
522                sprnames[fallback], sprnames[thing->sprite], thing->sprite);
523       *sprdef = sprites[fallback];
524       if (!sprdef->spriteframes)
525       {
526          I_Error ("R_ProjectSprite: fallback missing! sprite won't be rendered");
527          *sprdef = sprites[SPR_TNT1];
528          return;
529       }
530    }
531 
532    sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
533 
534    if (sprframe->rotate)
535    {
536       // choose a different rotation based on player view
537       angle_t ang = R_PointToAngle(fx, fy);
538       unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
539       lump = sprframe->lump[rot];
540       flip = (dbool) sprframe->flip[rot];
541    }
542    else
543    {
544       // use single rotation for all views
545       lump = sprframe->lump[0];
546       flip = (dbool) sprframe->flip[0];
547    }
548 
549    {
550       const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump);
551 
552       /* calculate edges of the shape
553        * cph 2003/08/1 - fraggle points out that this offset must be flipped
554        * if the sprite is flipped; e.g. FreeDoom imp is messed up by this. */
555       if (flip) {
556          tx -= (patch->width - patch->leftoffset) << FRACBITS;
557       } else {
558          tx -= patch->leftoffset << FRACBITS;
559       }
560       x1 = (centerxfrac + FixedMul(tx,xscale)) >> FRACBITS;
561 
562       tx += patch->width<<FRACBITS;
563       x2 = ((centerxfrac + FixedMul (tx,xscale) ) >> FRACBITS) - 1;
564 
565       gzt = fz + (patch->topoffset << FRACBITS);
566       width = patch->width;
567       R_UnlockPatchNum(lump+firstspritelump);
568    }
569 
570    // off the side?
571    if (x1 > viewwidth || x2 < 0)
572       return;
573 
574    // killough 4/9/98: clip things which are out of view due to height
575    // e6y: fix of hanging decoration disappearing in Batman Doom MAP02
576    // centeryfrac -> viewheightfrac
577    if (fz  > viewz + FixedDiv(viewheightfrac, xscale) ||
578          gzt < viewz - FixedDiv(viewheightfrac-viewheight, xscale))
579       return;
580 
581    // killough 3/27/98: exclude things totally separated
582    // from the viewer, by either water or fake ceilings
583    // killough 4/11/98: improve sprite clipping for underwater/fake ceilings
584 
585    heightsec = thing->subsector->sector->heightsec;
586 
587    if (heightsec != -1)   // only clip things which are in special sectors
588    {
589       int phs = viewplayer->mo->subsector->sector->heightsec;
590       if (phs != -1 && viewz < sectors[phs].floorheight ?
591             fz >= sectors[heightsec].floorheight :
592             gzt < sectors[heightsec].floorheight)
593          return;
594       if (phs != -1 && viewz > sectors[phs].ceilingheight ?
595             gzt < sectors[heightsec].ceilingheight &&
596             viewz >= sectors[heightsec].ceilingheight :
597             fz >= sectors[heightsec].ceilingheight)
598          return;
599    }
600 
601    // store information in a vissprite
602    vis = R_NewVisSprite ();
603 
604    // killough 3/27/98: save sector for special clipping later
605    vis->heightsec = heightsec;
606 
607    vis->mobjflags = thing->flags;
608    // proff 11/06/98: Changed for high-res
609    vis->scale = FixedDiv(projectiony, tz);
610    vis->gx = fx;
611    vis->gy = fy;
612    vis->gz = fz;
613    vis->gzt = gzt;                          // killough 3/27/98
614    vis->texturemid = vis->gzt - viewz;
615    vis->x1 = x1 < 0 ? 0 : x1;
616    vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
617    iscale = FixedDiv (FRACUNIT, xscale);
618 
619    if (flip)
620    {
621       vis->startfrac = (width<<FRACBITS)-1;
622       vis->xiscale = -iscale;
623    }
624    else
625    {
626       vis->startfrac = 0;
627       vis->xiscale = iscale;
628    }
629 
630    if (vis->x1 > x1)
631       vis->startfrac += vis->xiscale*(vis->x1-x1);
632    vis->patch = lump;
633 
634    // get light level
635    if (thing->flags & MF_SHADOW)
636       vis->colormap = NULL;             // shadow draw
637    else if (fixedcolormap)
638       vis->colormap = fixedcolormap;      // fixed map
639    else if (thing->frame & FF_FULLBRIGHT)
640       vis->colormap = fullcolormap;     // full bright  // killough 3/20/98
641    else
642    {      // diminished light
643       vis->colormap = R_ColourMap(lightlevel,xscale);
644    }
645 }
646 
647 //
648 // R_AddSprites
649 // During BSP traversal, this adds sprites by sector.
650 //
651 // killough 9/18/98: add lightlevel as parameter, fixing underwater lighting
R_AddSprites(subsector_t * subsec,int lightlevel)652 void R_AddSprites(subsector_t* subsec, int lightlevel)
653 {
654    sector_t* sec=subsec->sector;
655    mobj_t *thing;
656 
657    // BSP is traversed by subsector.
658    // A sector might have been split into several
659    //  subsectors during BSP building.
660    // Thus we check whether its already added.
661 
662    if (sec->validcount == validcount)
663       return;
664 
665    // Well, now it will be done.
666    sec->validcount = validcount;
667 
668    // Handle all things in sector.
669 
670    for (thing = sec->thinglist; thing; thing = thing->snext)
671       R_ProjectSprite(thing, lightlevel);
672 }
673 
674 //
675 // R_DrawPSprite
676 //
677 
R_DrawPSprite(pspdef_t * psp,int lightlevel)678 static void R_DrawPSprite (pspdef_t *psp, int lightlevel)
679 {
680    int           x1, x2;
681    spritedef_t   *sprdef;
682    spriteframe_t *sprframe;
683    int           lump;
684    dbool         flip;
685    vissprite_t   *vis;
686    vissprite_t   avis;
687    int           width;
688    fixed_t       topoffset;
689 
690    // decide which patch to use
691 
692    sprdef = &sprites[psp->state->sprite];
693 
694    sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
695 
696    lump = sprframe->lump[0];
697    flip = (dbool) sprframe->flip[0];
698 
699    {
700       const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump);
701       // calculate edges of the shape
702       fixed_t       tx;
703       tx = psp->sx-160*FRACUNIT;
704 
705       tx -= patch->leftoffset<<FRACBITS;
706       x1 = (centerxfrac + FixedMul (tx,pspritescale))>>FRACBITS;
707 
708       tx += patch->width<<FRACBITS;
709       x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
710 
711       width = patch->width;
712       topoffset = patch->topoffset<<FRACBITS;
713       R_UnlockPatchNum(lump+firstspritelump);
714    }
715 
716    // off the side
717    if (x2 < 0 || x1 > viewwidth)
718       return;
719 
720    // store information in a vissprite
721    vis = &avis;
722    vis->mobjflags = MF_PLAYERSPRITE;
723    // killough 12/98: fix psprite positioning problem
724    vis->texturemid = (BASEYCENTER<<FRACBITS) /* +  FRACUNIT/2 */ -
725       (psp->sy-topoffset);
726    vis->x1 = x1 < 0 ? 0 : x1;
727    vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
728    // proff 11/06/98: Added for high-res
729    vis->scale = pspriteyscale;
730 
731    if (flip)
732    {
733       vis->xiscale = -pspriteiscale;
734       vis->startfrac = (width<<FRACBITS)-1;
735    }
736    else
737    {
738       vis->xiscale = pspriteiscale;
739       vis->startfrac = 0;
740    }
741 
742    if (vis->x1 > x1)
743       vis->startfrac += vis->xiscale*(vis->x1-x1);
744 
745    vis->patch = lump;
746 
747    if (viewplayer->powers[pw_invisibility] > 4*32
748          || viewplayer->powers[pw_invisibility] & 8)
749       vis->colormap = NULL;                    // shadow draw
750    else if (fixedcolormap)
751       vis->colormap = fixedcolormap;           // fixed color
752    else if (psp->state->frame & FF_FULLBRIGHT)
753       vis->colormap = fullcolormap;            // full bright // killough 3/20/98
754    else
755       // add a fudge factor to better match the original game
756       vis->colormap = R_ColourMap(lightlevel,
757             FixedMul(pspritescale, 0x2b000));  // local light
758 
759    // proff 11/99: don't use software stuff in OpenGL
760    R_DrawVisSprite(vis, vis->x1, vis->x2);
761 }
762 
763 //
764 // R_DrawPlayerSprites
765 //
766 
R_DrawPlayerSprites(void)767 void R_DrawPlayerSprites(void)
768 {
769    int i, lightlevel = viewplayer->mo->subsector->sector->lightlevel;
770    pspdef_t *psp;
771 
772    // clip to screen bounds
773    mfloorclip = screenheightarray;
774    mceilingclip = negonearray;
775 
776    // add all active psprites
777    for (i=0, psp=viewplayer->psprites; i<NUMPSPRITES; i++,psp++)
778       if (psp->state)
779          R_DrawPSprite (psp, lightlevel);
780 }
781 
782 //
783 // R_SortVisSprites
784 //
785 // Rewritten by Lee Killough to avoid using unnecessary
786 // linked lists, and to use faster sorting algorithm.
787 //
788 
789 // killough 9/2/98: merge sort
790 
msort(vissprite_t ** s,vissprite_t ** t,int n)791 static void msort(vissprite_t **s, vissprite_t **t, int n)
792 {
793    if (n >= 16)
794    {
795       int n1 = n/2, n2 = n - n1;
796       vissprite_t **s1 = s, **s2 = s + n1, **d = t;
797 
798       msort(s1, t, n1);
799       msort(s2, t, n2);
800 
801       while ((*s1)->scale > (*s2)->scale ?
802             (*d++ = *s1++, --n1) : (*d++ = *s2++, --n2));
803 
804       if (n2)
805          memcpy(d, s2, n2 * sizeof(void *));
806       else
807          memcpy(d, s1, n1 * sizeof(void *));
808 
809       memcpy(s, t, n * sizeof(void *));
810    }
811    else
812    {
813       int i;
814       for (i = 1; i < n; i++)
815       {
816          vissprite_t *temp = s[i];
817          if (s[i-1]->scale < temp->scale)
818          {
819             int j = i;
820             while ((s[j] = s[j-1])->scale < temp->scale && --j);
821             s[j] = temp;
822          }
823       }
824    }
825 }
826 
R_SortVisSprites(void)827 void R_SortVisSprites (void)
828 {
829    if (num_vissprite)
830    {
831       int i = num_vissprite;
832 
833       // If we need to allocate more pointers for the vissprites,
834       // allocate as many as were allocated for sprites -- killough
835       // killough 9/22/98: allocate twice as many
836 
837       if (num_vissprite_ptrs < num_vissprite*2)
838       {
839          free(vissprite_ptrs);  // better than realloc -- no preserving needed
840          vissprite_ptrs = malloc((num_vissprite_ptrs = num_vissprite_alloc*2)
841                * sizeof *vissprite_ptrs);
842       }
843 
844       while (--i>=0)
845          vissprite_ptrs[i] = vissprites+i;
846 
847       // killough 9/22/98: replace qsort with merge sort, since the keys
848       // are roughly in order to begin with, due to BSP rendering.
849 
850       msort(vissprite_ptrs, vissprite_ptrs + num_vissprite, num_vissprite);
851    }
852 }
853 
854 //
855 // R_DrawSprite
856 //
857 
R_DrawSprite(vissprite_t * spr)858 static void R_DrawSprite (vissprite_t* spr)
859 {
860    drawseg_t *ds;
861    int     clipbot[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow
862    int     cliptop[MAX_SCREENWIDTH]; // change to MAX_*  // dropoff overflow
863    int     x;
864    int     r1;
865    int     r2;
866    fixed_t scale;
867    fixed_t lowscale;
868 
869    for (x = spr->x1 ; x<=spr->x2 ; x++)
870       clipbot[x] = cliptop[x] = -2;
871 
872    // Scan drawsegs from end to start for obscuring segs.
873    // The first drawseg that has a greater scale is the clip seg.
874 
875    // Modified by Lee Killough:
876    // (pointer check was originally nonportable
877    // and buggy, by going past LEFT end of array):
878 
879    //    for (ds=ds_p-1 ; ds >= drawsegs ; ds--)    old buggy code
880 
881    for (ds=ds_p ; ds-- > drawsegs ; )  // new -- killough
882    {      // determine if the drawseg obscures the sprite
883       if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
884             (!ds->silhouette && !ds->maskedtexturecol))
885          continue;      // does not cover sprite
886 
887       r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
888       r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
889 
890       if (ds->scale1 > ds->scale2)
891       {
892          lowscale = ds->scale2;
893          scale = ds->scale1;
894       }
895       else
896       {
897          lowscale = ds->scale1;
898          scale = ds->scale2;
899       }
900 
901       if (scale < spr->scale || (lowscale < spr->scale &&
902                !R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
903       {
904          if (ds->maskedtexturecol)       // masked mid texture?
905             R_RenderMaskedSegRange(ds, r1, r2);
906          continue;               // seg is behind sprite
907       }
908 
909       // clip this piece of the sprite
910       // killough 3/27/98: optimized and made much shorter
911 
912       if (ds->silhouette&SIL_BOTTOM && spr->gz < ds->bsilheight) //bottom sil
913          for (x=r1 ; x<=r2 ; x++)
914             if (clipbot[x] == -2)
915                clipbot[x] = ds->sprbottomclip[x];
916 
917       if (ds->silhouette&SIL_TOP && spr->gzt > ds->tsilheight)   // top sil
918          for (x=r1 ; x<=r2 ; x++)
919             if (cliptop[x] == -2)
920                cliptop[x] = ds->sprtopclip[x];
921    }
922 
923    // killough 3/27/98:
924    // Clip the sprite against deep water and/or fake ceilings.
925    // killough 4/9/98: optimize by adding mh
926    // killough 4/11/98: improve sprite clipping for underwater/fake ceilings
927    // killough 11/98: fix disappearing sprites
928 
929    if (spr->heightsec != -1)  // only things in specially marked sectors
930    {
931       fixed_t h,mh;
932       int phs = viewplayer->mo->subsector->sector->heightsec;
933       if ((mh = sectors[spr->heightsec].floorheight) > spr->gz &&
934             (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0 &&
935             (h >>= FRACBITS) < viewheight) {
936          if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight))
937          {                          // clip bottom
938             for (x=spr->x1 ; x<=spr->x2 ; x++)
939                if (clipbot[x] == -2 || h < clipbot[x])
940                   clipbot[x] = h;
941          }
942          else                        // clip top
943             if (phs != -1 && viewz <= sectors[phs].floorheight) // killough 11/98
944                for (x=spr->x1 ; x<=spr->x2 ; x++)
945                   if (cliptop[x] == -2 || h > cliptop[x])
946                      cliptop[x] = h;
947       }
948 
949       if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt &&
950             (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 &&
951             (h >>= FRACBITS) < viewheight) {
952          if (phs != -1 && viewz >= sectors[phs].ceilingheight)
953          {                         // clip bottom
954             for (x=spr->x1 ; x<=spr->x2 ; x++)
955                if (clipbot[x] == -2 || h < clipbot[x])
956                   clipbot[x] = h;
957          }
958          else                       // clip top
959             for (x=spr->x1 ; x<=spr->x2 ; x++)
960                if (cliptop[x] == -2 || h > cliptop[x])
961                   cliptop[x] = h;
962       }
963    }
964    // killough 3/27/98: end special clipping for deep water / fake ceilings
965 
966    // all clipping has been performed, so draw the sprite
967    // check for unclipped columns
968 
969    for (x = spr->x1 ; x<=spr->x2 ; x++) {
970       if (clipbot[x] == -2)
971          clipbot[x] = viewheight;
972 
973       if (cliptop[x] == -2)
974          cliptop[x] = -1;
975    }
976 
977    mfloorclip = clipbot;
978    mceilingclip = cliptop;
979    R_DrawVisSprite (spr, spr->x1, spr->x2);
980 }
981 
982 //
983 // R_DrawMasked
984 //
985 
R_DrawMasked(void)986 void R_DrawMasked(void)
987 {
988    int i;
989    drawseg_t *ds;
990 
991    R_SortVisSprites();
992 
993    // draw all vissprites back to front
994 
995    rendered_vissprites = num_vissprite;
996    for (i = num_vissprite ;--i>=0; )
997       R_DrawSprite(vissprite_ptrs[i]);         // killough
998 
999    // render any remaining masked mid textures
1000 
1001    // Modified by Lee Killough:
1002    // (pointer check was originally nonportable
1003    // and buggy, by going past LEFT end of array):
1004 
1005    //    for (ds=ds_p-1 ; ds >= drawsegs ; ds--)    old buggy code
1006 
1007    for (ds=ds_p ; ds-- > drawsegs ; )  // new -- killough
1008       if (ds->maskedtexturecol)
1009          R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
1010 
1011    // draw the psprites on top of everything
1012    //  but does not draw on side views
1013    if (!viewangleoffset && !viewpitchoffset)
1014       R_DrawPlayerSprites ();
1015 }
1016