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