1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: r_things.c 1564 2020-12-19 06:21:07Z wesleyjohnson $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Portions Copyright (C) 1998-2016 by DooM Legacy Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 //
20 // $Log: r_things.c,v $
21 // Revision 1.44  2002/11/12 00:06:05  ssntails
22 // Support for translated translucent columns in software mode.
23 //
24 // Revision 1.43  2002/06/30 21:37:48  hurdler
25 // Ready for 1.32 beta 5 release
26 //
27 // Revision 1.42  2001/12/31 16:56:39  metzgermeister
28 // see Dec 31 log
29 //
30 // Revision 1.41  2001/08/12 15:21:04  bpereira
31 // see my log
32 //
33 // Revision 1.40  2001/08/06 23:57:09  stroggonmeth
34 // Removed portal code, improved 3D floors in hardware mode.
35 //
36 // Revision 1.39  2001/06/16 08:07:55  bpereira
37 // Revision 1.38  2001/06/10 21:16:01  bpereira
38 //
39 // Revision 1.37  2001/05/30 18:15:21  stroggonmeth
40 // Small crashing bug fix...
41 //
42 // Revision 1.36  2001/05/30 04:00:52  stroggonmeth
43 // Fixed crashing bugs in software with 3D floors.
44 //
45 // Revision 1.35  2001/05/22 14:22:23  hurdler
46 // show 3d-floors bug + hack for filesearch with vc++
47 //
48 // Revision 1.34  2001/05/07 20:27:16  stroggonmeth
49 // Revision 1.33  2001/04/27 13:32:14  bpereira
50 //
51 // Revision 1.32  2001/04/17 21:12:08  stroggonmeth
52 // Little commit. Re-enables colormaps for trans columns in C and fixes some sprite bugs.
53 //
54 // Revision 1.31  2001/03/30 17:12:51  bpereira
55 //
56 // Revision 1.30  2001/03/21 18:24:56  stroggonmeth
57 // Misc changes and fixes. Code cleanup
58 //
59 // Revision 1.29  2001/03/13 22:14:20  stroggonmeth
60 // Long time no commit. 3D floors, FraggleScript, portals, ect.
61 //
62 // Revision 1.28  2001/02/24 13:35:21  bpereira
63 //
64 // Revision 1.27  2001/01/25 22:15:44  bpereira
65 // added heretic support
66 //
67 // Revision 1.26  2000/11/21 21:13:18  stroggonmeth
68 // Optimised 3D floors and fixed crashing bug in high resolutions.
69 //
70 // Revision 1.25  2000/11/12 14:15:46  hurdler
71 //
72 // Revision 1.24  2000/11/09 17:56:20  stroggonmeth
73 // Hopefully fixed a few bugs and did a few optimizations.
74 //
75 // Revision 1.23  2000/11/03 02:37:36  stroggonmeth
76 //
77 // Revision 1.22  2000/11/02 17:50:10  stroggonmeth
78 // Big 3Dfloors & FraggleScript commit!!
79 //
80 // Revision 1.21  2000/10/04 16:19:24  hurdler
81 // Change all those "3dfx names" to more appropriate names
82 //
83 // Revision 1.20  2000/10/02 18:25:45  bpereira
84 // Revision 1.19  2000/10/01 10:18:19  bpereira
85 // Revision 1.18  2000/09/30 16:33:08  metzgermeister
86 // Revision 1.17  2000/09/28 20:57:18  bpereira
87 // Revision 1.16  2000/09/21 16:45:08  bpereira
88 // Revision 1.15  2000/08/31 14:30:56  bpereira
89 //
90 // Revision 1.14  2000/08/11 21:37:17  hurdler
91 // fix win32 compilation problem
92 //
93 // Revision 1.13  2000/08/11 19:10:13  metzgermeister
94 // Revision 1.12  2000/04/30 10:30:10  bpereira
95 // Revision 1.11  2000/04/24 20:24:38  bpereira
96 // Revision 1.10  2000/04/20 21:47:24  stroggonmeth
97 // Revision 1.9  2000/04/18 17:39:40  stroggonmeth
98 //
99 // Revision 1.8  2000/04/11 19:07:25  stroggonmeth
100 // Finished my logs, fixed a crashing bug.
101 //
102 // Revision 1.7  2000/04/09 02:30:57  stroggonmeth
103 // Fixed missing sprite def
104 //
105 // Revision 1.6  2000/04/08 17:29:25  stroggonmeth
106 //
107 // Revision 1.5  2000/04/06 21:06:20  stroggonmeth
108 // Optimized extra_colormap code...
109 // Added #ifdefs for older water code.
110 //
111 // Revision 1.4  2000/04/04 19:28:43  stroggonmeth
112 // Global colormaps working. Added a new linedef type 272.
113 //
114 // Revision 1.3  2000/04/04 00:32:48  stroggonmeth
115 // Initial Boom compatability plus few misc changes all around.
116 //
117 // Revision 1.2  2000/02/27 00:42:11  hurdler
118 // Revision 1.1.1.1  2000/02/22 20:32:32  hurdler
119 // Initial import into CVS (v1.29 pr3)
120 //
121 //
122 // DESCRIPTION:
123 //      Refresh of things, i.e. objects represented by sprites.
124 //
125 //-----------------------------------------------------------------------------
126 
127 
128 #include "doomincl.h"
129 #include "console.h"
130 #include "g_game.h"
131 #include "r_local.h"
132 #include "sounds.h"             //skin sounds
133 #include "st_stuff.h"
134 #include "w_wad.h"
135 #include "z_zone.h"
136 #include "p_local.h"
137   // spr_light_t
138 #include "v_video.h"
139   // pLocalPalette
140 
141 #include "i_video.h"            //rendermode
142 #include "m_swap.h"
143 #include "m_random.h"
144 
145 
146 
147 static void R_Init_Skins (void);
148 
149 #define MINZ                  (FRACUNIT*4)
150 #define BASEYCENTER           (BASEVIDHEIGHT/2)
151 
152 // put this in transmap of visprite to draw a shade
153 #define VIS_SMOKESHADE        ((void*)-1)
154 
155 
156 typedef struct
157 {
158     int         x1;
159     int         x2;
160 
161     int         column;
162     int         topclip;
163     int         bottomclip;
164 
165 } maskdraw_t;
166 
167 
168 // SoM: A drawnode is something that points to a 3D floor, 3D side or masked
169 // middle texture. This is used for sorting with sprites.
170 typedef struct drawnode_s
171 {
172   visplane_t*   plane;
173   drawseg_t*    seg;
174   drawseg_t*    thickseg;
175   ffloor_t*     ffloor;
176   vissprite_t*  sprite;
177 
178   struct drawnode_s* next;
179   struct drawnode_s* prev;
180 } drawnode_t;
181 
182 
183 //
184 // Sprite rotation 0 is facing the viewer,
185 //  rotation 1 is one angle turn CLOCKWISE around the axis.
186 // This is not the same as the angle,
187 //  which increases counter clockwise (protractor).
188 // There was a lot of stuff grabbed wrong, so I changed it...
189 //
190 fixed_t         pspritescale;
191 fixed_t         pspriteyscale;  //added:02-02-98:aspect ratio for psprites
192 fixed_t         pspriteiscale;
193 
194 lighttable_t**  spritelights;	// selected scalelight for the sprite draw
195 
196 // constant arrays
197 //  used for sprite and psprite clipping
198 //  Set to last pixel row inside the drawable screen bounds.
199 //  This makes limit tests easier, do not need to do +1 or -1;
200 short           clip_screen_top_min[MAXVIDWIDTH];
201 short           clip_screen_bot_max[MAXVIDWIDTH];
202 
203 
204 //
205 // INITIALIZATION FUNCTIONS
206 //
207 
208 // variables used to look up
209 //  and range check thing_t sprites patches
210 spritedef_t*    sprites;
211 int             numsprites;
212 
213 static char          * spritename;
214 
215 // spritetmp
216 #define MAX_FRAMES   29
217 static spriteframe_t   sprfrm[MAX_FRAMES];
218 static int             maxframe;
219 
220 #ifdef ROT16
221 #define  NUM_SPRITETMP_ROT   16
222 #else
223 #define  NUM_SPRITETMP_ROT   8
224 #endif
225 static sprite_frot_t   sprfrot[MAX_FRAMES * NUM_SPRITETMP_ROT];
226 
227 
228 // ==========================================================================
229 //
230 //  New sprite loading routines for Legacy : support sprites in pwad,
231 //  dehacked sprite renaming, replacing not all frames of an existing
232 //  sprite, add sprites at run-time, add wads at run-time.
233 //
234 // ==========================================================================
235 
236 
get_spriteframe(const spritedef_t * spritedef,int frame_num)237 spriteframe_t *  get_spriteframe( const spritedef_t * spritedef, int frame_num )
238 {
239    return & spritedef->spriteframe[ frame_num ];
240 }
241 
get_framerotation(const spritedef_t * spritedef,int frame_num,byte rotation)242 sprite_frot_t *  get_framerotation( const spritedef_t * spritedef,
243                                     int frame_num, byte rotation )
244 {
245    return & spritedef->framerotation[ (frame_num * spritedef->frame_rot) + rotation ];
246 }
247 
248 const byte srp_to_num_rot[4] = { 0, 1, 8, 16 };
249 
250 
251 // Convert sprfrot formats.
252 
253 // The pattern of named rotations to draw rotations.
254 // Index rotation_char order.
255 static const byte rotation_char_to_draw[16] =
256 { 0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13, 15 };
257 
258 static
transfer_to_spritetmp(const spritedef_t * spritedef)259 void  transfer_to_spritetmp( const spritedef_t * spritedef )
260 {
261     int   src_frames =  spritedef->numframes;
262     byte  src_frame_rot = spritedef->frame_rot;
263     spriteframe_t * fmv, * fmp, * fmp_end;
264     sprite_frot_t * rtv, * rtv_nxt, * rtp, * rtp_nxt;
265     byte r, srp;
266 
267     // From
268     fmv = spritedef->spriteframe;
269     rtv = spritedef->framerotation;
270     // To
271     fmp = & sprfrm[0];
272     fmp_end = & sprfrm[src_frames];
273     rtp = & sprfrot[0];
274 
275     // Temp frame size is at the max (8 or 16).
276     for( ; fmp < fmp_end; fmp++, fmv++ )
277     {
278         // Index the next frame first.
279         rtv_nxt = rtv + src_frame_rot;
280         rtp_nxt = rtp + NUM_SPRITETMP_ROT;
281         // Adapt the rotation pattern to fill the temp array.
282         srp = fmv->rotation_pattern;
283         fmp->rotation_pattern = srp;
284         switch( srp )
285         {
286          case SRP_1:
287             // Duplicate into all rotations so later PWAD can alter it properly.
288             for( r=0; r<NUM_SPRITETMP_ROT; r++ )
289             {
290                 memcpy( rtp, rtv, sizeof(sprite_frot_t) );
291                 rtp++;
292             }
293             break;
294 
295          case SRP_8:
296             // Copy 8 rotations.
297             memcpy( rtp, rtv, sizeof(sprite_frot_t) * 8 );
298             break;
299 
300 #ifdef ROT16
301          case SRP_16:
302             // Copy 16 rotation draw order into rotation_char order.
303             for( r=0; r<16; r++ )
304             {
305                 int rd = rotation_char_to_draw[r];
306                 memcpy( &rtp[r], &rtv[rd], sizeof(sprite_frot_t) );
307             }
308             break;
309 #endif
310          default:
311             break;
312         }
313         rtv = rtv_nxt;
314         rtp = rtp_nxt;
315     }
316 }
317 
318 static
transfer_from_spritetmp(spritedef_t * spritedef,const byte dst_srp,const byte dst_frame_rot)319 void  transfer_from_spritetmp( spritedef_t * spritedef,
320                                const byte dst_srp, const byte dst_frame_rot )
321 {
322     int   dst_frames =  spritedef->numframes;
323     spriteframe_t * fmv, * fmp, * fmp_end;
324     sprite_frot_t * rtv, * rtv_nxt, * rtp, * rtp_nxt;
325     byte srp;
326 #ifdef ROT16
327     byte r;
328 #endif
329 
330     // From spritetmp
331     fmp = & sprfrm[0];
332     fmp_end = & sprfrm[dst_frames];
333     rtp = & sprfrot[0];
334     // To
335     fmv = spritedef->spriteframe;
336     rtv = spritedef->framerotation;
337 
338     for( ; fmp < fmp_end; fmp++, fmv++ )
339     {
340         rtv_nxt = rtv + dst_frame_rot;
341         rtp_nxt = rtp + NUM_SPRITETMP_ROT;
342         srp = fmp->rotation_pattern;
343         fmv->rotation_pattern = srp;
344         switch( srp )
345         {
346          case SRP_1:
347             // copy 1 rotations
348             memcpy( rtv, rtp, sizeof(sprite_frot_t) );
349             break;
350 
351          case SRP_8:
352             // copy 8 rotations
353             memcpy( rtv, rtp, sizeof(sprite_frot_t) * 8 );
354             break;
355 
356 #ifdef ROT16
357          case SRP_16:
358             // copy 16 rotation draw order into rotation_char order.
359             for( r=0; r<16; r++ )
360             {
361                 int rd = rotation_char_to_draw[r];
362                 memcpy( &rtv[rd], &rtp[r], sizeof(sprite_frot_t) );
363             }
364             break;
365 #endif
366          default:
367            break;
368         }
369         rtv = rtv_nxt;
370         rtp = rtp_nxt;
371     }
372 }
373 
374 
375 //
376 //
377 //
378 static
R_InstallSpriteLump(lumpnum_t pat_lumpnum,uint16_t spritelump_id,byte frame,char rotation_char,boolean flipped)379 void R_InstallSpriteLump ( lumpnum_t     pat_lumpnum,   // graphics patch
380                            uint16_t      spritelump_id, // spritelump_t index
381                            byte          frame,
382                            char          rotation_char,
383                            boolean       flipped )
384 {
385     int    r;
386     byte   rotation = 0;
387     byte   frame_srp;
388     spriteframe_t * fmp;
389     sprite_frot_t * rtp;
390 
391 #ifdef ROT16
392     // The rotations are saved in the sprfrot in the rotation_char order.
393     // They are converted to draw index order when the sprfrot is saved.
394     if( rotation_char == '0' )
395     {
396         rotation = 0;
397     }
398     else if((rotation_char >= '1') && (rotation_char <= '9'))
399     {
400         rotation = rotation_char - '1';  // 0..8
401     }
402     else if((rotation_char >= 'A') && (rotation_char <= 'G'))
403     {
404         rotation = rotation_char - 'A' + 10 - 1;  // 9..15
405     }
406     else if((rotation_char >= 'a') && (rotation_char <= 'g'))
407     {
408         rotation = rotation_char - 'a' + 10 - 1;  // 9..15
409     }
410 #else
411     if( rotation_char == '0' )
412     {
413         rotation = 0;
414     }
415     else if((rotation_char >= '1') && (rotation_char <= '8'))
416     {
417         rotation = rotation_char - '1';  // 0..7
418     }
419 #endif
420 
421     if( frame >= MAX_FRAMES || rotation >= NUM_SPRITETMP_ROT )
422     {
423         I_SoftError("R_InstallSpriteLump: Bad frame characters in lump %i\n",
424                     spritelump_id);
425         return;
426     }
427 
428     if ((int)frame > maxframe)
429         maxframe = frame;
430 
431     fmp = & sprfrm[frame];
432     frame_srp = fmp->rotation_pattern;
433     rtp = & sprfrot[ (frame * NUM_SPRITETMP_ROT) + rotation ];
434 
435     if( rotation_char == '0' )
436     {
437         // the lump should be used for all rotations
438         if( devparm )
439         {
440             if( frame_srp == SRP_1 )
441             {
442                 GenPrintf(EMSG_dev,
443                  "R_Init_Sprites: Sprite %s frame %c has multiple rot=0 lump\n",
444                  spritename, 'A'+frame);
445             }
446             else if( frame_srp >= SRP_8 )
447             {
448                 GenPrintf(EMSG_dev,
449                  "R_Init_Sprites: Sprite %s frame %c has rotations and a rot=0 lump\n",
450                  spritename, 'A'+frame);
451             }
452         }
453         fmp->rotation_pattern = SRP_1;
454 #if 0
455         // Only rotation 0.
456         rtp->pat_lumpnum = pat_lumpnum;
457         rtp->spritelump_id  = spritelump_id;
458         rtp->flip = (byte)flipped;
459 #else
460         // Fill the whole array with the single rotation so any later overwrites with
461         // SRP_8 will keep the single rotation as the default.
462         for (r=0 ; r<NUM_SPRITETMP_ROT ; r++)
463         {
464             rtp->pat_lumpnum = pat_lumpnum;
465             rtp->spritelump_id  = spritelump_id;
466             rtp->flip = (byte)flipped;
467             rtp++;
468         }
469 #endif
470         return;
471     }
472 
473     // The lump is one rotation in a set.
474     if( (frame_srp == SRP_1) && devparm )
475     {
476         GenPrintf(EMSG_dev,
477            "R_Init_Sprites: Sprite %s frame %c has rotations and a rot=0 lump\n",
478            spritename, 'A'+frame);
479     }
480 
481 #ifdef ROT16
482     byte new_frame_srp = ( rotation > 7 )? SRP_16 : SRP_8;
483     if( fmp->rotation_pattern < new_frame_srp )
484         fmp->rotation_pattern = new_frame_srp;
485 #else
486     fmp->rotation_pattern = SRP_8;
487 #endif
488 
489     if( (rtp->spritelump_id != -1) && devparm )
490     {
491         GenPrintf(EMSG_dev,
492            "R_Init_Sprites: Sprite %s : %c : %c has two lumps mapped to it\n",
493            spritename, 'A'+frame, rotation_char );
494     }
495 
496     // [WDJ] The pat_lumpnum is the (file,lump) used to load the lump from the file.
497     // The spritelump_id is the index into the spritelumps table, as maintained in r_data.
498     // Any similarity within the original Doom is accidental.
499     // This is the only func that changes them, and they are always both updated.
500     rtp->pat_lumpnum = pat_lumpnum;
501     rtp->spritelump_id = spritelump_id;
502     rtp->flip = (byte)flipped;
503 }
504 
505 
506 // Install a single sprite, given its identifying name (4 chars)
507 //
508 // (originally part of R_AddSpriteDefs)
509 //
510 // Pass: name of sprite : 4 chars
511 //       spritedef_t
512 //       wadnum         : wad number, indexes wadfiles[], where patches
513 //                        for frames are found
514 //       startlump      : first lump to search for sprite frames
515 //       endlump        : AFTER the last lump to search
516 //
517 // Returns true if the sprite was succesfully added
518 //
R_AddSingleSpriteDef(char * sprname,spritedef_t * spritedef,int wadnum,int startlump,int endlump)519 boolean R_AddSingleSpriteDef (char* sprname, spritedef_t* spritedef, int wadnum, int startlump, int endlump)
520 {
521     spriteframe_t * fmp;
522     sprite_frot_t * rtp;
523     lumpinfo_t *lumpinfo;
524     uint32_t    numname;
525     lumpnum_t   lumpnum;
526     lumpnum_t   fnd_lumpnum = 0;
527     int         l;
528     int         frame;
529     int         spritelump_id;  // spritelump table index
530     patch_t     patch;	// temp for read header
531     byte        array_srp = SRP_NULL;
532     byte        rotation, frame_rot;
533     char        rotation_char;
534 
535     numname = *(uint32_t *)sprname;
536 
537     memset (sprfrot,-1, sizeof(sprfrot));
538     memset (sprfrm, 0, sizeof(sprfrm));
539     maxframe = -1;
540 
541     // are we 'patching' a sprite already loaded ?
542     // if so, it might patch only certain frames, not all
543     if (spritedef->numframes) // (then spriteframes is not null)
544     {
545         // copy the already defined sprite frames
546         // Extract to sprfrot format.
547         transfer_to_spritetmp( spritedef );
548         maxframe = spritedef->numframes - 1;
549     }
550 
551     // scan the lumps,
552     //  filling in the frames for whatever is found
553     lumpinfo = wadfiles[wadnum]->lumpinfo;
554     if( lumpinfo == NULL )
555         return false;
556 
557     if( endlump > wadfiles[wadnum]->numlumps )
558         endlump = wadfiles[wadnum]->numlumps;
559 
560     for (l=startlump ; l<endlump ; l++)
561     {
562         lumpnum = WADLUMP(wadnum,l);	// as used by read lump routines
563         if (*(uint32_t *)lumpinfo[l].name == numname)
564         {
565             frame = lumpinfo[l].name[4] - 'A';
566             rotation_char = lumpinfo[l].name[5];
567 
568             // skip NULL sprites from very old dmadds pwads
569             if( W_LumpLength( lumpnum ) <= 8 )
570                 continue;
571 
572             // store sprite info in lookup tables
573             //FIXME:numspritelumps do not duplicate sprite replacements
574             W_ReadLumpHeader (lumpnum, &patch, sizeof(patch_t)); // to temp
575             // [WDJ] Do endian while translate temp to internal.
576             spritelump_id = R_Get_spritelump();  // get next index, may expand and move the table
577             spritelump_t * sl = &spritelumps[spritelump_id];  // sprite patch header
578 
579             // uint16_t convserion to block sign-extension of signed LE_SWAP16.
580             // uint32_t conversion needed for shift
581             sl->width = ((uint32_t)((uint16_t)( LE_SWAP16(patch.width) )))<<FRACBITS; // unsigned
582             sl->leftoffset = ((int32_t)LE_SWAP16(patch.leftoffset))<<FRACBITS;  // signed
583             sl->topoffset = ((int32_t)LE_SWAP16(patch.topoffset))<<FRACBITS;  // signed
584             sl->height = ((uint32_t)((uint16_t)( LE_SWAP16(patch.height) )))<<FRACBITS;  // unsigned
585 
586 #if 0
587 // [WDJ] see fig_topoffset, in hw_main.c
588 // This does not adjust to changes in drawmode, leaving objects embedded in floor.
589 #ifdef HWRENDER
590             //BP: we cannot use special trick in hardware mode because feet in ground caused by z-buffer
591             if( rendermode != render_soft )
592             {
593                 // topoffset may be negative, use signed compare
594                 int16_t p_topoffset = LE_SWAP16(patch.topoffset);
595                 int16_t p_height = (uint16_t)( LE_SWAP16(patch.height) );
596                 if( p_topoffset>0 && p_topoffset<p_height) // not for psprite
597                 {
598                     // perfect is patch.height but sometime it is too high
599                     sl->topoffset =
600                        min(p_topoffset+4, p_height)<<FRACBITS;
601                 }
602             }
603 #endif
604 #endif
605 
606             //----------------------------------------------------
607 
608             fnd_lumpnum = lumpnum;
609             R_InstallSpriteLump (lumpnum, spritelump_id, frame, rotation_char, false);
610 
611             if (lumpinfo[l].name[6])  // if flipped
612             {
613                 frame = lumpinfo[l].name[6] - 'A';
614                 rotation_char = lumpinfo[l].name[7];
615                 R_InstallSpriteLump (lumpnum, spritelump_id, frame, rotation_char, true);
616             }
617         }
618     }
619 
620     //
621     // if no frames found for this sprite
622     //
623     if (maxframe == -1)
624     {
625         // the first time (which is for the original wad),
626         // all sprites should have their initial frames
627         // and then, patch wads can replace it
628         // we will skip non-replaced sprite frames, only if
629         // they have already have been initially defined (original wad)
630 
631         //check only after all initial pwads added
632         //if (spritedef->numframes == 0)
633         //    I_SoftError("R_AddSpriteDefs: no initial frames found for sprite %s\n",
634         //             namelist[i]);
635 
636         // sprite already has frames, and is not replaced by this wad
637         return false;
638     }
639 
640     maxframe++;
641 
642     array_srp = SRP_NULL;
643     //
644     //  some checks to help development
645     //
646     for (frame = 0 ; frame < maxframe ; frame++)
647     {
648         fmp = & sprfrm[ frame ];
649         rtp = & sprfrot[frame * NUM_SPRITETMP_ROT];
650         if( array_srp < fmp->rotation_pattern )
651             array_srp = fmp->rotation_pattern;
652 
653         switch( fmp->rotation_pattern )
654         {
655           case SRP_NULL:
656             // no rotations were found for that frame at all
657 #ifdef DEBUG_CHEXQUEST
658             // [WDJ] 4/28/2009 Chexquest
659             // [WDJ] not fatal, some wads have broken sprite but still play
660             debug_Printf( "R_Init_Sprites: No patches found for %s frame %c \n",
661                           sprname, frame+'A');
662 #else
663             I_SoftError ("R_Init_Sprites: No patches found for %s frame %c\n",
664                          sprname, frame+'A');
665 #endif
666             break;
667 
668           case SRP_1:
669             // only the first rotation is needed
670             break;
671 
672           case SRP_8:
673             // must have all 8 frames
674             for (rotation=0 ; rotation<8 ; rotation++)
675             {
676                 // we test the patch lump, or the id lump whatever
677                 // if it was not loaded the two are -1
678                 if( ! VALID_LUMP(rtp->pat_lumpnum) )
679                 {
680                     I_SoftError("R_Init_Sprites: Sprite %s frame %c is missing rotation %i\n",
681                              sprname, frame+'A', rotation);
682                     // Limp, use the last sprite lump read for this sprite.
683                     rtp->pat_lumpnum = fnd_lumpnum;
684                 }
685                 rtp++;
686             }
687             break;
688 
689 #ifdef ROT16
690           case SRP_16:
691             // must have all 16 frames
692             for (rotation=0 ; rotation<16 ; rotation++)
693             {
694                 // we test the patch lump, or the id lump whatever
695                 // if it was not loaded the two are -1
696                 if( ! VALID_LUMP(rtp->pat_lumpnum) )
697                 {
698                     I_SoftError("R_Init_Sprites: Sprite %s frame %c is missing rotation %i\n",
699                              sprname, frame+'A', rotation);
700                     // Limp, use the last sprite lump read for this sprite.
701                     rtp->pat_lumpnum = fnd_lumpnum;
702                 }
703                 rtp++;
704             }
705             break;
706 #endif
707         }
708     }
709 
710     frame_rot = srp_to_num_rot[ array_srp ];
711 
712     // allocate space for the frames present and copy spritetmp to it
713     if( spritedef->numframes                // has been allocated
714         && (spritedef->numframes < maxframe  // more frames are defined
715             || spritedef->frame_rot < frame_rot) ) // more rotations are defined
716     {
717         Z_Free (spritedef->spriteframe);
718         Z_Free (spritedef->framerotation);
719         spritedef->spriteframe = NULL;
720         spritedef->framerotation = NULL;
721     }
722 
723     // allocate this sprite's frames
724     if (spritedef->spriteframe == NULL)
725     {
726         spritedef->spriteframe =
727             Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
728         spritedef->framerotation =
729             Z_Malloc (maxframe * frame_rot * sizeof(sprite_frot_t), PU_STATIC, NULL);
730     }
731 
732     spritedef->numframes = maxframe;
733     spritedef->frame_rot = frame_rot;
734     transfer_from_spritetmp( spritedef, array_srp, frame_rot );
735 
736     return true;
737 }
738 
739 
740 
741 //
742 // Search for sprites replacements in a wad whose names are in namelist
743 //
R_AddSpriteDefs(char ** namelist,int wadnum)744 void R_AddSpriteDefs (char** namelist, int wadnum)
745 {
746     lumpnum_t  start_ln, end_ln;
747     int         i, ln1, ln2;
748     int         addsprites;
749 
750     // find the sprites section in this pwad
751     // we need at least the S_END
752     // (not really, but for speedup)
753 
754     start_ln = W_CheckNumForNamePwad ("S_START",wadnum,0);
755     if( ! VALID_LUMP(start_ln) )
756         start_ln = W_CheckNumForNamePwad ("SS_START",wadnum,0); //deutex compatib.
757     if( ! VALID_LUMP(start_ln) )
758     {
759         // search frames from start of wad
760         ln1 = 0;
761     }
762     else
763     {
764         // just after S_START
765         ln1 = LUMPNUM( start_ln ) + 1;
766     }
767 
768 
769     end_ln = W_CheckNumForNamePwad ("S_END",wadnum,0);
770     if( ! VALID_LUMP(end_ln) )
771         end_ln = W_CheckNumForNamePwad ("SS_END",wadnum,0);     //deutex compatib.
772     if( ! VALID_LUMP(end_ln) )
773     {
774         if (devparm)
775             GenPrintf(EMSG_dev, "no sprites in pwad %d\n", wadnum);
776         return;
777         //I_Error ("R_AddSpriteDefs: S_END, or SS_END missing for sprites "
778         //         "in pwad %d\n",wadnum);
779     }
780     ln2 = LUMPNUM( end_ln );
781 
782     //
783     // scan through lumps, for each sprite, find all the sprite frames
784     //
785     addsprites = 0;
786     for (i=0 ; i<numsprites ; i++)
787     {
788         spritename = namelist[i];
789 
790         if (R_AddSingleSpriteDef (spritename, &sprites[i], wadnum, ln1, ln2) )
791         {
792             // if a new sprite was added (not just replaced)
793             addsprites++;
794             if (devparm)
795                 GenPrintf(EMSG_dev, "sprite %s set in pwad %d\n", namelist[i], wadnum);//Fab
796         }
797     }
798 
799     GenPrintf(EMSG_info, "%d sprites added from file %s\n", addsprites, wadfiles[wadnum]->filename);//Fab
800     //CONS_Error ("press enter\n");
801 }
802 
803 
804 
805 //
806 // GAME FUNCTIONS
807 //
808 
809 // [WDJ] Remove sprite limits. This is the soft limit, the hard limit is twice this value.
810 CV_PossibleValue_t spritelim_cons_t[] = {
811    {128, "128"}, {192,"192"}, {256, "256"}, {384,"384"},
812    {512,"512"}, {768,"768"}, {1024,"1024"}, {1536,"1536"},
813    {2048,"2048"}, {3072, "3072"}, {4096,"4096"}, {6144, "6144"},
814    {8192,"8192"}, {12288, "12288"}, {16384,"16384"},
815    {0, NULL} };
816 consvar_t  cv_spritelim = { "sprites_limit", "512", CV_SAVE, spritelim_cons_t, NULL };
817 
818 // [WDJ] Remove sprite limits.
819 static int  vspr_change_delay = 128;  // quick first allocate
820 static unsigned int  vspr_random = 0x7f43916;
821 static int  vspr_halfcnt; // count to halfway
822 
823 static int  vspr_count = 0;	// count of sprites in the frame
824 static int  vspr_needed = 64;     // max over several frames
825 static int  vspr_max = 0;	// size of array - 1
826 static vissprite_t*    vissprites = NULL;  // [0 .. vspr_max]
827 static vissprite_t*    vissprite_last;	   // last vissprite in array
828 static vissprite_t*    vissprite_p;    // next free vissprite
829 static vissprite_t*    vissprite_far;  // a far vissprite, can be replaced
830 
831 static vissprite_t     vsprsortedhead;  // sorted list head (circular linked)
832 
833 // Call between frames, it does not copy contents, and does not init.
vissprites_tablesize(void)834 void vissprites_tablesize ( void )
835 {
836     int request;
837     // sprite needed over several frames
838     if ( vspr_count > vspr_needed )
839         vspr_needed = vspr_count;  // max
840     else
841         vspr_needed -= (vspr_needed - vspr_count) >> 8;  // slow decay
842 
843     request = ( vspr_needed > cv_spritelim.value )?
844               (cv_spritelim.value + vspr_needed)/2  // soft limit
845             : vspr_needed;  // under limit
846 
847     // round-up to avoid trivial adjustments
848     request = (request < (256*6))?
849               (request + 0x003F) & ~0x003F   // 64
850             : (request + 0x00FF) & ~0x00FF;  // 256
851     // hard limit
852     if ( request > (cv_spritelim.value * 2) )
853         request = cv_spritelim.value * 2;
854 
855     if ( request == (vspr_max+1) )
856         return;		// same as existing allocation
857 
858     if( vspr_change_delay < INT_MAX )
859     {
860         vspr_change_delay ++;
861     }
862     if ( request < vspr_max )
863     {
864         // decrease allocation
865         if ( ( request < cv_spritelim.value )  // once up to limit, stay there
866              || ( request > (vspr_max / 4))  // avoid vacillation
867              || ( vspr_change_delay < 8192 )  )  // delay decreases
868         {
869             if (vspr_max <= cv_spritelim.value * 2)  // unless user setting was reduced
870                 return;
871         }
872         if ( request < 64 )
873              request = 64;  // absolute minimum
874     }
875     else
876     {
877         // delay to get max sprites needed for new scene
878         // but not too much or is very visible
879         if( vspr_change_delay < 16 )  return;
880     }
881     vspr_change_delay = 0;
882     // allocate
883     if ( vissprites )
884     {
885         free( vissprites );
886     }
887     do {  // repeat allocation attempt until success
888         vissprites = (vissprite_t*) malloc ( sizeof(vissprite_t) * request );
889         if( vissprites )
890         {
891             vspr_max = request-1;
892             return;	// normal successful allocation
893         }
894         // allocation failed
895         request /= 2;  // halve the request
896     }while( request > 63 );
897 
898     I_Error ("Cannot allocate vissprites\n");
899 }
900 
901 
902 //
903 // R_Init_Sprites
904 // Called at program start.
905 //
R_Init_Sprites(char ** namelist)906 void R_Init_Sprites (char** namelist)
907 {
908     int         i;
909     char**      check;
910 
911     memset( clip_screen_top_min, 0, MAXVIDWIDTH * sizeof(short) );
912 
913     vissprites_tablesize();  // initial allocation
914 
915     //
916     // count the number of sprite names, and allocate sprites table
917     //
918     check = namelist;
919     while (*check != NULL)
920         check++;
921     numsprites = check - namelist;
922 
923     if (!numsprites)
924         I_Error ("R_AddSpriteDefs: no sprites in namelist\n");
925 
926     sprites = Z_Malloc(numsprites * sizeof(*sprites), PU_STATIC, NULL);
927     memset (sprites, 0, numsprites * sizeof(*sprites));
928 
929     // find sprites in each -file added pwad
930     for (i=0; i<numwadfiles; i++)
931         R_AddSpriteDefs (namelist, i);
932 
933     //
934     // now check for skins
935     //
936 
937     // all that can be before loading config is to load possible skins
938     R_Init_Skins ();
939     for (i=0; i<numwadfiles; i++)
940         R_AddSkins (i);
941 
942 
943     //
944     // check if all sprites have frames
945     //
946     /*
947     for (i=0; i<numsprites; i++)
948          if (sprites[i].numframes<1)
949              I_SoftError("R_Init_Sprites: sprite %s has no frames at all\n", sprnames[i]);
950     */
951 }
952 
953 
954 
955 //
956 // R_Clear_Sprites
957 // Called at frame start.
958 //
R_Clear_Sprites(void)959 void R_Clear_Sprites (void)
960 {
961     vissprites_tablesize();  // re-allocation
962     vspr_random += (vspr_count & 0xFFFF0) + 0x010001;  // just keep it changing
963     vissprite_last = &vissprites[vspr_max];
964     vissprite_p = vissprites;  // first free vissprite
965     vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;  // init sorted
966     vsprsortedhead.scale = FIXED_MAX;  // very near, so it is rejected in farthest search
967     vissprite_far = & vsprsortedhead;
968     vspr_halfcnt = 0; // force vissprite_far init
969     vspr_count = 0;  // stat for allocation
970 }
971 
972 
973 //
974 // R_NewVisSprite
975 //
976 static vissprite_t     overflowsprite;
977 
978 // [WDJ] New vissprite sorted by scale
979 // Closer sprites get preference in the vissprite list when too many.
980 // Sorted list is farthest to nearest (circular).
981 //   scale : the draw scale, representing distance from viewer
982 //   dist_pri : distance priority, 0..255, dead are low, monsters are high
983 //   copysprite : copy this sprite
984 static
R_NewVisSprite(fixed_t scale,byte dist_pri,vissprite_t * copysprite)985 vissprite_t* R_NewVisSprite ( fixed_t scale, byte dist_pri,
986                               vissprite_t * copysprite )
987 {
988     vissprite_t * vs;
989     register vissprite_t * ns;
990 
991     vspr_count ++;	// allocation stat
992     if (vissprite_p == vissprite_last)  // array full ?
993     {
994         unsigned int rn, cnt;
995         // array is full
996         vspr_random += 0x021019; // semi-random stirring (prime)
997         if ( vsprsortedhead.next->scale > scale )
998         {
999             // New sprite is farther than farthest sprite in array,
1000             // even far sprites have random chance of being seen (flicker)
1001             // Avg (pri=128) monster has 1/16 chance.
1002             if (((vspr_random >> 8) & 0x7FF) > dist_pri)
1003                 return &overflowsprite;
1004         }
1005         // Must remove a sprite to make room.
1006         // Sacrifice a random sprite from farthest half.
1007         // Skip a random number of sprites, at least 1.
1008         // Try for a tapering distance effect.
1009         rn = (vspr_random & 0x000F) + ((vspr_max - vspr_halfcnt) >> 7);
1010         for( cnt = 2; ; cnt-- )  // tries to find lower priority
1011         {
1012             if( vspr_halfcnt <= 0 ) // halfway count trigger
1013             {
1014                 // init, or re-init
1015                 vspr_halfcnt = vspr_max / 2;
1016                 vissprite_far = vsprsortedhead.next; // farthest
1017             }
1018             vs = vissprite_far;
1019             rn ++;  // at least 1
1020             // Move vissprite_far off the sprite that will be removed.
1021             vspr_halfcnt -= rn;  // count down to halfway
1022             for( ; rn > 0 ; rn -- )
1023             {
1024                 vissprite_far = vissprite_far->next; // to nearer sprites
1025             }
1026             // Compare priority, but only a few times.
1027             if( cnt == 0 )  break;
1028             if( vs->dist_priority <= dist_pri )   break;
1029         }
1030 
1031         // unlink it so it can be re-linked by distance
1032         vs->next->prev = vs->prev;
1033         vs->prev->next = vs->next;
1034     }
1035     else
1036     {
1037         // still filling up array
1038         vs = vissprite_p ++;
1039     }
1040 
1041     // Set links so order is farthest to nearest.
1042     // Check the degenerate case first and avoid this test in the loop below.
1043     // Empty list looks to have head as max nearest sprite, so first is farthest.
1044     if (vsprsortedhead.next->scale > scale)
1045     {
1046         // New is farthest, this will happen often because of close preference.
1047         ns = &vsprsortedhead; // farthest is linked after head
1048     }
1049     else
1050     {
1051         // Search nearest to farthest.
1052         // The above farthest check ensures that search will hit something farther.
1053         ns = vsprsortedhead.prev; // nearest
1054         while( ns->scale > scale )  // while new is farther
1055         {
1056             ns = ns->prev;
1057         }
1058     }
1059     // ns is farther than new
1060     // Copy before linking, is easier.
1061     if( copysprite )
1062         memcpy( vs, copysprite, sizeof(vissprite_t));
1063     // link new vs after ns (nearer than ns)
1064     vs->next = ns->next;
1065     vs->next->prev = vs;
1066     ns->next = vs;
1067     vs->prev = ns;
1068     vs->dist_priority = dist_pri;
1069 
1070     return vs;
1071 }
1072 
1073 
1074 
1075 //
1076 // R_DrawMaskedColumn
1077 // Used for sprites and masked mid textures.
1078 // Masked means: partly transparent, i.e. stored
1079 //  in posts/runs of opaque pixels.
1080 // The colfunc_2s function for TM_patch and TM_combine_patch
1081 //
1082 // draw masked global parameters
1083 // clipping array[x], in int screen coord.
1084 short*          dm_floorclip;
1085 short*          dm_ceilingclip;
1086 
1087 fixed_t         dm_yscale;  // world to fixed_t screen coord
1088 // draw masked column top and bottom, in fixed_t screen coord.
1089 fixed_t         dm_top_patch, dm_bottom_patch;
1090 // window clipping in fixed_t screen coord., set to FIXED_MAX to disable
1091 // to draw, require dm_windowtop < dm_windowbottom
1092 fixed_t         dm_windowtop, dm_windowbottom;
1093 // for masked draw of patch, to form dc_texturemid
1094 fixed_t         dm_texturemid;
1095 
1096 
1097 // Called by R_RenderMaskedSegRange, R_RenderThickSideRange, R_RenderFog
R_DrawMaskedColumn(byte * column_data)1098 void R_DrawMaskedColumn ( byte * column_data )
1099 {
1100     fixed_t     top_post_sc, bottom_post_sc;  // fixed_t screen coord.
1101 #ifdef DEEPSEA_TALL_PATCH
1102     // [MB (M. Bauerle), from crispy Doom]  Support for DeePsea tall patches, [WDJ]
1103     int         cur_topdelta = -1;  // [crispy]
1104 #endif
1105 
1106     column_t * column = (column_t*) column_data;
1107 
1108     // over all column posts for this column
1109     for ( ; column->topdelta != 0xff ; )
1110     {
1111         // calculate unclipped screen coordinates
1112         //  for post
1113 #ifdef DEEPSEA_TALL_PATCH
1114         // [crispy] [MB] [WDJ] DeePsea tall patch.
1115         // DeepSea allows the patch to exceed 254 height.
1116         // A Doom patch has monotonic ascending topdelta values, 0..254.
1117         // DeePsea tall patches have an optional relative topdelta.
1118         // When the column topdelta is <= the current topdelta,
1119         // it is a DeePsea tall patch relative topdelta.
1120         if( (int)column->topdelta <= cur_topdelta )
1121         {
1122             cur_topdelta += column->topdelta;  // DeePsea relative topdelta
1123         }
1124         else
1125         {
1126             cur_topdelta = column->topdelta;  // Normal Doom patch
1127         }
1128         top_post_sc = dm_top_patch + (dm_yscale * cur_topdelta);
1129 #else
1130         // Normal patch
1131         top_post_sc = dm_top_patch + (dm_yscale * column->topdelta);
1132 #endif
1133 
1134         bottom_post_sc = (dm_yscale * column->length)
1135 	    + ((dm_bottom_patch == FIXED_MAX) ? top_post_sc : dm_bottom_patch );
1136 
1137         // fixed_t to int screen coord.
1138         dc_yl = (top_post_sc+FRACUNIT-1)>>FRACBITS;
1139         dc_yh = (bottom_post_sc-1)>>FRACBITS;
1140 
1141         if(dm_windowtop != FIXED_MAX && dm_windowbottom != FIXED_MAX)
1142         {
1143           // screen coord. where +y is down screen
1144           if(dm_windowtop > top_post_sc)
1145             dc_yl = (dm_windowtop + FRACUNIT - 1) >> FRACBITS;
1146           if(dm_windowbottom < bottom_post_sc)
1147             dc_yh = (dm_windowbottom - 1) >> FRACBITS;
1148         }
1149 
1150         if (dc_yh > dm_floorclip[dc_x])
1151             dc_yh = dm_floorclip[dc_x];
1152         if (dc_yl < dm_ceilingclip[dc_x])
1153             dc_yl = dm_ceilingclip[dc_x];
1154 
1155         // [WDJ] limit to split screen area above status bar,
1156         // instead of whole screen,
1157         if (dc_yl <= dc_yh && dc_yl < rdraw_viewheight && dc_yh > 0)  // [WDJ] exclude status bar
1158         {
1159 
1160 #ifdef RANGECHECK_DRAW_LIMITS
1161     // Temporary check code.
1162     // Due to better clipping, this extra clip should no longer be needed.
1163     if( dc_yl < 0 )
1164     {
1165         printf( "DrawMasked dc_yl  %i < 0\n", dc_yl );
1166         dc_yl = 0;
1167     }
1168     if ( dc_yh >= rdraw_viewheight )
1169     {
1170         printf( "DrawMasked dc_yh  %i > rdraw_viewheight\n", dc_yh );
1171         dc_yh = rdraw_viewheight - 1;
1172     }
1173 #endif
1174 
1175 #ifdef CLIP2_LIMIT
1176             //[WDJ] phobiata.wad has many views that need clipping
1177             if ( dc_yl < 0 )   dc_yl = 0;
1178             if ( dc_yh >= rdraw_viewheight )   dc_yh = rdraw_viewheight - 1;
1179 #endif
1180 
1181             dc_source = (byte *)column + 3;
1182 #ifdef DEEPSEA_TALL_PATCH
1183             // [crispy] Support for DeePsea tall patches
1184             dc_texturemid = dm_texturemid - (cur_topdelta<<FRACBITS);
1185             // dc_source = (byte *)column + 3 - cur_topdelta;
1186 #else
1187             // Normal patch
1188             dc_texturemid = dm_texturemid - (column->topdelta<<FRACBITS);
1189             // dc_source = (byte *)column + 3 - column->topdelta;
1190 #endif
1191             fog_col_length = column->length;
1192 
1193             // Drawn by either R_DrawColumn
1194             //  or (SHADOW) R_DrawFuzzColumn.
1195             colfunc ();
1196         }
1197         column = (column_t *)(  (byte *)column + column->length + 4);
1198     }
1199 }
1200 
1201 
1202 
1203 //
1204 // R_DrawVisSprite
1205 //  dm_floorclip and dm_ceilingclip should also be set.
1206 //
R_DrawVisSprite(vissprite_t * vis,int x1,int x2)1207 static void R_DrawVisSprite ( vissprite_t *  vis,
1208                               int  x1,  int  x2 )
1209 {
1210     int        texturecolumn;
1211     fixed_t    texcol_frac;
1212     patch_t  * patch;
1213 
1214 
1215     //Fab:R_Init_Sprites now sets a wad lump number
1216     // Use common patch read so do not have patch in cache without endian fixed.
1217     patch = W_CachePatchNum (vis->patch_lumpnum, PU_CACHE);
1218 
1219     dc_colormap = vis->colormap;
1220 
1221     // Support for translated and translucent sprites. SSNTails 11-11-2002
1222     dr_alpha = 0;  // ensure use of translucent normally for all drawers
1223     if((vis->mobj_flags & MFT_TRANSLATION6) && vis->translucentmap)
1224     {
1225         colfunc = skintranscolfunc;
1226         dc_translucent_index = vis->translucent_index;
1227         dc_translucentmap = vis->translucentmap;
1228         dc_skintran = MFT_TO_SKINMAP( vis->mobj_flags ); // skins 1..
1229     }
1230     else if (vis->translucentmap==VIS_SMOKESHADE)
1231     {
1232         // Draw smoke
1233         // shadecolfunc uses 'reg_colormaps'
1234         colfunc = shadecolfunc;
1235     }
1236     else if (vis->translucentmap)
1237     {
1238 //        colfunc = fuzzcolfunc;
1239         colfunc = (vis->mobj_flags & MF_SHADOW)? fuzzcolfunc : transcolfunc;
1240         dc_translucent_index = vis->translucent_index;
1241         dc_translucentmap = vis->translucentmap;    //Fab:29-04-98: translucency table
1242     }
1243     else if (vis->mobj_flags & MFT_TRANSLATION6)
1244     {
1245         // translate green skin to another color
1246         colfunc = skincolfunc;
1247         dc_skintran = MFT_TO_SKINMAP( vis->mobj_flags ); // skins 1..
1248     }
1249 
1250     if((vis->extra_colormap || view_colormap) && !fixedcolormap)
1251     {
1252        // reverse indexing, and change to extra_colormap, default 0
1253        int lightindex = dc_colormap? (dc_colormap - reg_colormaps) : 0;
1254        lighttable_t* cm = (view_colormap? view_colormap : vis->extra_colormap->colormap);
1255        dc_colormap = & cm[ lightindex ];
1256     }
1257     if(!dc_colormap)
1258       dc_colormap = & reg_colormaps[0];
1259 
1260     // dc_iscale: fixed_t texture step per pixel, for draw function
1261     //dc_iscale = abs(vis->tex_x_iscale)>>detailshift;  ???
1262     dc_iscale = FixedDiv (FRACUNIT, vis->scale);
1263     dm_texturemid = vis->texturemid;
1264     dc_texheight = 0;  // no wrap repeat
1265 
1266     dm_yscale = vis->scale;
1267     dm_top_patch = centeryfrac - FixedMul(dm_texturemid, dm_yscale);
1268     dm_windowtop = dm_windowbottom = dm_bottom_patch = FIXED_MAX; // disable
1269 
1270     texcol_frac = vis->tex_x1;  // texture x at vis->x1
1271     for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, texcol_frac += vis->tex_x_iscale)
1272     {
1273         texturecolumn = texcol_frac>>FRACBITS;
1274 #ifdef RANGECHECK
1275         if (texturecolumn < 0 || texturecolumn >= patch->width) {
1276             // [WDJ] Give msg and don't draw it
1277             I_SoftError ("R_DrawVisSprite: bad texturecolumn\n");
1278             return;
1279         }
1280 #endif
1281 
1282         byte * col_data = ((byte *)patch) + patch->columnofs[texturecolumn];
1283         R_DrawMaskedColumn( col_data );
1284     }
1285 
1286     colfunc = basecolfunc;
1287 }
1288 
1289 
1290 
1291 
1292 //
1293 // R_Split_Sprite_over_FFloor
1294 // Makes a separate sprite for each floor in a sector lightlist that it touches.
1295 // These must be drawn interspersed with the ffloor floors and ceilings.
1296 // Called by R_ProjectSprite
1297 static
R_Split_Sprite_over_FFloor(vissprite_t * sprite,mobj_t * thing)1298 void R_Split_Sprite_over_FFloor (vissprite_t* sprite, mobj_t* thing)
1299 {
1300   int           i;
1301   int		sz_cut;		// where lightheight cuts on screen
1302   fixed_t	lightheight;
1303   sector_t*     sector;
1304   ff_light_t*   ff_light; // lightlist item
1305   vissprite_t*  newsprite;
1306 
1307   sector = sprite->sector;
1308 
1309   for(i = 1; i < sector->numlights; i++)	// from top to bottom
1310   {
1311     ff_light = &frontsector->lightlist[i];
1312     lightheight = ff_light->height;
1313 
1314     // must be a caster
1315     if(lightheight >= sprite->gz_top || !(ff_light->caster->flags & FF_CUTSPRITES))
1316       continue;
1317     if(lightheight <= sprite->gz_bot)
1318       return;
1319 
1320     // where on screen the lightheight cut appears
1321     sz_cut = (centeryfrac - FixedMul(lightheight - viewz, sprite->scale)) >> FRACBITS;
1322     if(sz_cut < 0)
1323             continue;
1324     if(sz_cut > rdraw_viewheight)	// [WDJ] 11/14/2009
1325             return;
1326 
1327     // Found a split! Make a new sprite, copy the old sprite to it, and
1328     // adjust the heights.  Below the cut is the newsprite.
1329     newsprite = R_NewVisSprite( sprite->scale, sprite->dist_priority, sprite );
1330 
1331     sprite->cut |= SC_BOTTOM;
1332     sprite->gz_bot = lightheight;
1333 
1334     newsprite->gz_top = sprite->gz_bot;
1335 
1336     // [WDJ] 11/14/2009 clip at window again, fix split sprites corrupt status bar
1337     sprite->sz_bot = (sz_cut < rdraw_viewheight)? sz_cut : rdraw_viewheight;
1338     newsprite->sz_top = sz_cut - 1;
1339 
1340     if(lightheight < sprite->mobj_top_z
1341            && lightheight > sprite->mobj_bot_z)
1342     {
1343         sprite->mobj_bot_z = newsprite->mobj_top_z = lightheight;
1344     }
1345     else
1346     {
1347         newsprite->mobj_bot_z = newsprite->gz_bot;
1348         newsprite->mobj_top_z = newsprite->gz_top;
1349     }
1350 
1351     newsprite->cut |= SC_TOP;
1352     if(!(ff_light->caster->flags & FF_NOSHADE))
1353     {
1354       lightlev_t  vlight = *ff_light->lightlevel  // visible light 0..255
1355           + ((ff_light->caster->flags & FF_FOG)? extralight_fog : extralight);
1356 
1357       spritelights =
1358           (vlight < 0) ? scalelight[0]
1359         : (vlight >= 255) ? scalelight[LIGHTLEVELS-1]
1360         : scalelight[vlight>>LIGHTSEGSHIFT];
1361 
1362       newsprite->extra_colormap = ff_light->extra_colormap;
1363 
1364       if (thing->frame & FF_SMOKESHADE)
1365         ;
1366       else
1367       {
1368 /*        if (thing->frame & FF_TRANSMASK)
1369           ;
1370         else if (thing->flags & MF_SHADOW)
1371           ;*/
1372 
1373         if (fixedcolormap )
1374           ;
1375         else if ((thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK)
1376                   || thing->flags & MF_SHADOW)
1377                  && !(newsprite->extra_colormap && newsprite->extra_colormap->fog))
1378           ;
1379         else
1380         {
1381           int dlit = sprite->xscale>>(LIGHTSCALESHIFT-detailshift);
1382           if (dlit >= MAXLIGHTSCALE)
1383             dlit = MAXLIGHTSCALE-1;
1384           newsprite->colormap = spritelights[dlit];
1385         }
1386       }
1387     }
1388     sprite = newsprite;
1389   }
1390 }
1391 
1392 
1393 //
1394 // R_ProjectSprite
1395 // Generates a vissprite for a thing, if it might be visible.
1396 //
R_ProjectSprite(mobj_t * thing)1397 static void R_ProjectSprite (mobj_t* thing)
1398 {
1399     fixed_t             tr_x, tr_y;
1400     fixed_t             tx, tz;
1401 
1402     fixed_t             xscale;
1403     fixed_t             yscale; //added:02-02-98:aaargll..if I were a math-guy!!!
1404 
1405     int                 x1, x2, fr;
1406 
1407     sector_t*		thingsector;	 // [WDJ] 11/14/2009
1408 
1409     spritedef_t*        sprdef;
1410     spriteframe_t *     sprframe;
1411     sprite_frot_t *     sprfrot;
1412     spritelump_t *      sprlump;  // sprite patch header (no pixels)
1413 
1414     unsigned int        rot;
1415     byte                flip;
1416 
1417     byte                dist_pri;  // distance priority
1418 
1419     vissprite_t*        vis;
1420     ff_light_t *        ff_light = NULL;  // lightlist light
1421 
1422     angle_t             ang;
1423     fixed_t             iscale;
1424 
1425     //SoM: 3/17/2000
1426     fixed_t             gz_top;
1427     int                 thingmodelsec;
1428     boolean	        thing_has_model;  // has a model, such as water
1429 
1430 
1431     // transform the origin point
1432     tr_x = thing->x - viewx;
1433     tr_y = thing->y - viewy;
1434 
1435     tz = FixedMul(tr_x,viewcos) + FixedMul(tr_y,viewsin);
1436 
1437     // thing is behind view plane?
1438     if (tz < MINZ)
1439         return;
1440 
1441     // aspect ratio stuff :
1442     xscale = FixedDiv(projection, tz);
1443     yscale = FixedDiv(projectiony, tz);
1444 
1445     tx = FixedMul(tr_x,viewsin) - FixedMul(tr_y,viewcos);
1446 
1447     // too far off the side?
1448     if (abs(tx)>(tz<<2))
1449         return;
1450 
1451     // decide which patch to use for sprite relative to player
1452 #ifdef RANGECHECK
1453     if ((unsigned)thing->sprite >= numsprites) {
1454         // [WDJ] Give msg and don't draw it
1455         I_SoftError ("R_ProjectSprite: invalid sprite number %i\n",
1456                  thing->sprite);
1457         return;
1458     }
1459 #endif
1460 
1461     //Fab:02-08-98: 'skin' override spritedef currently used for skin
1462     if (thing->skin)
1463         sprdef = &((skin_t *)thing->skin)->spritedef;
1464     else
1465         sprdef = &sprites[thing->sprite];
1466 
1467 #ifdef RANGECHECK
1468     if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes ) {
1469         // [WDJ] Give msg and don't draw it
1470         I_SoftError ("R_ProjectSprite: invalid sprite frame %i : %i for %s\n",
1471                  thing->sprite, thing->frame, sprnames[thing->sprite]);
1472         return;
1473     }
1474 #endif
1475 
1476     // [WDJ] segfault control in heretic shareware, not all sprites present
1477     if( (byte*)sprdef->spriteframe < (byte*)0x1000 )
1478     {
1479         I_SoftError("R_ProjectSprite: sprframe ptr NULL for sprite %d\n", thing->sprite );
1480         return;
1481     }
1482 
1483     fr = thing->frame & FF_FRAMEMASK;
1484     sprframe = get_spriteframe( sprdef, fr );
1485 
1486     if( sprframe->rotation_pattern == SRP_1 )
1487     {
1488         // use single rotation for all views
1489         rot = 0;  //Fab: for vis->patch_lumpnum below
1490     }
1491     else
1492     {
1493         // choose a different rotation based on player view
1494         ang = R_PointToAngle(thing->x, thing->y);       // uses viewx,viewy
1495 
1496         if( sprframe->rotation_pattern == SRP_8)
1497         {
1498             // 8 direction rotation pattern
1499             rot = (ang - thing->angle + (unsigned) (ANG45/2) * 9) >> 29;
1500         }
1501 #ifdef ROT16
1502         else if( sprframe->rotation_pattern == SRP_16)
1503         {
1504             // 16 direction rotation pattern
1505             rot = (ang - thing->angle + (unsigned) (ANG45/4) * 17) >> 28;
1506         }
1507 #endif
1508         else return;
1509     }
1510 
1511     sprfrot = get_framerotation( sprdef, fr, rot );
1512     //Fab: [WDJ] spritelump_id is the index
1513     sprlump = &spritelumps[sprfrot->spritelump_id];  // sprite patch header
1514     flip = sprfrot->flip;
1515 
1516     // calculate edges of the shape
1517     if( flip )
1518     {
1519         // [WDJ] Flip offset, as suggested by Fraggle (seen in prboom 2003)
1520         tx -= sprlump->width - sprlump->leftoffset;
1521     }
1522     else
1523     {
1524         // apply offset from sprite lump normally
1525         tx -= sprlump->leftoffset;
1526     }
1527     x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
1528 
1529     // off the right side?
1530     if (x1 > rdraw_viewwidth)
1531         return;
1532 
1533 #if 1
1534     x2 = ((centerxfrac + FixedMul (tx + sprlump->width, xscale) ) >>FRACBITS) - 1;
1535 #else
1536     tx += sprlump->width;
1537     x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
1538 #endif
1539 
1540     // off the left side
1541     if (x2 < 0)
1542         return;
1543 
1544     //SoM: 3/17/2000: Disregard sprites that are out of view..
1545 
1546     // Sprite scale is same as physical scale.
1547     gz_top = thing->z + sprlump->topoffset;
1548 
1549     thingsector = thing->subsector->sector;	 // [WDJ] 11/14/2009
1550     if(thingsector->numlights)
1551     {
1552       lightlev_t  vlight;
1553       ff_light = R_GetPlaneLight(thingsector, gz_top);
1554       vlight = *ff_light->lightlevel;
1555       if(!( ff_light->caster && (ff_light->caster->flags & FF_FOG) ))
1556         vlight += extralight;
1557 
1558       spritelights =
1559           (vlight < 0) ? scalelight[0]
1560         : (vlight >= 255) ? scalelight[LIGHTLEVELS-1]
1561         : scalelight[vlight>>LIGHTSEGSHIFT];
1562     }
1563 
1564     thingmodelsec = thingsector->modelsec;
1565     thing_has_model = thingsector->model > SM_fluid; // water
1566 
1567     if (thing_has_model)   // only clip things which are in special sectors
1568     {
1569       sector_t * thingmodsecp = & sectors[thingmodelsec];
1570 
1571       // [WDJ] 4/20/2010  Added some structure and ()
1572       // [WDJ] Could use viewer_at_water to force view of objects above and
1573       // below to be seen simultaneously.
1574       // Instead have choosen to have objects underwater not be seen until
1575       // viewer_underwater.
1576       // When at viewer_at_water, will not see objects above nor below the water.
1577       // As this has some validity in reality, and does not generate HOM,
1578       // will live with it.  It is transient, and most players will not notice.
1579       if (viewer_has_model)
1580       {
1581           // [WDJ] FakeFlat uses viewz<=floor, and thing used viewz<floor,
1582           // They both should be the same or else things do not
1583           // appear when just underwater.
1584           if( viewer_underwater ?
1585               (thing->z >= thingmodsecp->floorheight)
1586               : (gz_top < thingmodsecp->floorheight)
1587               )
1588               return;
1589           // [WDJ] FakeFlat uses viewz>=ceiling, and thing used viewz>ceiling,
1590           // They both should be the same or else things do not
1591           // appear when just over ceiling.
1592           if( viewer_overceiling ?
1593               ((gz_top < thingmodsecp->ceilingheight) && (viewz > thingmodsecp->ceilingheight))
1594               : (thing->z >= thingmodsecp->ceilingheight)
1595               )
1596               return;
1597       }
1598     }
1599 
1600     // Store information in a vissprite.
1601     dist_pri = thing->height >> 16;  // height (fixed_t), 0..120, 56=norm.
1602     if( thing->flags & MF_MISSILE )
1603         dist_pri += 60;  // missiles are important
1604     else
1605     {
1606         // CORPSE may not be MF_SHOOTABLE.
1607         if( thing->flags & MF_CORPSE )
1608             dist_pri >>= 2;  // corpse has much less priority
1609         else if( thing->flags & (MF_SHOOTABLE|MF_COUNTKILL) )
1610             dist_pri += 20;  // monsters are important too
1611     }
1612 
1613     vis = R_NewVisSprite ( yscale, dist_pri, NULL );
1614     // do not waste time on the massive number of sprites in the distance
1615     if( vis == &overflowsprite )  // test for rejected, or too far
1616         return;
1617 
1618     // [WDJ] Only pass water models, not colormap model sectors
1619     vis->modelsec = thing_has_model ? thingmodelsec : -1 ; //SoM: 3/17/2000
1620     vis->mobj_flags = (thing->flags & MF_SHADOW) | (thing->tflags & MFT_TRANSLATION6);
1621     vis->mobj = thing;
1622     vis->mobj_x = thing->x;
1623     vis->mobj_y = thing->y;
1624  //   vis->mobj_height = thing->height;  // unused
1625     vis->mobj_bot_z = thing->z;
1626     vis->mobj_top_z = thing->z + thing->height;
1627     vis->gz_top = gz_top;
1628     vis->gz_bot = gz_top - sprlump->height;
1629     vis->texturemid = vis->gz_top - viewz;
1630     // foot clipping
1631     if(thing->flags2&MF2_FEETARECLIPPED
1632        && thing->z <= thingsector->floorheight)
1633     {
1634          vis->texturemid -= 10*FRACUNIT;
1635     }
1636 
1637     vis->x1 = (x1 < 0) ? 0 : x1;
1638     vis->x2 = (x2 >= rdraw_viewwidth) ? rdraw_viewwidth-1 : x2;
1639     vis->xscale = xscale; // SoM: 4/17/2000
1640     vis->scale = yscale;  // <<detailshift;
1641     vis->sz_top = (centeryfrac - FixedMul(vis->gz_top - viewz, yscale)) >> FRACBITS;
1642     vis->sz_bot = (centeryfrac - FixedMul(vis->gz_bot - viewz, yscale)) >> FRACBITS;
1643     vis->cut = SC_NONE;	// none, false
1644 
1645     iscale = FixedDiv (FRACUNIT, xscale);
1646 
1647     if (flip)
1648     {
1649         vis->tex_x1 = sprlump->width - 1;
1650         vis->tex_x_iscale = -iscale;
1651     }
1652     else
1653     {
1654         vis->tex_x1 = 0;
1655         vis->tex_x_iscale = iscale;
1656     }
1657 
1658     if (vis->x1 > x1)
1659         vis->tex_x1 += vis->tex_x_iscale * (vis->x1 - x1);
1660 
1661     // [WDJ] The patch_lumpnum is the (file,lump) used to load the lump from the file.
1662     // The spritelump_id is the index to the sprite lump table.
1663     vis->patch_lumpnum = sprfrot->pat_lumpnum;
1664 
1665     vis->sector = thingsector;
1666     vis->extra_colormap = (ff_light)?
1667         ff_light->extra_colormap
1668         : thingsector->extra_colormap;
1669 
1670 //
1671 // determine the colormap (lightlevel & special effects)
1672 //
1673     vis->translucentmap = NULL;
1674     vis->translucent_index = 0;
1675 
1676     // specific translucency
1677     if (thing->frame & FF_SMOKESHADE)
1678     {
1679         // Draw smoke
1680         // not really a colormap ... see R_DrawVisSprite
1681 //        vis->colormap = VIS_SMOKESHADE;
1682         vis->colormap = NULL;
1683         vis->translucentmap = VIS_SMOKESHADE;
1684     }
1685     else
1686     {
1687         if (thing->frame & FF_TRANSMASK)
1688         {
1689             vis->translucent_index = (thing->frame&FF_TRANSMASK)>>FF_TRANSSHIFT;
1690             vis->translucentmap = & translucenttables[ FF_TRANSLU_TABLE_INDEX(thing->frame) ];
1691         }
1692         else if (thing->flags & MF_SHADOW)
1693         {
1694             // actually only the player should use this (temporary invisibility)
1695             // because now the translucency is set through FF_TRANSMASK
1696             vis->translucent_index = TRANSLU_hi;
1697             vis->translucentmap = & translucenttables[ TRANSLU_TABLE_hi ];
1698         }
1699 
1700 
1701         if (fixedcolormap )
1702         {
1703             // fixed map : all the screen has the same colormap
1704             //  eg: negative effect of invulnerability
1705             vis->colormap = fixedcolormap;
1706         }
1707         else if( ( (thing->frame & (FF_FULLBRIGHT|FF_TRANSMASK))
1708                    || (thing->flags & MF_SHADOW) )
1709                  && (!vis->extra_colormap || !vis->extra_colormap->fog)  )
1710         {
1711             // full bright : goggles
1712             vis->colormap = & reg_colormaps[0];
1713         }
1714         else
1715         {
1716 
1717             // diminished light
1718             int index = xscale>>(LIGHTSCALESHIFT-detailshift);
1719 
1720             if (index >= MAXLIGHTSCALE)
1721                 index = MAXLIGHTSCALE-1;
1722 
1723             vis->colormap = spritelights[index];
1724         }
1725     }
1726 
1727     if(thingsector->numlights)
1728         R_Split_Sprite_over_FFloor(vis, thing);
1729 }
1730 
1731 
1732 
1733 
1734 //
1735 // R_AddSprites
1736 // During BSP traversal, this adds sprites by sector.
1737 //
R_AddSprites(sector_t * sec,int lightlevel)1738 void R_AddSprites (sector_t* sec, int lightlevel)
1739 {
1740     mobj_t*   thing;
1741 
1742     if (rendermode != render_soft)
1743         return;
1744 
1745     // BSP is traversed by subsector.
1746     // A sector might have been split into several
1747     //  subsectors during BSP building.
1748     // Thus we check whether its already added.
1749     if (sec->validcount == validcount)
1750         return;
1751 
1752     // Well, now it will be done.
1753     sec->validcount = validcount;
1754 
1755     if(!sec->numlights)  // otherwise see ProjectSprite
1756     {
1757       if(sec->model < SM_fluid)   lightlevel = sec->lightlevel;
1758 
1759       lightlev_t  vlight = lightlevel + extralight;
1760 
1761       spritelights =
1762           (vlight < 0) ? scalelight[0]
1763         : (vlight >= 255) ? scalelight[LIGHTLEVELS-1]
1764         : scalelight[vlight>>LIGHTSEGSHIFT];
1765     }
1766 
1767     // Handle all things in sector.
1768     for (thing = sec->thinglist ; thing ; thing = thing->snext)
1769     {
1770         if((thing->flags2 & MF2_DONTDRAW)==0)
1771             R_ProjectSprite (thing);
1772     }
1773 }
1774 
1775 
1776 const int PSpriteSY[NUMWEAPONS] =
1777 {
1778      0,             // staff
1779      5*FRACUNIT,    // goldwand
1780     15*FRACUNIT,    // crossbow
1781     15*FRACUNIT,    // blaster
1782     15*FRACUNIT,    // skullrod
1783     15*FRACUNIT,    // phoenix rod
1784     15*FRACUNIT,    // mace
1785     15*FRACUNIT,    // gauntlets
1786     15*FRACUNIT     // beak
1787 };
1788 
1789 //
1790 // R_DrawPSprite, Draw one player sprite.
1791 //
1792 // Draw parts of the viewplayer weapon
R_DrawPSprite(pspdef_t * psp)1793 void R_DrawPSprite (pspdef_t* psp)
1794 {
1795     fixed_t             tx;
1796     int                 x1, x2, fr;
1797     spritedef_t*        sprdef;
1798 //    spriteframe_t*      sprframe;
1799     sprite_frot_t *     sprfrot;
1800     spritelump_t*       sprlump;
1801     vissprite_t*        vis;
1802     vissprite_t         avis;
1803 
1804     // [WDJ] 11/14/2012 use viewer variables, which will be for viewplayer
1805 
1806     // decide which patch to use
1807 #ifdef RANGECHECK
1808     if ( (unsigned)psp->state->sprite >= numsprites) {
1809         // [WDJ] Give msg and don't draw it, (** Heretic **)
1810         I_SoftError ("R_DrawPSprite: invalid sprite number %i\n",
1811                  psp->state->sprite);
1812         return;
1813     }
1814 #endif
1815 
1816     sprdef = &sprites[psp->state->sprite];
1817 
1818 #ifdef RANGECHECK
1819     if ( (psp->state->frame & FF_FRAMEMASK)  >= sprdef->numframes) {
1820         // [WDJ] Give msg and don't draw it
1821         I_SoftError ("R_DrawPSprite: invalid sprite frame %i : %i for %s\n",
1822                  psp->state->sprite, psp->state->frame, sprnames[psp->state->sprite]);
1823         return;
1824     }
1825 #endif
1826 
1827     // [WDJ] segfault control in heretic shareware, not all sprites present
1828     if( (byte*)sprdef->spriteframe < (byte*)0x1000 )
1829     {
1830         I_SoftError("R_DrawPSprite: sprframe ptr NULL for state %d\n", psp->state );
1831         return;
1832     }
1833 
1834     fr = psp->state->frame & FF_FRAMEMASK;
1835 //    sprframe = get_spriteframe( sprdef, fr );
1836 
1837     // use single rotation for all views
1838     sprfrot = get_framerotation( sprdef, fr, 0 );
1839 
1840     //Fab: see the notes in R_ProjectSprite about spritelump_id, pat_lumpnum
1841     sprlump = &spritelumps[sprfrot->spritelump_id];  // sprite patch header
1842 
1843     // calculate edges of the shape
1844 
1845     //added:08-01-98:replaced mul by shift
1846     tx = psp->sx-((BASEVIDWIDTH/2)<<FRACBITS); //*FRACUNITS);
1847 
1848     //added:02-02-98:spriteoffset should be abs coords for psprites, based on
1849     //               320x200
1850 #if 0
1851     // [WDJ] I don't think that weapon sprites need flip, but prboom
1852     // and prboom-plus are still supporting it, so maybe there are some.
1853     // There being one viewpoint per offset, probably do not need this.
1854     if( sprfrot->flip )
1855     {
1856         // debug_Printf("Player weapon flip detected!\n" );
1857         tx -= sprlump->width - sprlump->leftoffset;  // Fraggle's flip offset
1858     }
1859     else
1860     {
1861         // apply offset from sprite lump normally
1862         tx -= sprlump->leftoffset;
1863     }
1864 #else
1865     tx -= sprlump->leftoffset;
1866 #endif
1867     x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS;
1868 
1869     // off the right side
1870     if (x1 > rdraw_viewwidth)
1871         return;
1872 
1873     tx += sprlump->width;
1874     x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
1875 
1876     // off the left side
1877     if (x2 < 0)
1878         return;
1879 
1880     // store information in a vissprite
1881     vis = &avis;
1882     vis->mobj_flags = 0;
1883     vis->texturemid = (cv_splitscreen.EV) ?
1884         (120<<(FRACBITS)) + FRACUNIT/2 - (psp->sy - sprlump->topoffset)
1885         : (BASEYCENTER<<FRACBITS) + FRACUNIT/2 - (psp->sy - sprlump->topoffset);
1886 
1887     if( EN_heretic_hexen )
1888     {
1889         if( rdraw_viewheight == vid.height
1890             || (!cv_scalestatusbar.EV && vid.dupy>1) )
1891             vis->texturemid -= PSpriteSY[viewplayer->readyweapon];
1892     }
1893 
1894     //vis->texturemid += FRACUNIT/2;
1895 
1896     vis->x1 = (x1 < 0) ? 0 : x1;
1897     vis->x2 = (x2 >= rdraw_viewwidth) ? rdraw_viewwidth-1 : x2;
1898     vis->scale = pspriteyscale;  //<<detailshift;
1899 
1900     if( sprfrot->flip )
1901     {
1902         vis->tex_x_iscale = -pspriteiscale;
1903         vis->tex_x1 = sprlump->width - 1;
1904     }
1905     else
1906     {
1907         vis->tex_x_iscale = pspriteiscale;
1908         vis->tex_x1 = 0;
1909     }
1910 
1911     if (vis->x1 > x1)
1912         vis->tex_x1 += vis->tex_x_iscale * (vis->x1 - x1);
1913 
1914     //Fab: see above for more about spritelump_id,lumppat
1915     vis->patch_lumpnum = sprfrot->pat_lumpnum;
1916     vis->translucentmap = NULL;
1917     vis->translucent_index = 0;
1918     if (viewplayer->mo->flags & MF_SHADOW)      // invisibility effect
1919     {
1920         vis->colormap = NULL;   // use translucency
1921 
1922         // in Doom2, it used to switch between invis/opaque the last seconds
1923         // now it switch between invis/less invis the last seconds
1924         if (viewplayer->powers[pw_invisibility] > 4*TICRATE
1925                  || viewplayer->powers[pw_invisibility] & 8)
1926         {
1927             vis->translucent_index = TRANSLU_hi;
1928             vis->translucentmap = & translucenttables[ TRANSLU_TABLE_hi ];
1929         }
1930         else
1931         {
1932             vis->translucent_index = TRANSLU_med;
1933             vis->translucentmap = & translucenttables[ TRANSLU_TABLE_med ];
1934         }
1935     }
1936     else if (fixedcolormap)
1937     {
1938         // fixed color
1939         vis->colormap = fixedcolormap;
1940     }
1941     else if (psp->state->frame & FF_FULLBRIGHT)
1942     {
1943         // full bright
1944         vis->colormap = & reg_colormaps[0]; // [0]
1945     }
1946     else
1947     {
1948         // local light
1949         vis->colormap = spritelights[MAXLIGHTSCALE-1];
1950     }
1951 
1952     if(viewer_sector->numlights)
1953     {
1954       lightlev_t  vlight;  // 0..255
1955       ff_light_t * ff_light =
1956         R_GetPlaneLight(viewer_sector, viewmobj->z + (41 << FRACBITS));
1957       vis->extra_colormap = ff_light->extra_colormap;
1958       vlight = *ff_light->lightlevel + extralight;
1959 
1960       spritelights =
1961           (vlight < 0) ? scalelight[0]
1962         : (vlight >= 255) ? scalelight[LIGHTLEVELS-1]
1963         : scalelight[vlight>>LIGHTSEGSHIFT];
1964 
1965       vis->colormap = spritelights[MAXLIGHTSCALE-1];
1966     }
1967     else
1968       vis->extra_colormap = viewer_sector->extra_colormap;
1969 
1970     R_DrawVisSprite (vis, vis->x1, vis->x2);
1971 }
1972 
1973 
1974 
1975 //
1976 // R_DrawPlayerSprites
1977 //
1978 // Draw the viewplayer weapon, render_soft.
R_DrawPlayerSprites(void)1979 void R_DrawPlayerSprites (void)
1980 {
1981     int         i = 0;
1982     lightlev_t  vlight;  // visible light 0..255
1983     pspdef_t*   psp;
1984 
1985     int kikhak;
1986 
1987     // rendermode == render_soft
1988     // [WDJ] 11/14/2012 use viewer variables for viewplayer
1989 
1990     // get light level
1991     if(viewer_sector->numlights)
1992     {
1993       ff_light_t * ff_light =
1994         R_GetPlaneLight(viewer_sector, viewmobj->z + viewmobj->info->height);
1995       vlight = *ff_light->lightlevel + extralight;
1996     }
1997     else
1998       vlight = viewer_sector->lightlevel + extralight;
1999 
2000     spritelights =
2001         (vlight < 0) ? scalelight[0]
2002       : (vlight >= 255) ? scalelight[LIGHTLEVELS-1]
2003       : scalelight[vlight>>LIGHTSEGSHIFT];
2004 
2005     // clip to screen bounds
2006     dm_floorclip = clip_screen_bot_max;  // clip at bottom of screen
2007     dm_ceilingclip = clip_screen_top_min;  // clip at top of screen
2008 
2009     //added:06-02-98: quickie fix for psprite pos because of freelook
2010     kikhak = centery;
2011     centery = centerypsp;             //for R_DrawColumn
2012     centeryfrac = centery<<FRACBITS;  //for R_DrawVisSprite
2013 
2014     // add all active psprites
2015     for (i=0, psp=viewplayer->psprites;
2016          i<NUMPSPRITES;
2017          i++,psp++)
2018     {
2019         if (psp->state)
2020             R_DrawPSprite (psp);
2021     }
2022 
2023     //added:06-02-98: oooo dirty boy
2024     centery = kikhak;
2025     centeryfrac = centery<<FRACBITS;
2026 }
2027 
2028 
2029 
2030 // R_Create_DrawNodes
2031 // Creates and sorts a list of drawnodes for the scene being rendered.
2032 static void           R_Create_DrawNodes();
2033 static drawnode_t*    R_CreateDrawNode (drawnode_t* link);
2034 
2035 static drawnode_t     nodebankhead;
2036 static drawnode_t     nodehead;
2037 
2038 // called by R_DrawMasked
R_Create_DrawNodes(void)2039 static void R_Create_DrawNodes( void )
2040 {
2041   drawnode_t*   entry;
2042   drawseg_t*    ds;
2043   vissprite_t*  vsp;  // rover vissprite
2044   drawnode_t*   dnp;  // rover drawnode
2045   visplane_t*   plane;
2046   int           i, p, x1, x2;
2047   fixed_t       delta;
2048   int           sintersect;
2049 //  fixed_t       gzm;
2050   fixed_t       mobj_mid_z; // mid of sprite
2051   fixed_t       scale;
2052 
2053     // Add the 3D floors, thicksides, and masked textures...
2054     for(ds = ds_p; ds-- > drawsegs;)
2055     {
2056       if(ds->numthicksides)
2057       {
2058         for(i = 0; i < ds->numthicksides; i++)
2059         {
2060           entry = R_CreateDrawNode(&nodehead);
2061           entry->thickseg = ds;
2062           entry->ffloor = ds->thicksides[i];
2063         }
2064       }
2065       if(ds->maskedtexturecol)
2066       {
2067         entry = R_CreateDrawNode(&nodehead);
2068         entry->seg = ds;
2069       }
2070       if(ds->numffloorplanes)
2071       {
2072         // create drawnodes for the floorplanes with the closest last
2073         // [WDJ] Sort as they are put into the list.  This avoids repeating
2074         // searching through the same entries, PlaneBounds() and tests.
2075         drawnode_t * first_dnp = nodehead.prev; // previous last drawnode
2076         for(p = 0; p < ds->numffloorplanes; p++)
2077         {
2078             if(!ds->ffloorplanes[p])  // ignore NULL
2079               continue;
2080             plane = ds->ffloorplanes[p];
2081             ds->ffloorplanes[p] = NULL;  // remove from floorplanes
2082             R_PlaneBounds(plane);  // set highest_top, lowest_bottom
2083                  // in screen coord, where 0 is top (hi)
2084             // Drawable area is con_clipviewtop to (rdraw_viewheight - 1)
2085             if(plane->lowest_bottom < con_clipviewtop
2086                || plane->highest_top >= rdraw_viewheight  // [WDJ] rdraw window, not vid.height
2087                || plane->highest_top > plane->lowest_bottom)
2088             {
2089               continue;  // not visible, next plane
2090             }
2091             delta = abs(plane->height - viewz); // new entry distance
2092             // merge sort into the drawnode list
2093             dnp = first_dnp->next; // first plane, or nodehead
2094             while( dnp != &nodehead )  // until reach end of new entries
2095             {
2096                 // test for plane closer
2097                 // everything between first_dnp and nodehead must be plane
2098                 if(abs(dnp->plane->height - viewz) < delta)
2099                     break; // is farther than dnp
2100                 dnp = dnp->next; // towards closer, towards nodehead
2101             }
2102             // create new drawnode
2103             entry = R_CreateDrawNode(dnp); // before closer entry, or nodehead
2104             entry->plane = plane;
2105             entry->seg = ds;
2106         }
2107       }
2108     }
2109 
2110     if(vissprite_p == vissprites)  // empty sprite list
2111       return;
2112 
2113     // sprite list is sorted from vprsortedhead
2114     // traverse vissprite sorted list, nearest to farthest
2115     for(vsp = vsprsortedhead.prev; vsp != &vsprsortedhead; vsp = vsp->prev)
2116     {
2117       if(vsp->sz_top > vid.height || vsp->sz_bot < 0)
2118         continue;
2119 
2120       sintersect = (vsp->x1 + vsp->x2) / 2;
2121 //      gzm = (vsp->gz_bot + vsp->gz_top) / 2;
2122       mobj_mid_z = (vsp->mobj_bot_z + vsp->mobj_top_z) / 2;
2123 
2124       // search drawnodes
2125       // drawnodes are in bsp order, partially sorted
2126       for(dnp = nodehead.next; dnp != &nodehead; dnp = dnp->next)
2127       {
2128         if(dnp->plane)
2129         {
2130           // sprite vrs floor plane
2131           if(dnp->plane->minx > vsp->x2 || dnp->plane->maxx < vsp->x1)
2132             continue;  // next dnp
2133           if(vsp->sz_top > dnp->plane->lowest_bottom
2134              || vsp->sz_bot < dnp->plane->highest_top)
2135             continue;  // next dnp
2136 
2137           // [WDJ] test mid of sprite instead of toe and head
2138           // to avoid whole sprite affected by a marginal overlap
2139           if( dnp->plane->height < viewz )
2140           {
2141               // floor
2142               if( dnp->plane->height < mobj_mid_z )  continue;  // sprite over floor
2143           }
2144           else
2145           {
2146               // ceiling
2147               if( dnp->plane->height > mobj_mid_z )  continue;  // sprite under ceiling
2148           }
2149 
2150           {
2151             // SoM: NOTE: Because a visplane's shape and scale is not directly
2152             // bound to any single linedef, a simple poll of it's scale is
2153             // not adequate. We must check the entire scale array for any
2154             // part that is in front of the sprite.
2155 
2156             x1 = vsp->x1;
2157             x2 = vsp->x2;
2158             if(x1 < dnp->plane->minx) x1 = dnp->plane->minx;
2159             if(x2 > dnp->plane->maxx) x2 = dnp->plane->maxx;
2160 
2161             fixed_t * bsr = & dnp->seg->backscale_r[ x1 ];
2162             for(  ; bsr <= & dnp->seg->backscale_r[ x2 ]; bsr++)
2163             {
2164               // keeps sprite from being seen through floors
2165               if(*(bsr++) > vsp->scale)
2166               {
2167                   // this plane needs to be drawn after sprite
2168                   goto  dnp_closer_break;
2169               }
2170             }
2171             continue;  // next dnp
2172           }
2173         }
2174         else if(dnp->thickseg)
2175         {
2176           // sprite vrs 3d thickseg
2177           if(vsp->x1 > dnp->thickseg->x2 || vsp->x2 < dnp->thickseg->x1)
2178             continue;  // next dnp
2179 
2180           // max of scale1, scale2 (which is closest)
2181           scale = (dnp->thickseg->scale1 > dnp->thickseg->scale2) ? dnp->thickseg->scale1 : dnp->thickseg->scale2;
2182           if(scale <= vsp->scale)
2183             continue;  // next dnp
2184           scale = dnp->thickseg->scale1 + (dnp->thickseg->scalestep * (sintersect - dnp->thickseg->x1));
2185           if(scale <= vsp->scale)
2186             continue;  // next dnp
2187 
2188           if((*dnp->ffloor->topheight > viewz
2189                  && *dnp->ffloor->bottomheight < viewz)
2190              || (*dnp->ffloor->topheight < viewz
2191                  && vsp->gz_top < *dnp->ffloor->topheight)
2192              || (*dnp->ffloor->bottomheight > viewz
2193                  && vsp->gz_bot > *dnp->ffloor->bottomheight))
2194           {
2195             // thickseg is closer, must be drawn after sprite
2196             goto  dnp_closer_break;
2197           }
2198         }
2199         else if(dnp->seg)
2200         {
2201           // sprite vrs seg
2202           if(vsp->x1 > dnp->seg->x2 || vsp->x2 < dnp->seg->x1)
2203             continue;  // next dnp
2204 
2205           scale = dnp->seg->scale1 > dnp->seg->scale2 ? dnp->seg->scale1 : dnp->seg->scale2;
2206           if(scale <= vsp->scale)
2207             continue;  // next dnp
2208           scale = dnp->seg->scale1 + (dnp->seg->scalestep * (sintersect - dnp->seg->x1));
2209 
2210           if(vsp->scale < scale)
2211           {
2212             goto  dnp_closer_break;
2213           }
2214         }
2215         else if(dnp->sprite)
2216         {
2217           // sprite vrs sprite
2218           if(dnp->sprite->x1 > vsp->x2 || dnp->sprite->x2 < vsp->x1)
2219             continue;  // next dnp
2220           if(dnp->sprite->sz_top > vsp->sz_bot || dnp->sprite->sz_bot < vsp->sz_top)
2221             continue;  // next dnp
2222 
2223           if(dnp->sprite->scale > vsp->scale)
2224           {
2225             goto  dnp_closer_break;
2226           }
2227         }
2228         continue;  // next dnp
2229       }
2230       // end of dnp
2231 
2232       if(dnp == &nodehead)
2233       {
2234         // end of list, draw in front of everything else
2235         entry = R_CreateDrawNode(&nodehead);
2236         entry->sprite = vsp;
2237       }
2238       continue; // next vsp
2239 
2240     dnp_closer_break:
2241       // enter sprite after dnp
2242       entry = R_CreateDrawNode(NULL);
2243       (entry->prev = dnp->prev)->next = entry;
2244       (entry->next = dnp)->prev = entry;
2245       entry->sprite = vsp;
2246     }  // for vsp
2247 }
2248 
2249 
2250 // called by R_Create_DrawNodes
R_CreateDrawNode(drawnode_t * link)2251 static drawnode_t* R_CreateDrawNode (drawnode_t* link)
2252 {
2253   drawnode_t* node;
2254 
2255   node = nodebankhead.next;
2256   if(node == &nodebankhead)
2257   {
2258     node = malloc(sizeof(drawnode_t));
2259   }
2260   else
2261     (nodebankhead.next = node->next)->prev = &nodebankhead;
2262 
2263   if(link)
2264   {
2265     node->next = link;
2266     node->prev = link->prev;
2267     link->prev->next = node;
2268     link->prev = node;
2269   }
2270 
2271   node->plane = NULL;
2272   node->seg = NULL;
2273   node->thickseg = NULL;
2274   node->ffloor = NULL;
2275   node->sprite = NULL;
2276   return node;
2277 }
2278 
2279 
2280 
R_DoneWithNode(drawnode_t * node)2281 static void R_DoneWithNode(drawnode_t* node)
2282 {
2283   (node->next->prev = node->prev)->next = node->next;
2284   (node->next = nodebankhead.next)->prev = node;
2285   (node->prev = &nodebankhead)->next = node;
2286 }
2287 
2288 
2289 
R_Clear_DrawNodes()2290 static void R_Clear_DrawNodes()
2291 {
2292   drawnode_t* dnp; // rover drawnode
2293   drawnode_t* next;
2294 
2295   for(dnp = nodehead.next; dnp != &nodehead; )
2296   {
2297     next = dnp->next;
2298     R_DoneWithNode(dnp);
2299     dnp = next;
2300   }
2301 
2302   nodehead.next = nodehead.prev = &nodehead;
2303 }
2304 
2305 
2306 
R_Init_DrawNodes()2307 void R_Init_DrawNodes()
2308 {
2309   nodebankhead.next = nodebankhead.prev = &nodebankhead;
2310   nodehead.next = nodehead.prev = &nodehead;
2311 }
2312 
2313 
2314 // =======
2315 //  Corona
2316 
2317 static patch_t *  corona_patch = NULL;
2318 static spritelump_t  corona_sprlump;
2319 
2320 // One or the other.
2321 #ifdef ENABLE_DRAW_ALPHA
2322 #else
2323 #define ENABLE_COLORED_PATCH
2324 // [WDJ] Wad patches usable as corona.
2325 // It is easier to recolor during drawing than to pick one of each.
2326 // Only use patches that are likely to be round in every instance (teleport fog is often not round).
2327 // Corona alternatives list.
2328 const char * corona_name[] = {
2329   "CORONAP",  // patch version of corona, from legacy.wad
2330   "PLSEA0", "PLSSA0", "APBXA0",  // Doom1, Doom2
2331 //  "AMB2A0", "PUF2A0", "FX01A0",  // Heretic
2332   "PUF2A0", "FX01A0",  // Heretic
2333   NULL
2334 };
2335 #endif
2336 
2337 
2338 #ifdef ENABLE_COLORED_PATCH
2339 static int corona_patch_size = 0;
2340 
2341 typedef struct {
2342     RGBA_t  corona_color;
2343     patch_t * colored_patch;  // Z_Malloc
2344 } corona_image_t;
2345 
2346 static corona_image_t  corona_image[NUMLIGHTS];
2347 #endif
2348 
2349 // Also does release, after corona_patch_size is set.
2350 static
init_corona_data(void)2351 void init_corona_data( void )
2352 {
2353 #ifdef ENABLE_DRAW_ALPHA
2354 #endif
2355 
2356 #ifdef ENABLE_COLORED_PATCH
2357     int i;
2358     for( i = 0; i< NUMLIGHTS; i++ )
2359     {
2360         if( corona_patch_size )
2361         {
2362             if( corona_image[i].colored_patch )
2363                 Z_Free( corona_image[i].colored_patch );
2364         }
2365         corona_image[i].corona_color.rgba = 0;
2366         corona_image[i].colored_patch = NULL;
2367     }
2368 #endif
2369 }
2370 
2371 #ifdef ENABLE_COLORED_PATCH
2372 static
setup_colored_corona(corona_image_t * ccp,RGBA_t corona_color)2373 void setup_colored_corona( corona_image_t * ccp, RGBA_t corona_color )
2374 {
2375     byte  colormap[256];
2376     patch_t * pp;
2377 
2378     // when draw alpha is intense cannot have faint color in corona image
2379     int alpha = (255 + corona_color.s.alpha) >> 1;
2380     int za = (255 - alpha);
2381     int c;
2382 
2383     // A temporary colormap
2384     for( c = 0; c<256; c++ )
2385     {
2386         // make a colormap that is mostly of the corona color
2387         RGBA_t rc = pLocalPalette[ reg_colormaps[c] ];
2388         int r = (corona_color.s.red * alpha + rc.s.red * za) >> 8;
2389         int g = (corona_color.s.green * alpha + rc.s.green * za) >> 8;
2390         int b = (corona_color.s.blue * alpha + rc.s.blue * za) >> 8;
2391         colormap[c] = NearestColor( r, g, b );
2392     }
2393 
2394     // Allocate a copy of the corona patch.
2395     ccp->corona_color = corona_color;
2396     if( ccp->colored_patch )
2397         Z_Free( ccp->colored_patch );
2398     pp = Z_Malloc( corona_patch_size, PU_STATIC, NULL );
2399     ccp->colored_patch = pp;
2400     memcpy( pp, corona_patch, corona_patch_size );
2401 
2402     // Change the corona copy to the corona color.
2403     for( c=0; c < corona_patch->width; c++ )
2404     {
2405         column_t * cp = (column_t*)((byte*)pp + pp->columnofs[c]);
2406         while( cp->topdelta != 0xff )  // end of posts
2407         {
2408             byte * s = (byte*)cp + 3;
2409             int count = cp->length;
2410             while( count-- )
2411             {
2412                 *s = colormap[*s];
2413                 s++;
2414             }
2415             // next source post, adv by (length + 2 byte header + 2 extra bytes)
2416             cp = (column_t *)((byte *)cp + cp->length + 4);
2417         }
2418     }
2419 }
2420 
2421 static
get_colored_corona(int sprite_light_num)2422 patch_t * get_colored_corona( int sprite_light_num )
2423 {
2424     corona_image_t * cc = & corona_image[ sprite_light_num ];
2425     RGBA_t corona_color = sprite_light[ sprite_light_num ].corona_color;
2426 
2427     if( cc->corona_color.rgba != corona_color.rgba || cc->colored_patch == NULL )
2428     {
2429         setup_colored_corona( cc, corona_color );
2430     }
2431 
2432     return  cc->colored_patch;
2433 }
2434 #endif
2435 
2436 
2437 
2438 // Called by SCR_SetMode
R_Load_Corona(void)2439 void R_Load_Corona( void )
2440 {
2441 #ifdef ENABLE_COLORED_PATCH
2442     lumpnum_t  lumpid;
2443 #endif
2444 
2445     Setup_sprite_light( cv_monball_light.EV );
2446 
2447     // must call at least once, before setting corona_patch_size
2448     init_corona_data();
2449 
2450 #ifdef HWRENDER
2451     if( rendermode != render_soft )
2452     {
2453         return;
2454     }
2455 #endif
2456 
2457 #ifdef ENABLE_DRAW_ALPHA
2458     if( ! corona_patch )
2459     {
2460         pic_t * corona_pic = (pic_t*) W_CachePicName( "corona", PU_STATIC );
2461         if( corona_pic )
2462         {
2463             // Z_Malloc
2464             // The corona pic is INTENSITY_ALPHA, bytepp=2, blank=0
2465             corona_patch = (patch_t*) R_Create_Patch( corona_pic->width, corona_pic->height,
2466                 /*SRC*/    TM_row_image, & corona_pic->data[0], 2, 1, 0,
2467                 /*DEST*/   TM_patch, CPO_blank_trim, NULL );
2468             Z_ChangeTag( corona_patch, PU_STATIC );
2469             corona_patch->leftoffset += corona_pic->width/2;
2470             corona_patch->topoffset += corona_pic->height/2;
2471             // Do not need the corona pic_t anymore
2472             Z_Free( corona_pic );
2473             goto setup_corona;
2474         }
2475     }
2476 #endif
2477 
2478 #ifdef ENABLE_COLORED_PATCH
2479     if( ! corona_patch )
2480     {
2481         // Find first valid patch in corona_name list
2482         const char ** namep = &corona_name[0];
2483         while( *namep )
2484         {
2485             lumpid = W_Check_Namespace( *namep, LNS_patch );
2486             if( VALID_LUMP(lumpid) )  goto setup_corona;
2487             namep++;
2488         }
2489     }
2490 #endif
2491     return; // fail
2492 
2493 setup_corona :
2494 #ifdef ENABLE_COLORED_PATCH
2495     // setup the corona support
2496     corona_patch_size = W_LumpLength( lumpid );
2497     corona_patch = W_CachePatchNum( lumpid, PU_STATIC );
2498 #endif
2499 
2500     // The patch endian conversion is already done.
2501     corona_sprlump.width = corona_patch->width << FRACBITS;
2502     corona_sprlump.height = corona_patch->height << FRACBITS;
2503     corona_sprlump.leftoffset = corona_patch->leftoffset << FRACBITS;
2504     corona_sprlump.topoffset = corona_patch->topoffset << FRACBITS;
2505     return;
2506 }
2507 
2508 
R_Release_Corona(void)2509 void R_Release_Corona( void )
2510 {
2511     init_corona_data( );  // does release too
2512 
2513     if( corona_patch )
2514     {
2515         Z_Free( corona_patch );
2516         corona_patch = NULL;
2517     }
2518 }
2519 
2520 // Propotional fade of corona from Z1 to Z2
2521 #define  Z1  (250.0f)
2522 #define  Z2  ((255.0f*8) + 250.0f)
2523 
2524 #ifdef SPDR_CORONAS
2525 // --------------------------------------------------------------------------
2526 // coronas lighting with the sprite
2527 // --------------------------------------------------------------------------
2528 
2529 // corona state
2530 spr_light_t  * corona_lsp = NULL;
2531 fixed_t   corona_x0, corona_x1, corona_x2;
2532 fixed_t   corona_xscale, corona_yscale;
2533 float     corona_size;
2534 byte      corona_alpha;
2535 byte      corona_bright; // used by software draw to brighten active light sources
2536 byte      corona_index;  // corona_lsp index
2537 byte      corona_draw = 0;  // 1 = before sprite, 2 = after sprite
2538 
2539 byte spec_dist[ 16 ] = {
2540   10,  // SPLT_unk
2541   35,  // SPLT_rocket
2542   20,  // SPLT_lamp
2543   45,  // SPLT_fire
2544    0, 0, 0, 0, 0, 0, 0, 0,
2545   60,  // SPLT_light
2546   30,  // SPLT_firefly
2547   80,  // SPLT_random
2548   80,  // SPLT_pulse
2549 };
2550 
2551 typedef enum {
2552    FADE_FAR = 0x01,
2553    FADE_NEAR = 0x02
2554 } sprite_corona_fade_e;
2555 
2556 #define  NUM_FIRE_PATTERN  64
2557 static  int8_t  fire_pattern[ NUM_FIRE_PATTERN ];
2558 static  byte  fire_pattern_tic[ NUM_FIRE_PATTERN ];
2559 
2560 #define  NUM_RAND_PATTERN  32
2561 static  byte  rand_pattern_cnt[ NUM_RAND_PATTERN ];
2562 static  byte  rand_pattern_state[ NUM_RAND_PATTERN ];
2563 static  byte  rand_pattern_tic[ NUM_RAND_PATTERN ];
2564 
2565 //  sprnum : sprite number
2566 //
2567 //  Return: corona_index, corona_lsp
2568 //  Return NULL when no draw.
Sprite_Corona_Light_lsp(int sprnum,state_t * sprstate)2569 spr_light_t *  Sprite_Corona_Light_lsp( int sprnum, state_t * sprstate )
2570 {
2571     spr_light_t  * lsp;
2572 
2573     // Sprite explosion, light substitution
2574     byte li = sprite_light_ind[sprnum];
2575     if( (sprstate >= &states[S_EXPLODE1]
2576          && sprstate <= &states[S_EXPLODE3])
2577      || (sprstate >= &states[S_FATSHOTX1]
2578          && sprstate <= &states[S_FATSHOTX3]))
2579     {
2580         li = LT_ROCKETEXP;
2581     }
2582 
2583     corona_index = li;
2584     if( li == LT_NOLIGHT )  return NULL;
2585 
2586     lsp = &sprite_light[li];
2587     corona_lsp = lsp;
2588 
2589     return lsp;
2590 }
2591 
2592 //  lsp : sprite light
2593 //  cz : distance to corona
2594 //
2595 //  Return: corona_alpha, corona_size
2596 //  Return 0 when no draw.
Sprite_Corona_Light_fade(spr_light_t * lsp,float cz,int objid)2597 byte  Sprite_Corona_Light_fade( spr_light_t * lsp, float cz, int objid )
2598 {
2599     float  relsize;
2600     uint16_t  type, cflags;
2601     byte   fade;
2602     unsigned int index, v;
2603 
2604     // Objects which emit light.
2605     type = lsp->impl_flags & SPLT_type_field;  // working type setting
2606     cflags = lsp->splgt_flags;
2607     corona_alpha = lsp->corona_color.s.alpha;
2608     corona_bright = 0;
2609 
2610     // Update flagged by corona setting change, and fragglescript settings.
2611     if( lsp->impl_flags & SLI_changed )
2612     {
2613         lsp->impl_flags &= ~SLI_changed;
2614 
2615         // [WDJ] Fixes must be determined here because Phobiata and other wads,
2616         // do not set all the dependent fields at one time.
2617         // They never set some fields, like type, at all.
2618 
2619         type = cflags & SPLT_type_field;  // table or fragglescript setting
2620 
2621         if( cv_corona.EV == 20 )  // Old
2622         {
2623             // Revert the new tables to use
2624             // only that flags that existed in Old.
2625             cflags &= (SPLGT_corona|SPLGT_dynamic);
2626             if( type != SPLT_rocket )
2627             {
2628                if( cflags & SPLGT_dynamic )
2629                   type = SPLT_lamp;  // closest to old SPLGT_light
2630                else
2631                   type = SPLT_unk;  // corona only
2632             }
2633         }
2634         else
2635 
2636         // We have no way of determining the intended version compatibility.  This limits
2637         // the characteristics that we can check.
2638         // Some older wads just used the existing corona without setting the type.
2639         // The default type of some of the existing corona have changed to use the new
2640         // corona types for ordinary wads, version 1.47.3.
2641         if( (lsp->impl_flags & SLI_corona_set)  // set by fragglescript
2642             && ( !(lsp->impl_flags & SLI_type_set) || (type == SPLT_unk) ) )
2643         {
2644             // Correct corona settings made by older wads, such as Phobiata, and newmaps.
2645             // Has the old default type, or type was never set.
2646 #if 0
2647             // In the original code, the alpha from the corona color was ignored,
2648             // even though it was set in the tables.  Instead the draw code used 0xff.
2649             if( corona_alpha == 0 )
2650                 corona_alpha = lsp->corona_color.s.alpha = 0xff; // previous default
2651 #endif
2652 
2653             // Refine some of the old wad settings, to use new capabilities correctly.
2654             // Check for Phobiata and newmaps problems.
2655             if( corona_alpha > 0xDF )
2656             {
2657                 // Default radius is 20 to 120.
2658                 // Phobiata flies have a radius of 7
2659                 if( lsp->corona_radius < 10.0f )
2660                 {
2661                     // newmaps and phobiata firefly
2662                     type = SPLT_light;
2663                 }
2664                 else if( lsp->corona_radius < 80.0f )
2665                 {
2666                     // torches
2667                     type = SPLT_lamp;
2668                 }
2669             }
2670         }
2671         // update the working type
2672         lsp->impl_flags = (lsp->impl_flags & ~SPLT_type_field) | type;
2673     }
2674 
2675     if( (type == SPLT_unk) && !(cflags & SPLGT_corona) )
2676         goto no_corona;  // no corona set
2677 
2678     if( corona_alpha < 3 )
2679         goto no_corona;  // too faint to see, effectively off
2680 
2681     if( cv_corona.EV == 20 )  // Old
2682     {
2683         // alpha settings were ignored
2684         corona_alpha = 0xff;
2685     }
2686     else if( cv_corona.EV == 16 )  // Bright
2687     {
2688         corona_bright = 20;  // brighten the default cases
2689         corona_alpha = (((int)corona_alpha * 3) + 255) >> 2; // +25%
2690     }
2691     else if( cv_corona.EV == 14 )  // Dim
2692     {
2693         corona_alpha = ((int)corona_alpha * 3) >> 2; // -25%
2694     }
2695     else if( cv_corona.EV <= 2 )  // Special, Most
2696     {
2697         int spec = spec_dist[type>>4];
2698 
2699         if( lsp->impl_flags & SLI_corona_set )  // set by wad
2700             spec <<= 2;
2701 
2702         if( cv_corona.EV == 2 )  // Most
2703         {
2704             // Must do this before any flicker modifications, or else they blink.
2705             if( corona_alpha < 40 )  // ignore the dim corona
2706                 goto no_corona;
2707             if( corona_alpha + spec + Z1 < cz )
2708                 goto no_corona;  // not close enough
2709         }
2710         else
2711         {
2712             if( (spec < 33) && ( cz > (Z1+Z2)/2 ) )
2713                 goto no_corona; // not special enough
2714             if( corona_alpha < 20 )  // ignore the dim corona
2715                 goto no_corona;
2716         }
2717     }
2718 
2719     relsize = 1.0f;
2720     fade = FADE_FAR | FADE_NEAR;
2721 
2722     // Each of these types has a corona.
2723     switch( type )
2724     {
2725       case SPLT_unk: // corona only
2726         // object corona
2727         relsize = ((cz+60.0f)/100.0f);
2728         break;
2729       case SPLT_rocket: // flicker
2730         // svary the alpha
2731         relsize = ((cz+60.0f)/100.0f);
2732         corona_alpha = 7 + (A_Random()>>1);
2733         corona_bright = 128;
2734         break;
2735       case SPLT_lamp:  // lamp with a corona
2736         // lamp corona
2737         relsize = ((cz+120.0f)/950.0f);
2738         corona_bright = 40;
2739         break;
2740       case SPLT_fire: // slow flicker, torch
2741         // torches
2742         relsize = ((cz+120.0f)/950.0f);
2743         index = objid & (NUM_FIRE_PATTERN - 1);  // obj dependent
2744         if( fire_pattern_tic[ index ] != gametic )
2745         {
2746             fire_pattern_tic[ index ] = gametic;
2747             if( A_Random() > 35 )
2748             {
2749                 register int r = A_Random();
2750                 r = ((r - 128) >> 3) + fire_pattern[index];
2751                 if( r > 50 )  r = 40;
2752                 else if( r < -50 )  r = -40;
2753                 fire_pattern[index] = r;
2754             }
2755         }
2756         v = (int)corona_alpha + (int)fire_pattern[index];
2757         if( v > 255 )  v = 255;
2758         if( v < 4 )    v = 4;
2759         corona_alpha = v;
2760         corona_bright = 45;
2761         break;
2762       case SPLT_light: // no corona fade
2763         // newmaps and phobiata firefly
2764         // dimming with distance
2765         relsize = ((cz+120.0f)/950.0f);
2766 #if 0
2767         if( ( cz < Z1 ) & ((lsp->splgt_flags & SPLGT_source) == 0 ))
2768         {
2769             // Fade corona partial to 0 when get too close
2770             corona_alpha = (int)(( (float)corona_alpha * corona_alpha + (255 - corona_alpha) * (corona_alpha * cz / Z1)) / 255.0f);
2771         }
2772 #endif
2773         // Version 1.42 had corona_alpha = 0xff
2774         corona_bright = 132;
2775         fade = FADE_FAR;
2776         break;
2777       case SPLT_firefly: // firefly blink, un-synch
2778         // lower 6 bits gives a repeat rate of 1.78 seconds
2779         if( ((gametic + objid) & 0x003F) < 0x20 )   // obj dependent phase
2780           goto no_corona; // blink off
2781         fade = FADE_FAR;
2782         break;
2783       case SPLT_random: // random LED, un-synch
2784         index = objid & (NUM_RAND_PATTERN-1);   // obj dependent counter
2785         if( rand_pattern_tic[ index ] != gametic )
2786         {
2787             rand_pattern_tic[ index ] = gametic;
2788             if( rand_pattern_cnt[ index ] == 0 )
2789             {
2790                 rand_pattern_cnt[ index ] = A_Random();
2791                 rand_pattern_state[ index ] ++;
2792             }
2793             rand_pattern_cnt[ index ] --;
2794         }
2795         if( (rand_pattern_state[ index ] & 1) == 0 )
2796           goto no_corona; // off
2797         corona_bright = 128;
2798         fade = 0;
2799         break;
2800       case SPLT_pulse: // slow pulsation, un-synch
2801         index = (gametic + objid) & 0xFF;  // obj dependent phase
2802         index -= 128; // -128 to +127
2803         // Make a positive parabola pulse, min does not quite reach 0.
2804         register float f = 1.0f - ((index*index) * 0.000055f);
2805         relsize = f;
2806         corona_alpha = corona_alpha * f;
2807         corona_bright = 80;
2808         fade = 0;
2809         break;
2810       default:
2811         I_SoftError("Draw_Sprite_Corona_Light: unknown light type %x", type);
2812         goto no_corona;
2813     }
2814 
2815     if( cz > Z1 )
2816     {
2817         if( fade & FADE_FAR )
2818         {
2819             // Proportional fade from Z1 to Z2
2820             corona_alpha = (int)( corona_alpha * ( Z2 - cz ) / ( Z2 - Z1 ));
2821         }
2822     }
2823     else if( fade & FADE_NEAR )
2824     {
2825         // Fade to 0 when get too close
2826         corona_alpha = (int)( corona_alpha *  cz / Z1 );
2827     }
2828 
2829     if (relsize > 1.0)
2830         relsize = 1.0;
2831     corona_size = lsp->corona_radius * relsize * FIXED_TO_FLOAT( cv_coronasize.value );
2832     return corona_alpha;
2833 
2834 no_corona:
2835    corona_alpha = 0;
2836    return 0;
2837 }
2838 
2839 
2840 static
Sprite_Corona_Light_setup(vissprite_t * vis)2841 void Sprite_Corona_Light_setup( vissprite_t * vis )
2842 {
2843     mobj_t       * vismobj = vis->mobj;
2844     spr_light_t  * lsp;
2845 
2846     lsp = Sprite_Corona_Light_lsp( vismobj->sprite, vismobj->state );
2847     if( lsp == NULL )  goto no_corona;
2848 
2849     // Objects which emit light.
2850     if( (lsp->splgt_flags & (SPLGT_corona|SPLT_type_field)) == 0  )  goto no_corona;
2851 
2852     fixed_t tz = FixedDiv( projectiony, vis->scale );
2853     float cz = FIXED_TO_FLOAT( tz );
2854     // more realistique corona !
2855     if( cz >= Z2 )  goto no_corona;
2856 
2857     int mobjid = (uintptr_t)vismobj; // mobj dependent id
2858     if( Sprite_Corona_Light_fade( lsp, cz, mobjid>>1 ) == 0 )  goto no_corona;
2859 
2860     if( corona_bright )
2861     {
2862         // brighten the corona for software draw
2863         corona_alpha = (((int)corona_alpha * (255 - corona_bright)) + (255 * (int)corona_bright)) >> 8;
2864     }
2865 
2866     float size = corona_size / FIXED_TO_FLOAT(corona_sprlump.width);
2867     corona_xscale = (int)( (double)vis->xscale * size );
2868     corona_yscale = (int)( (double)vis->scale * size );
2869 
2870     // Corona specific.
2871     // Corona offsets are from center of drawn sprite.
2872     // no flip on corona
2873 
2874     // Position of the corona
2875 # if 1
2876     fixed_t  midx = (vis->x1 + vis->x2) << (FRACBITS-1);  // screen
2877 # else
2878     // same as spr, but not stored in vissprite so must recalculate it
2879 //    fixed_t tr_x = vismobj->x - viewx;
2880 //    fixed_t tr_y = vismobj->y - viewy;
2881     fixed_t tr_x = vis->mobj_x - viewx;
2882     fixed_t tr_y = vis->mobj_y - viewy;
2883     fixed_t  tx = (FixedMul(tr_x,viewsin) - FixedMul(tr_y,viewcos));
2884     fixed_t  midx = centerxfrac + FixedMul(tx, vis->xscale);
2885 # endif
2886     corona_x0 = corona_x1 = (midx - FixedMul(corona_sprlump.leftoffset, corona_xscale)) >>FRACBITS;
2887     corona_x2 = ((midx + FixedMul(corona_sprlump.width - corona_sprlump.leftoffset, corona_xscale)) >>FRACBITS) - 1;
2888     if( corona_x1 < 0 )  corona_x1 = 0;
2889     if( corona_x1 > rdraw_viewwidth )  goto no_corona;  // off the right side
2890     if( corona_x2 >= rdraw_viewwidth )  corona_x2 = rdraw_viewwidth - 1;
2891     if( corona_x2 < 0 )  goto no_corona;  //  off the left side
2892 
2893     corona_draw = 2;
2894     return;
2895 
2896 no_corona:
2897     corona_draw = 0;
2898     return;
2899 }
2900 
2901 
2902 
2903 static
Draw_Sprite_Corona_Light(vissprite_t * vis)2904 void Draw_Sprite_Corona_Light( vissprite_t * vis )
2905 {
2906     int            texturecolumn;
2907 
2908     // Sprite has a corona, and coronas are enabled.
2909     dr_alpha = (((int)corona_alpha * 7) + (2 * (16-7))) >> 4; // compensate for different HWR alpha
2910 
2911 #ifdef ENABLE_DRAW_ALPHA
2912     colfunc = alpha_colfunc;  // R_DrawAlphaColumn
2913     patch_t * corona_cc_patch = corona_patch;
2914     dr_color = corona_lsp->corona_color;
2915 # ifndef ENABLE_DRAW8_USING_12
2916     if( vid.drawmode == DRAW8PAL )
2917     {
2918         dr_color8 = NearestColor( dr_color.s.red, dr_color.s.green, dr_color.s.blue);
2919     }
2920 # endif
2921     dr_alpha_mode = cv_corona_draw_mode.EV;
2922     // alpha to dim the background through the corona
2923     dr_alpha_background = (cv_corona_draw_mode.EV == 1)? (255 - dr_alpha) : 240;
2924 #else
2925     colfunc = transcolfunc;  // R_DrawTranslucentColumn
2926     // Get the corona patch specifically colored for this light.
2927     patch_t * corona_cc_patch = get_colored_corona( corona_index );
2928 //    dc_colormap = & reg_colormaps[0];
2929     dc_translucent_index = 0;  // translucent dr_alpha
2930     dc_translucentmap = & translucenttables[ translucent_alpha_table[dr_alpha >> 4] ];  // for draw8
2931 #endif
2932 
2933     fixed_t light_yoffset = (int)(corona_lsp->light_yoffset * FRACUNIT); // float to fixed
2934 
2935 #if 1
2936     // [WDJ] This is the one that puts the center closest to where OpenGL puts it.
2937     fixed_t g_midy = (vis->gz_bot + vis->gz_top)>>1;  // mid of sprite
2938 #else
2939     // Too high
2940     mobj_t * vismobj = vis->mobj;
2941 #if 0
2942     fixed_t g_midy = vismobj->z + ((vis->gz_top - vis->gz_bot)>>1);
2943 #else
2944     fixed_t g_midy = (vismobj->z + vis->gz_top)>>1;  // mid of sprite
2945 #endif
2946 #endif
2947     fixed_t g_cp = g_midy + light_yoffset - viewz;  // corona center point in vissprite scale
2948     fixed_t tp_cp = FixedMul(g_cp, vis->scale) + FixedMul(corona_sprlump.topoffset, corona_yscale);
2949     dm_top_patch = centeryfrac - tp_cp;
2950     dm_texturemid = FixedDiv( tp_cp, corona_yscale );
2951     dm_yscale = corona_yscale;
2952     dc_iscale = FixedDiv (FRACUNIT, dm_yscale);  // y texture step
2953     dc_texheight = 0;  // no wrap repeat
2954 //    dc_texheight = corona_patch->height;
2955 
2956 
2957 // not flipped so
2958 //  tex_x1 = 0
2959 //  tex_x_iscale = iscale
2960 //    fixed_t tex_x_iscale = (int)( (double)vis->iscale * size );
2961     fixed_t tex_x_iscale = FixedDiv (FRACUNIT, corona_xscale);
2962     fixed_t texcol_frac = 0;  // tex_x1, not flipped
2963     if( (corona_x1 - corona_x0) > 0 )  // it was clipped
2964         texcol_frac = tex_x_iscale * (corona_x1 - corona_x0);
2965 
2966     for (dc_x=corona_x1 ; dc_x<=corona_x2 ; dc_x++, texcol_frac += tex_x_iscale)
2967     {
2968         texturecolumn = texcol_frac>>FRACBITS;
2969 #ifdef RANGECHECK
2970         if (texturecolumn < 0 || texturecolumn >= corona_patch->width) {
2971             // [WDJ] Give msg and don't draw it
2972             I_SoftError ("Sprite_Corona: bad texturecolumn\n");
2973             return;
2974         }
2975 #endif
2976         byte * col_data = ((byte *)corona_cc_patch) + corona_cc_patch->columnofs[texturecolumn];
2977         R_DrawMaskedColumn( col_data );
2978     }
2979 
2980     colfunc = basecolfunc;
2981 }
2982 #endif
2983 
2984 
2985 // ========
2986 // [WDJ] 2019 With the CLIP3 improvements.
2987 #define CLIPTOP_MIN   -2
2988 // Larger than any rdraw_viewheight.
2989 #define CLIPBOT_MAX   0x7FFE
2990 
2991 //
2992 // R_DrawSprite
2993 //
2994 //Fab:26-04-98:
2995 // NOTE : uses con_clipviewtop, so that when console is on,
2996 //        don't draw the part of sprites hidden under the console
R_DrawSprite(vissprite_t * spr)2997 void R_DrawSprite (vissprite_t* spr)
2998 {
2999     drawseg_t*          ds;
3000     // Clip limit is the last drawable row inside the drawable area.
3001     // This makes limit tests easier, not needing +1 or -1.
3002     short               clipbot[MAXVIDWIDTH];
3003     short               cliptop[MAXVIDWIDTH];
3004     int                 x;
3005     int                 r1, r2;
3006     int                 cx1, cx2; // clipping bounds
3007     fixed_t             c_scale;  // clipping scale
3008     fixed_t             ds_highscale, ds_lowscale;
3009     int                 silhouette;
3010     // clip the unclipped columns between console and status bar
3011     //Fab:26-04-98: was -1, now clips against console bottom
3012     // [WDJ] These clips are all of a constant value across the entire sprite.
3013     // One traverse of the clip array with the severest clip is sufficient.
3014     short  ht = con_clipviewtop;
3015     short  hb = rdraw_viewheight - 1;
3016 
3017     c_scale = spr->scale;
3018     cx1 = spr->x1;
3019     cx2 = spr->x2;
3020 
3021 #ifdef SPDR_CORONAS
3022     corona_draw = 0;
3023 #if 0
3024     // Exclude Split sprites that are cut on the bottom, so there
3025     // is only one corona per object.
3026     // Their position would be off too.
3027     if( cv_corona.EV
3028         && ( (spr->cut & SC_BOTTOM) == 0 ) )
3029 #else
3030     if( cv_corona.EV )
3031 #endif
3032     {
3033         // setup corona state
3034         Sprite_Corona_Light_setup( spr );  // set corona_draw
3035         if( corona_draw )
3036         {
3037             // Expand clipping to include corona draw
3038             if( corona_x1 < cx1 )   cx1 = corona_x1;
3039             if( corona_x2 > cx2 )   cx2 = corona_x2;
3040         }
3041     }
3042 #endif
3043 
3044     for (x = cx1 ; x <= cx2 ; x++)
3045     {
3046         cliptop[x] = CLIPTOP_MIN;
3047         clipbot[x] = CLIPBOT_MAX;
3048     }
3049 
3050     // Scan drawsegs from end to start for obscuring segs.
3051     // The first drawseg that has a greater scale is the clip seg.
3052     //SoM: 4/8/2000:
3053     // Pointer check was originally nonportable
3054     // and buggy, by going past LEFT end of array:
3055 
3056     //    for (ds=ds_p-1 ; ds >= drawsegs ; ds--)    old buggy code
3057     for (ds=ds_p ; ds-- > drawsegs ; )
3058     {
3059         if( (ds->silhouette == 0) && !ds->maskedtexturecol )
3060              continue;  // cannot clip sprite
3061 
3062         // determine if the drawseg obscures the sprite
3063         if(   ds->x1 > cx2
3064            || ds->x2 < cx1 )
3065         {
3066             // does not cover sprite
3067             continue;
3068         }
3069 
3070         // r1..r2 where drawseg overlaps sprite (intersect)
3071         r1 = ds->x1 < cx1 ? cx1 : ds->x1;  // max x1
3072         r2 = ds->x2 > cx2 ? cx2 : ds->x2;  // min x2
3073 
3074         // if( c_scale < ds->scale1 && c_scale < ds->scale2 )  continue; // ds is behind sprite
3075         // if( c_scale > ds->scale1 && c_scale > ds->scale2 )  clip; // ds is in front of sprite
3076         // (lowscale,scale) = minmax( ds->scale1, ds->scale2 )
3077         if (ds->scale1 > ds->scale2)
3078         {
3079             ds_lowscale = ds->scale2;
3080             ds_highscale = ds->scale1;
3081         }
3082         else
3083         {
3084             ds_lowscale = ds->scale1;
3085             ds_highscale = ds->scale2;
3086         }
3087 
3088         if (ds_highscale < c_scale
3089             || ( ds_lowscale < c_scale
3090                  && !R_PointOnSegSide (spr->mobj_x, spr->mobj_y, ds->curline) ) )
3091         {
3092             // masked mid texture?
3093             /*if (ds->maskedtexturecol)
3094                 R_RenderMaskedSegRange (ds, r1, r2);*/
3095             // seg is behind sprite
3096             continue;  // next drawseg
3097         }
3098 
3099         // clip this piece of the sprite
3100         silhouette = ds->silhouette;
3101 
3102         // check sprite bottom above clip height
3103         if (spr->gz_bot >= ds->sil_bottom_height)
3104             silhouette &= ~SIL_BOTTOM;
3105 
3106         // check sprite top above clip height
3107         if (spr->gz_top <= ds->sil_top_height)
3108             silhouette &= ~SIL_TOP;
3109 
3110         if (silhouette == SIL_BOTTOM)
3111         {
3112             // bottom sil
3113             for (x=r1 ; x<=r2 ; x++)
3114                 if (clipbot[x] == CLIPBOT_MAX)
3115                     clipbot[x] = ds->spr_bottomclip[x];
3116         }
3117         else if (silhouette == SIL_TOP)
3118         {
3119             // top sil
3120             for (x=r1 ; x<=r2 ; x++)
3121                 if (cliptop[x] == CLIPTOP_MIN)
3122                     cliptop[x] = ds->spr_topclip[x];
3123         }
3124         else if (silhouette == (SIL_BOTTOM|SIL_TOP))
3125         {
3126             // both
3127             for (x=r1 ; x<=r2 ; x++)
3128             {
3129                 if (clipbot[x] == CLIPBOT_MAX)
3130                     clipbot[x] = ds->spr_bottomclip[x];
3131                 if (cliptop[x] == CLIPTOP_MIN)
3132                     cliptop[x] = ds->spr_topclip[x];
3133             }
3134         }
3135     }
3136 
3137     //SoM: 3/17/2000: Clip sprites in water.
3138     // [WDJ] vissprite uses a heightsec, which is only used for selected modelsec.
3139     if( spr->modelsec >= 0 )  // only things in specially marked sectors, not colormaps
3140     {
3141         fixed_t h,mh;
3142         // model sector for special sector clipping
3143         sector_t * spr_heightsecp = & sectors[spr->modelsec];
3144 
3145         // beware, this test does two assigns to mh, and an assign to h
3146         if ((mh = spr_heightsecp->floorheight) > spr->gz_bot
3147             && (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0
3148             && (h >>= FRACBITS) < rdraw_viewheight)
3149         {
3150             // Assert: 0 <= h < rdraw_viewheight
3151             if (mh <= 0 || (viewer_has_model && !viewer_underwater))
3152             {                          // clip bottom
3153                 // water cut clips that cover x1..x2
3154                 if( h < hb )
3155                     hb = h;
3156             }
3157             else                        // clip top
3158             {
3159                 // water cut clips that cover x1..x2
3160                 if( h > ht )
3161                     ht = h;
3162             }
3163         }
3164 
3165         // beware, this test does an assign to mh, and an assign to h
3166         if ((mh = spr_heightsecp->ceilingheight) < spr->gz_top
3167             && (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0
3168             && (h >>= FRACBITS) < rdraw_viewheight)
3169         {
3170             // Assert: 0 <= h < rdraw_viewheight
3171             if (viewer_overceiling)
3172             {                         // clip bottom
3173                 // overceiling cut clips that cover x1..x2
3174                 if( h < hb )
3175                     hb = h;
3176             }
3177             else                       // clip top
3178             {
3179                 // water cut clips that cover x1..x2
3180                 if( h > ht )
3181                     ht = h;
3182             }
3183         }
3184     }
3185 
3186     // Sprite cut clips that cover x1..x2
3187     // This would work just as well without the SC_TOP and SC_BOTTOM tests.
3188     if( (spr->cut & SC_TOP)
3189        && spr->sz_top > ht )
3190             ht = spr->sz_top;  // a lower clip
3191     if( (spr->cut & SC_BOTTOM)
3192        && spr->sz_bot < hb )
3193             hb = spr->sz_bot;  // a higher clip
3194 
3195     // [WDJ] Act on most severe combined cut clips that cover x1..x2.
3196     // This now always clips to (0, rdraw_viewheight-1) or better.
3197     for(x = cx1; x <= cx2; x++)
3198     {
3199         if (hb < clipbot[x])  // OR CLIPBOT_MAX
3200             clipbot[x] = hb;
3201 
3202         if (ht > cliptop[x])  // OR CLIPTOP_MIN
3203             cliptop[x] = ht;
3204     }
3205 
3206     // All clipping has been performed, so draw the sprite.
3207     // [WDJ] No longer any need to check for unclipped columns.
3208 
3209     dm_floorclip = clipbot;
3210     dm_ceilingclip = cliptop;
3211 
3212 #if 0
3213 #ifdef SPDR_CORONAS
3214     if( corona_draw == 1 )
3215     {
3216         // Draw corona before sprite, occlude
3217         Draw_Sprite_Corona_Light( spr );
3218     }
3219 #endif
3220 #endif
3221 
3222     R_DrawVisSprite (spr, spr->x1, spr->x2);
3223 
3224 #ifdef SPDR_CORONAS
3225 //    if( corona_draw == 2 )
3226     if( corona_draw == 2  && ((spr->cut & 0x80) == 0) )
3227     {
3228         Draw_Sprite_Corona_Light( spr );
3229         spr->cut |= 0x80;
3230     }
3231 #endif
3232 }
3233 
3234 
3235 //
3236 // R_DrawMasked
3237 //
R_DrawMasked(void)3238 void R_DrawMasked (void)
3239 {
3240     drawnode_t*           r2;
3241     drawnode_t*           next;
3242 
3243     R_Create_DrawNodes();
3244 
3245     for(r2 = nodehead.next; r2 != &nodehead; r2 = r2->next)
3246     {
3247       if(r2->plane)
3248       {
3249         next = r2->prev;
3250         R_DrawSinglePlane(r2->plane);
3251         R_DoneWithNode(r2);
3252         r2 = next;
3253       }
3254       else if(r2->seg && r2->seg->maskedtexturecol != NULL)
3255       {
3256         next = r2->prev;
3257         R_RenderMaskedSegRange(r2->seg, r2->seg->x1, r2->seg->x2);
3258         r2->seg->maskedtexturecol = NULL;
3259         R_DoneWithNode(r2);
3260         r2 = next;
3261       }
3262       else if(r2->thickseg)
3263       {
3264         next = r2->prev;
3265         R_RenderThickSideRange(r2->thickseg, r2->thickseg->x1, r2->thickseg->x2, r2->ffloor);
3266         R_DoneWithNode(r2);
3267         r2 = next;
3268       }
3269       else if(r2->sprite)
3270       {
3271         next = r2->prev;
3272         R_DrawSprite(r2->sprite);
3273         R_DoneWithNode(r2);
3274         r2 = next;
3275       }
3276     }
3277     R_Clear_DrawNodes();
3278 }
3279 
3280 
3281 
3282 
3283 
3284 // ==========================================================================
3285 //
3286 //                              SKINS CODE
3287 //
3288 // ==========================================================================
3289 
3290 // This does not deallocate the skins memory.
3291 #define SKIN_ALLOC   8
3292 int         numskins = 0;
3293 skin_t *    skins[MAXSKINS+1];
3294 skin_t *    skin_free = NULL;
3295 skin_t      marine;
3296 
3297 
3298 static
get_skin_slot(void)3299 int  get_skin_slot(void)
3300 {
3301     skin_t * sk;
3302     int si, i;
3303 
3304     // Find unused skin slot, or add one.
3305     for(si=0; si<numskins; si++ )
3306     {
3307         if( skins[si] == NULL )  break;
3308     }
3309     if( si >= MAXSKINS )  goto none;
3310 
3311     // Get skin alloc.
3312     if( skin_free == NULL )
3313     {
3314         i = SKIN_ALLOC;
3315         sk = (skin_t*) malloc( sizeof(skin_t) * SKIN_ALLOC );
3316         if( sk == NULL )   goto none;
3317         // Link to free list
3318         while( i-- )
3319         {
3320             *(skin_t**)sk = skin_free;  // link
3321             skin_free = sk++;
3322         }
3323     }
3324 
3325     sk = skin_free;
3326     skin_free = *(skin_t**)sk;  // unlink
3327     skins[si] = sk;
3328     if( si >= numskins )  numskins = si+1;
3329     return si;
3330 
3331 none:
3332     return 0xFFFF;
3333 }
3334 
3335 static
free_skin(int skin_num)3336 void  free_skin( int skin_num )
3337 {
3338     skin_t * sk;
3339 
3340     if( skin_num >= MAXSKINS )  return;
3341     sk = skins[skin_num];
3342     if( sk == NULL )  return;
3343 
3344     skins[skin_num] = NULL;
3345     *(skin_t**)sk = skin_free;  // Link into free list
3346     skin_free = sk;
3347 
3348     while( numskins>0 && (skins[numskins-1] == NULL) )
3349     {
3350         numskins --;
3351     }
3352     // Cannot move existing skins
3353 }
3354 
3355 static
Skin_SetDefaultValue(skin_t * skin)3356 void Skin_SetDefaultValue(skin_t *skin)
3357 {
3358     int   i;
3359 
3360     // setup the 'marine' as default skin
3361     memset (skin, 0, sizeof(skin_t));
3362     strcpy (skin->name, DEFAULTSKIN);
3363     strcpy (skin->faceprefix, "STF");
3364     for (i=0;i<sfx_freeslot0;i++)
3365     {
3366         if (S_sfx[i].skinsound!=-1)
3367         {
3368             skin->soundsid[S_sfx[i].skinsound] = i;
3369         }
3370     }
3371 //    memcpy(&skin->spritedef, &sprites[SPR_PLAY], sizeof(spritedef_t));
3372 }
3373 
3374 //
3375 // Initialize the basic skins
3376 //
R_Init_Skins(void)3377 void R_Init_Skins (void)
3378 {
3379     skin_free = NULL;
3380 
3381     memset (skins, 0, sizeof(skins));
3382 
3383     // initialize free sfx slots for skin sounds
3384     S_InitRuntimeSounds ();
3385 
3386     // make the standard Doom2 marine as the default skin
3387     // skin[0] = marine skin
3388     skins[0] = & marine;
3389     Skin_SetDefaultValue( & marine );
3390     memcpy(&marine.spritedef, &sprites[SPR_PLAY], sizeof(spritedef_t));
3391     numskins = 1;
3392 }
3393 
3394 // Returns the skin index if the skin name is found (loaded from pwad).
3395 // Return 0 (the default skin) if not found.
R_SkinAvailable(const char * name)3396 int R_SkinAvailable (const char* name)
3397 {
3398     int  i;
3399 
3400     for (i=0;i<numskins;i++)
3401     {
3402         if( skins[i] && strcasecmp(skins[i]->name, name)==0)
3403             return i;
3404     }
3405     return 0;
3406 }
3407 
3408 
SetPlayerSkin_by_index(player_t * player,int index)3409 void SetPlayerSkin_by_index( player_t * player, int index )
3410 {
3411     skin_t * sk;
3412 
3413     if( index >= numskins )   goto default_skin;
3414 
3415     sk = skins[index];
3416     if( sk == NULL )   goto default_skin;
3417 
3418     // Change the face graphics
3419     if( player == &players[statusbarplayer]
3420         // for save time test it there is a real change
3421         && !( skins[player->skin] && strcmp (skins[player->skin]->faceprefix, sk->faceprefix)==0 )
3422         )
3423     {
3424         ST_Release_FaceGraphics();
3425         ST_Load_FaceGraphics(sk->faceprefix);
3426     }
3427 
3428 set_skin:
3429     // Record the player skin.
3430     player->skin = index;
3431 
3432     // A copy of the skin value so that dead body detached from
3433     // respawning player keeps the skin
3434     if( player->mo )
3435         player->mo->skin = sk;
3436     return;
3437 
3438 default_skin:
3439     index = 0;  // the old marine skin
3440     sk = &marine;
3441     goto set_skin;
3442 }
3443 
3444 
3445 // network code calls this when a 'skin change' is received
SetPlayerSkin(int playernum,const char * skinname)3446 void  SetPlayerSkin (int playernum, const char *skinname)
3447 {
3448     int   i;
3449 
3450     for(i=0;i<numskins;i++)
3451     {
3452         // search in the skin list
3453         if( skins[i] && strcasecmp(skins[i]->name,skinname)==0)
3454         {
3455             SetPlayerSkin_by_index( &players[playernum], i );
3456             return;
3457         }
3458     }
3459 
3460     GenPrintf(EMSG_warn, "Skin %s not found\n", skinname);
3461     // not found put the old marine skin
3462     SetPlayerSkin_by_index( &players[playernum], 0 );
3463 }
3464 
3465 
3466 //
3467 // Add skins from a pwad, each skin preceded by 'S_SKIN' marker
3468 //
3469 
3470 // Does the same as in w_wad, but check only for
3471 // the first 6 characters (this is so we can have S_SKIN1, S_SKIN2..
3472 // for wad editors that don't like multiple resources of the same name)
3473 //
3474 static
W_CheckForSkinMarkerInPwad(int wadid,int startlump)3475 int W_CheckForSkinMarkerInPwad (int wadid, int startlump)
3476 {
3477     lump_name_t name8;
3478     uint64_t mask6;  // big endian, little endian
3479     int  numlumps = wadfiles[wadid]->numlumps;
3480     lumpinfo_t * lumpinfo = wadfiles[wadid]->lumpinfo;
3481 
3482     name8.namecode = -1; // make 6 char mask
3483     name8.s[6] = name8.s[7] = 0;
3484     mask6 = name8.namecode;
3485 
3486     numerical_name( "S_SKIN", & name8 );  // fast compares
3487 
3488     // scan forward, start at <startlump>
3489     if( (startlump < numlumps) && lumpinfo )
3490     {
3491         lumpinfo_t * lump_p = & lumpinfo[ startlump ];
3492         int i;
3493         for (i = startlump; i < numlumps; i++,lump_p++)
3494         {
3495             // Only check first 6 characters.
3496             if( (*(uint64_t *)lump_p->name & mask6) == name8.namecode )
3497             {
3498                 return WADLUMP(wadid,i);
3499             }
3500         }
3501     }
3502     return -1; // not found
3503 }
3504 
3505 //
3506 // Find skin sprites, sounds & optional status bar face, & add them
3507 //
R_AddSkins(int wadnum)3508 void R_AddSkins (int wadnum)
3509 {
3510     int         lumpnum, lastlump, lumpn;
3511 
3512     lumpinfo_t* lumpinfo;
3513     char*       sprname;
3514     uint32_t    numname;
3515 
3516     char*       buf;
3517     char*       buf2;
3518 
3519     char*       token;
3520     char*       value;
3521 
3522     skin_t *    sk;
3523     int         skin_index;
3524 
3525     int         i,size;
3526 
3527     //
3528     // search for all skin markers in pwad
3529     //
3530 
3531     lastlump = 0;
3532     for(;;)
3533     {
3534         sprname = NULL;
3535 
3536         lumpnum = W_CheckForSkinMarkerInPwad (wadnum, lastlump);
3537         if( lumpnum == -1 )  break;
3538 
3539         lumpn = LUMPNUM(lumpnum);
3540         lastlump = lumpn + 1;  // prevent repeating same skin
3541 
3542         skin_index = get_skin_slot();
3543         if( skin_index > MAXSKINS )
3544         {
3545             GenPrintf(EMSG_warn, "ignored skin lump %d (%d skins maximum)\n", lumpn, MAXSKINS);
3546             continue; //faB:so we know how many skins couldn't be added
3547         }
3548         sk = skins[skin_index];
3549 
3550         // set defaults
3551         Skin_SetDefaultValue(sk);
3552         sprintf (sk->name,"skin %d", numskins-1);
3553 
3554         buf  = W_CacheLumpNum (lumpnum, PU_CACHE);
3555         size = W_LumpLength (lumpnum);
3556 
3557         // for strtok
3558         buf2 = (char *) malloc (size+1);
3559         if(!buf2)
3560         {
3561              I_SoftError("R_AddSkins: No more free memory\n");
3562              goto skin_error;
3563         }
3564         memcpy (buf2,buf,size);
3565         buf2[size] = '\0';
3566 
3567         // parse
3568         token = strtok (buf2, "\r\n= ");
3569         while (token)
3570         {
3571             if(token[0]=='/' && token[1]=='/') // skip comments
3572             {
3573                 token = strtok (NULL, "\r\n"); // skip end of line
3574                 goto next_token;               // find the real next token
3575             }
3576 
3577             value = strtok (NULL, "\r\n= ");
3578 //            CONS_Printf("token = %s, value = %s",token,value);
3579 //            CONS_Error("ga");
3580 
3581             if (!value)
3582             {
3583                 I_SoftError("R_AddSkins: syntax error in S_SKIN lump# %d in WAD %s\n", lumpn, wadfiles[wadnum]->filename);
3584                 goto skin_error;
3585             }
3586 
3587             if (!strcasecmp(token,"name"))
3588             {
3589                 // the skin name must uniquely identify a single skin
3590                 // I'm lazy so if name is already used I leave the 'skin x'
3591                 // default skin name set above
3592                 if (!R_SkinAvailable (value))
3593                 {
3594                     strncpy (sk->name, value, SKINNAMESIZE);
3595                     strlwr (sk->name);
3596                 }
3597             }
3598             else
3599             if (!strcasecmp(token,"face"))
3600             {
3601                 strncpy (sk->faceprefix, value, 3);
3602                 sk->faceprefix[3] = 0;
3603                 strupr (sk->faceprefix);
3604             }
3605             else
3606             if (!strcasecmp(token,"sprite"))
3607             {
3608                 sprname = value;
3609                 strupr(sprname);
3610             }
3611             else
3612             {
3613                 int found=false;
3614                 // copy name of sounds that are remapped for this skin
3615                 for (i=0;i<sfx_freeslot0;i++)
3616                 {
3617                     if (!S_sfx[i].name)
3618                       continue;
3619                     if (S_sfx[i].skinsound!=-1 &&
3620                         !strcasecmp(S_sfx[i].name, token+2) )
3621                     {
3622                         sk->soundsid[S_sfx[i].skinsound]=
3623                             S_AddSoundFx(value+2, S_sfx[i].flags);
3624                         found=true;
3625                     }
3626                 }
3627                 if(!found)
3628                 {
3629                     I_SoftError("R_AddSkins: Unknown keyword '%s' in S_SKIN lump# %d (WAD %s)\n",
3630                                token, lumpn, wadfiles[wadnum]->filename);
3631                     goto skin_error;
3632                 }
3633             }
3634 next_token:
3635             token = strtok (NULL,"\r\n= ");
3636         }
3637 
3638         // if no sprite defined use sprite just after this one
3639         if( !sprname )
3640         {
3641             lumpn++;
3642             lumpinfo = wadfiles[wadnum]->lumpinfo;
3643             if( lumpinfo == NULL )
3644                 return;
3645 
3646             // get the base name of this skin's sprite (4 chars)
3647             sprname = lumpinfo[lumpn].name;
3648             numname = *(uint32_t *)sprname;
3649 
3650             // skip to end of this skin's frames
3651             lastlump = lumpn;
3652             while (*(uint32_t *)lumpinfo[lastlump].name == numname)
3653                 lastlump++;
3654             // allocate (or replace) sprite frames, and set spritedef
3655             R_AddSingleSpriteDef (sprname, &sk->spritedef, wadnum, lumpn, lastlump);
3656         }
3657         else
3658         {
3659             // search in the normal sprite tables
3660             char **name;
3661             boolean found = false;
3662             for(name = sprnames;*name;name++)
3663             {
3664                 if( strcmp(*name, sprname) == 0 )
3665                 {
3666                     found = true;
3667                     sk->spritedef = sprites[sprnames-name];
3668                 }
3669             }
3670 
3671             // not found so make a new one
3672             if( !found )
3673                 R_AddSingleSpriteDef (sprname, &sk->spritedef, wadnum, 0, INT_MAX);
3674 
3675         }
3676 
3677         CONS_Printf ("added skin '%s'\n", sk->name);
3678 
3679         free(buf2);
3680     }
3681     return;
3682 
3683 skin_error:
3684     free_skin(skin_index);
3685     return;
3686 }
3687