1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1993-1996 by id Software, Inc.
4 // Copyright (C) 1998-2000 by DooM Legacy Team.
5 // Copyright (C) 1999-2021 by Sonic Team Junior.
6 //
7 // This program is free software distributed under the
8 // terms of the GNU General Public License, version 2.
9 // See the 'LICENSE' file for more details.
10 //-----------------------------------------------------------------------------
11 /// \file r_things.c
12 /// \brief Refresh of things, i.e. objects represented by sprites
13
14 #include "doomdef.h"
15 #include "console.h"
16 #include "g_game.h"
17 #include "r_local.h"
18 #include "st_stuff.h"
19 #include "w_wad.h"
20 #include "z_zone.h"
21 #include "m_menu.h" // character select
22 #include "m_misc.h"
23 #include "info.h" // spr2names
24 #include "i_video.h" // rendermode
25 #include "i_system.h"
26 #include "r_things.h"
27 #include "r_patch.h"
28 #include "r_patchrotation.h"
29 #include "r_picformats.h"
30 #include "r_plane.h"
31 #include "r_portal.h"
32 #include "r_splats.h"
33 #include "p_tick.h"
34 #include "p_local.h"
35 #include "p_slopes.h"
36 #include "d_netfil.h" // blargh. for nameonly().
37 #include "m_cheat.h" // objectplace
38 #ifdef HWRENDER
39 #include "hardware/hw_md2.h"
40 #include "hardware/hw_glob.h"
41 #include "hardware/hw_light.h"
42 #include "hardware/hw_drv.h"
43 #endif
44
45 #define MINZ (FRACUNIT*4)
46 #define BASEYCENTER (BASEVIDHEIGHT/2)
47
48 typedef struct
49 {
50 INT32 x1, x2;
51 INT32 column;
52 INT32 topclip, bottomclip;
53 } maskdraw_t;
54
55 //
56 // Sprite rotation 0 is facing the viewer,
57 // rotation 1 is one angle turn CLOCKWISE around the axis.
58 // This is not the same as the angle,
59 // which increases counter clockwise (protractor).
60 // There was a lot of stuff grabbed wrong, so I changed it...
61 //
62 static lighttable_t **spritelights;
63
64 // constant arrays used for psprite clipping and initializing clipping
65 INT16 negonearray[MAXVIDWIDTH];
66 INT16 screenheightarray[MAXVIDWIDTH];
67
68 spriteinfo_t spriteinfo[NUMSPRITES];
69
70 //
71 // INITIALIZATION FUNCTIONS
72 //
73
74 // variables used to look up and range check thing_t sprites patches
75 spritedef_t *sprites;
76 size_t numsprites;
77
78 static spriteframe_t sprtemp[64];
79 static size_t maxframe;
80 static const char *spritename;
81
82 // ==========================================================================
83 //
84 // Sprite loading routines: support sprites in pwad, dehacked sprite renaming,
85 // replacing not all frames of an existing sprite, add sprites at run-time,
86 // add wads at run-time.
87 //
88 // ==========================================================================
89
90 //
91 //
92 //
R_InstallSpriteLump(UINT16 wad,UINT16 lump,size_t lumpid,UINT8 frame,UINT8 rotation,UINT8 flipped)93 static void R_InstallSpriteLump(UINT16 wad, // graphics patch
94 UINT16 lump,
95 size_t lumpid, // identifier
96 UINT8 frame,
97 UINT8 rotation,
98 UINT8 flipped)
99 {
100 char cn = R_Frame2Char(frame), cr = R_Rotation2Char(rotation); // for debugging
101
102 INT32 r;
103 lumpnum_t lumppat = wad;
104 lumppat <<= 16;
105 lumppat += lump;
106
107 if (maxframe ==(size_t)-1 || frame > maxframe)
108 maxframe = frame;
109
110 #ifdef ROTSPRITE
111 for (r = 0; r < 16; r++)
112 {
113 sprtemp[frame].rotated[0][r] = NULL;
114 sprtemp[frame].rotated[1][r] = NULL;
115 }
116 #endif
117
118 if (rotation == 0)
119 {
120 // the lump should be used for all rotations
121 if (sprtemp[frame].rotate == SRF_SINGLE)
122 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple rot = 0 lump\n", spritename, cn);
123 else if (sprtemp[frame].rotate != SRF_NONE) // Let's bundle 1-8/16 and L/R rotations into one debug message.
124 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has rotations and a rot = 0 lump\n", spritename, cn);
125
126 sprtemp[frame].rotate = SRF_SINGLE;
127 for (r = 0; r < 16; r++)
128 {
129 sprtemp[frame].lumppat[r] = lumppat;
130 sprtemp[frame].lumpid[r] = lumpid;
131 }
132 sprtemp[frame].flip = flipped ? 0xFFFF : 0; // 1111111111111111 in binary
133 return;
134 }
135
136 if (rotation == ROT_L || rotation == ROT_R)
137 {
138 UINT8 rightfactor = ((rotation == ROT_R) ? 4 : 0);
139
140 // the lump should be used for half of all rotations
141 if (sprtemp[frame].rotate == SRF_NONE)
142 sprtemp[frame].rotate = SRF_SINGLE;
143 else if (sprtemp[frame].rotate == SRF_SINGLE)
144 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has L/R rotations and a rot = 0 lump\n", spritename, cn);
145 else if (sprtemp[frame].rotate == SRF_3D)
146 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8 rotations\n", spritename, cn);
147 else if (sprtemp[frame].rotate == SRF_3DGE)
148 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-G rotations\n", spritename, cn);
149 else if ((sprtemp[frame].rotate & SRF_LEFT) && (rotation == ROT_L))
150 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple L rotations\n", spritename, cn);
151 else if ((sprtemp[frame].rotate & SRF_RIGHT) && (rotation == ROT_R))
152 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has multiple R rotations\n", spritename, cn);
153
154 sprtemp[frame].rotate |= ((rotation == ROT_R) ? SRF_RIGHT : SRF_LEFT);
155 if ((sprtemp[frame].rotate & SRF_2D) == SRF_2D)
156 sprtemp[frame].rotate &= ~SRF_3DMASK; // SRF_3D|SRF_2D being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
157
158 // load into every relevant angle, including the front one
159 for (r = 0; r < 4; r++)
160 {
161 sprtemp[frame].lumppat[r + rightfactor] = lumppat;
162 sprtemp[frame].lumpid[r + rightfactor] = lumpid;
163 sprtemp[frame].lumppat[r + rightfactor + 8] = lumppat;
164 sprtemp[frame].lumpid[r + rightfactor + 8] = lumpid;
165
166 }
167
168 if (flipped)
169 sprtemp[frame].flip |= (0x0F0F<<rightfactor); // 0000111100001111 or 1111000011110000 in binary, depending on rotation being ROT_L or ROT_R
170 else
171 sprtemp[frame].flip &= ~(0x0F0F<<rightfactor); // ditto
172
173 return;
174 }
175
176 if (sprtemp[frame].rotate == SRF_NONE)
177 sprtemp[frame].rotate = SRF_SINGLE;
178 else if (sprtemp[frame].rotate == SRF_SINGLE)
179 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has 1-8/G rotations and a rot = 0 lump\n", spritename, cn);
180 else if (sprtemp[frame].rotate & SRF_2D)
181 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s frame %c has both L/R and 1-8/G rotations\n", spritename, cn);
182
183 // make 0 based
184 rotation--;
185
186 {
187 // SRF_3D|SRF_3DGE being enabled at the same time doesn't HURT in the current sprite angle implementation, but it DOES mean more to check in some of the helper functions. Let's not allow this scenario to happen.
188 UINT8 threedrot = (rotation > 7) ? SRF_3DGE : (sprtemp[frame].rotate & SRF_3DMASK);
189 if (!threedrot)
190 threedrot = SRF_3D;
191
192 if (rotation == 0 || rotation == 4) // Front or back...
193 sprtemp[frame].rotate = threedrot; // Prevent L and R changeover
194 else if ((rotation & 7) > 3) // Right side
195 sprtemp[frame].rotate = (threedrot | (sprtemp[frame].rotate & SRF_LEFT)); // Continue allowing L frame changeover
196 else // if ((rotation & 7) <= 3) // Left side
197 sprtemp[frame].rotate = (threedrot | (sprtemp[frame].rotate & SRF_RIGHT)); // Continue allowing R frame changeover
198 }
199
200 if (sprtemp[frame].lumppat[rotation] != LUMPERROR)
201 CONS_Debug(DBG_SETUP, "R_InitSprites: Sprite %s: %c%c has two lumps mapped to it\n", spritename, cn, cr);
202
203 // lumppat & lumpid are the same for original Doom, but different
204 // when using sprites in pwad : the lumppat points the new graphics
205 sprtemp[frame].lumppat[rotation] = lumppat;
206 sprtemp[frame].lumpid[rotation] = lumpid;
207 if (flipped)
208 sprtemp[frame].flip |= (1<<rotation);
209 else
210 sprtemp[frame].flip &= ~(1<<rotation);
211 }
212
213 // Install a single sprite, given its identifying name (4 chars)
214 //
215 // (originally part of R_AddSpriteDefs)
216 //
217 // Pass: name of sprite : 4 chars
218 // spritedef_t
219 // wadnum : wad number, indexes wadfiles[], where patches
220 // for frames are found
221 // startlump : first lump to search for sprite frames
222 // endlump : AFTER the last lump to search
223 //
224 // Returns true if the sprite was succesfully added
225 //
R_AddSingleSpriteDef(const char * sprname,spritedef_t * spritedef,UINT16 wadnum,UINT16 startlump,UINT16 endlump)226 boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump)
227 {
228 UINT16 l;
229 UINT8 frame;
230 UINT8 rotation;
231 lumpinfo_t *lumpinfo;
232 softwarepatch_t patch;
233 UINT16 numadded = 0;
234
235 memset(sprtemp,0xFF, sizeof (sprtemp));
236 maxframe = (size_t)-1;
237
238 spritename = sprname;
239
240 // are we 'patching' a sprite already loaded ?
241 // if so, it might patch only certain frames, not all
242 if (spritedef->numframes) // (then spriteframes is not null)
243 {
244 // copy the already defined sprite frames
245 M_Memcpy(sprtemp, spritedef->spriteframes,
246 spritedef->numframes * sizeof (spriteframe_t));
247 maxframe = spritedef->numframes - 1;
248 }
249
250 // scan the lumps,
251 // filling in the frames for whatever is found
252 lumpinfo = wadfiles[wadnum]->lumpinfo;
253 if (endlump > wadfiles[wadnum]->numlumps)
254 endlump = wadfiles[wadnum]->numlumps;
255
256 for (l = startlump; l < endlump; l++)
257 {
258 if (memcmp(lumpinfo[l].name,sprname,4)==0)
259 {
260 INT32 width, height;
261 INT16 topoffset, leftoffset;
262 #ifndef NO_PNG_LUMPS
263 boolean isPNG = false;
264 #endif
265
266 frame = R_Char2Frame(lumpinfo[l].name[4]);
267 rotation = R_Char2Rotation(lumpinfo[l].name[5]);
268
269 if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
270 {
271 CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
272 continue;
273 }
274
275 // skip NULL sprites from very old dmadds pwads
276 if (W_LumpLengthPwad(wadnum,l)<=8)
277 continue;
278
279 // store sprite info in lookup tables
280 //FIXME : numspritelumps do not duplicate sprite replacements
281
282 #ifndef NO_PNG_LUMPS
283 {
284 softwarepatch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC);
285 size_t len = W_LumpLengthPwad(wadnum, l);
286
287 if (Picture_IsLumpPNG((UINT8 *)png, len))
288 {
289 Picture_PNGDimensions((UINT8 *)png, &width, &height, &topoffset, &leftoffset, len);
290 isPNG = true;
291 }
292
293 Z_Free(png);
294 }
295
296 if (!isPNG)
297 #endif
298 {
299 W_ReadLumpHeaderPwad(wadnum, l, &patch, sizeof(INT16) * 4, 0);
300 width = (INT32)(SHORT(patch.width));
301 height = (INT32)(SHORT(patch.height));
302 topoffset = (INT16)(SHORT(patch.topoffset));
303 leftoffset = (INT16)(SHORT(patch.leftoffset));
304 }
305
306 spritecachedinfo[numspritelumps].width = width<<FRACBITS;
307 spritecachedinfo[numspritelumps].offset = leftoffset<<FRACBITS;
308 spritecachedinfo[numspritelumps].topoffset = topoffset<<FRACBITS;
309 spritecachedinfo[numspritelumps].height = height<<FRACBITS;
310
311 // BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer
312 spritecachedinfo[numspritelumps].topoffset += FEETADJUST;
313
314 //----------------------------------------------------
315
316 R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 0);
317
318 if (lumpinfo[l].name[6])
319 {
320 frame = R_Char2Frame(lumpinfo[l].name[6]);
321 rotation = R_Char2Rotation(lumpinfo[l].name[7]);
322
323 if (frame >= 64 || rotation == 255) // Give an actual NAME error -_-...
324 {
325 CONS_Alert(CONS_WARNING, M_GetText("Bad sprite name: %s\n"), W_CheckNameForNumPwad(wadnum,l));
326 continue;
327 }
328 R_InstallSpriteLump(wadnum, l, numspritelumps, frame, rotation, 1);
329 }
330
331 if (++numspritelumps >= max_spritelumps)
332 {
333 max_spritelumps *= 2;
334 Z_Realloc(spritecachedinfo, max_spritelumps*sizeof(*spritecachedinfo), PU_STATIC, &spritecachedinfo);
335 }
336
337 ++numadded;
338 }
339 }
340
341 //
342 // if no frames found for this sprite
343 //
344 if (maxframe == (size_t)-1)
345 {
346 // the first time (which is for the original wad),
347 // all sprites should have their initial frames
348 // and then, patch wads can replace it
349 // we will skip non-replaced sprite frames, only if
350 // they have already have been initially defined (original wad)
351
352 //check only after all initial pwads added
353 //if (spritedef->numframes == 0)
354 // I_Error("R_AddSpriteDefs: no initial frames found for sprite %s\n",
355 // namelist[i]);
356
357 // sprite already has frames, and is not replaced by this wad
358 return false;
359 }
360 else if (!numadded)
361 {
362 // Nothing related to this spritedef has been changed
363 // so there is no point going back through these checks again.
364 return false;
365 }
366
367 maxframe++;
368
369 //
370 // some checks to help development
371 //
372 for (frame = 0; frame < maxframe; frame++)
373 {
374 switch (sprtemp[frame].rotate)
375 {
376 case SRF_NONE:
377 // no rotations were found for that frame at all
378 I_Error("R_AddSingleSpriteDef: No patches found for %.4s frame %c", sprname, R_Frame2Char(frame));
379 break;
380
381 case SRF_SINGLE:
382 // only the first rotation is needed
383 break;
384
385 case SRF_2D: // both Left and Right rotations
386 // we test to see whether the left and right slots are present
387 if ((sprtemp[frame].lumppat[2] == LUMPERROR) || (sprtemp[frame].lumppat[6] == LUMPERROR))
388 I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (L-R mode)",
389 sprname, R_Frame2Char(frame));
390 break;
391
392 default:
393 // must have all 8/16 frames
394 rotation = ((sprtemp[frame].rotate & SRF_3DGE) ? 16 : 8);
395 while (rotation--)
396 // we test the patch lump, or the id lump whatever
397 // if it was not loaded the two are LUMPERROR
398 if (sprtemp[frame].lumppat[rotation] == LUMPERROR)
399 I_Error("R_AddSingleSpriteDef: Sprite %.4s frame %c is missing rotations (1-%c mode)",
400 sprname, R_Frame2Char(frame), ((sprtemp[frame].rotate & SRF_3DGE) ? 'G' : '8'));
401 break;
402 }
403 }
404
405 // allocate space for the frames present and copy sprtemp to it
406 if (spritedef->numframes && // has been allocated
407 spritedef->numframes < maxframe) // more frames are defined ?
408 {
409 Z_Free(spritedef->spriteframes);
410 spritedef->spriteframes = NULL;
411 }
412
413 // allocate this sprite's frames
414 if (!spritedef->spriteframes)
415 spritedef->spriteframes =
416 Z_Malloc(maxframe * sizeof (*spritedef->spriteframes), PU_STATIC, NULL);
417
418 spritedef->numframes = maxframe;
419 M_Memcpy(spritedef->spriteframes, sprtemp, maxframe*sizeof (spriteframe_t));
420
421 return true;
422 }
423
424 //
425 // Search for sprites replacements in a wad whose names are in namelist
426 //
R_AddSpriteDefs(UINT16 wadnum)427 void R_AddSpriteDefs(UINT16 wadnum)
428 {
429 size_t i, addsprites = 0;
430 UINT16 start, end;
431 char wadname[MAX_WADPATH];
432
433 // Find the sprites section in this resource file.
434 switch (wadfiles[wadnum]->type)
435 {
436 case RET_WAD:
437 start = W_CheckNumForMarkerStartPwad("S_START", wadnum, 0);
438 if (start == INT16_MAX)
439 start = W_CheckNumForMarkerStartPwad("SS_START", wadnum, 0); //deutex compatib.
440
441 end = W_CheckNumForNamePwad("S_END",wadnum,start);
442 if (end == INT16_MAX)
443 end = W_CheckNumForNamePwad("SS_END",wadnum,start); //deutex compatib.
444 break;
445 case RET_PK3:
446 start = W_CheckNumForFolderStartPK3("Sprites/", wadnum, 0);
447 end = W_CheckNumForFolderEndPK3("Sprites/", wadnum, start);
448 break;
449 default:
450 return;
451 }
452
453 if (start == INT16_MAX)
454 {
455 // ignore skin wads (we don't want skin sprites interfering with vanilla sprites)
456 if (W_CheckNumForNamePwad("S_SKIN", wadnum, 0) != UINT16_MAX)
457 return;
458
459 start = 0; //let say S_START is lump 0
460 }
461
462 if (end == INT16_MAX || start >= end)
463 {
464 CONS_Debug(DBG_SETUP, "no sprites in pwad %d\n", wadnum);
465 return;
466 }
467
468
469 //
470 // scan through lumps, for each sprite, find all the sprite frames
471 //
472 for (i = 0; i < numsprites; i++)
473 {
474 if (sprnames[i][4] && wadnum >= (UINT16)sprnames[i][4])
475 continue;
476
477 if (R_AddSingleSpriteDef(sprnames[i], &sprites[i], wadnum, start, end))
478 {
479 #ifdef HWRENDER
480 if (rendermode == render_opengl)
481 HWR_AddSpriteModel(i);
482 #endif
483 // if a new sprite was added (not just replaced)
484 addsprites++;
485 #ifndef ZDEBUG
486 CONS_Debug(DBG_SETUP, "sprite %s set in pwad %d\n", sprnames[i], wadnum);
487 #endif
488 }
489 }
490
491 nameonly(strcpy(wadname, wadfiles[wadnum]->filename));
492 CONS_Printf(M_GetText("%s added %d frames in %s sprites\n"), wadname, end-start, sizeu1(addsprites));
493 }
494
495 //
496 // GAME FUNCTIONS
497 //
498 UINT32 visspritecount;
499 static UINT32 clippedvissprites;
500 static vissprite_t *visspritechunks[MAXVISSPRITES >> VISSPRITECHUNKBITS] = {NULL};
501
502 //
503 // R_InitSprites
504 // Called at program start.
505 //
R_InitSprites(void)506 void R_InitSprites(void)
507 {
508 size_t i;
509 #ifdef ROTSPRITE
510 INT32 angle;
511 float fa;
512 #endif
513
514 for (i = 0; i < MAXVIDWIDTH; i++)
515 negonearray[i] = -1;
516
517 #ifdef ROTSPRITE
518 for (angle = 1; angle < ROTANGLES; angle++)
519 {
520 fa = ANG2RAD(FixedAngle((ROTANGDIFF * angle)<<FRACBITS));
521 rollcosang[angle] = FLOAT_TO_FIXED(cos(-fa));
522 rollsinang[angle] = FLOAT_TO_FIXED(sin(-fa));
523 }
524 #endif
525
526 //
527 // count the number of sprite names, and allocate sprites table
528 //
529 numsprites = 0;
530 for (i = 0; i < NUMSPRITES + 1; i++)
531 if (sprnames[i][0] != '\0') numsprites++;
532
533 if (!numsprites)
534 I_Error("R_AddSpriteDefs: no sprites in namelist\n");
535
536 sprites = Z_Calloc(numsprites * sizeof (*sprites), PU_STATIC, NULL);
537
538 // find sprites in each -file added pwad
539 for (i = 0; i < numwadfiles; i++)
540 R_AddSpriteDefs((UINT16)i);
541
542 //
543 // now check for skins
544 //
545
546 // it can be is do before loading config for skin cvar possible value
547 R_InitSkins();
548 for (i = 0; i < numwadfiles; i++)
549 {
550 R_AddSkins((UINT16)i);
551 R_PatchSkins((UINT16)i);
552 R_LoadSpriteInfoLumps(i, wadfiles[i]->numlumps);
553 }
554 ST_ReloadSkinFaceGraphics();
555
556 //
557 // check if all sprites have frames
558 //
559 /*
560 for (i = 0; i < numsprites; i++)
561 if (sprites[i].numframes < 1)
562 CONS_Debug(DBG_SETUP, "R_InitSprites: sprite %s has no frames at all\n", sprnames[i]);
563 */
564 }
565
566 //
567 // R_ClearSprites
568 // Called at frame start.
569 //
R_ClearSprites(void)570 void R_ClearSprites(void)
571 {
572 visspritecount = clippedvissprites = 0;
573 }
574
575 //
576 // R_NewVisSprite
577 //
578 static vissprite_t overflowsprite;
579
R_GetVisSprite(UINT32 num)580 static vissprite_t *R_GetVisSprite(UINT32 num)
581 {
582 UINT32 chunk = num >> VISSPRITECHUNKBITS;
583
584 // Allocate chunk if necessary
585 if (!visspritechunks[chunk])
586 Z_Malloc(sizeof(vissprite_t) * VISSPRITESPERCHUNK, PU_LEVEL, &visspritechunks[chunk]);
587
588 return visspritechunks[chunk] + (num & VISSPRITEINDEXMASK);
589 }
590
R_NewVisSprite(void)591 static vissprite_t *R_NewVisSprite(void)
592 {
593 if (visspritecount == MAXVISSPRITES)
594 return &overflowsprite;
595
596 return R_GetVisSprite(visspritecount++);
597 }
598
599 //
600 // R_DrawMaskedColumn
601 // Used for sprites and masked mid textures.
602 // Masked means: partly transparent, i.e. stored
603 // in posts/runs of opaque pixels.
604 //
605 INT16 *mfloorclip;
606 INT16 *mceilingclip;
607
608 fixed_t spryscale = 0, sprtopscreen = 0, sprbotscreen = 0;
609 fixed_t windowtop = 0, windowbottom = 0;
610
R_DrawMaskedColumn(column_t * column)611 void R_DrawMaskedColumn(column_t *column)
612 {
613 INT32 topscreen;
614 INT32 bottomscreen;
615 fixed_t basetexturemid;
616 INT32 topdelta, prevdelta = 0;
617
618 basetexturemid = dc_texturemid;
619
620 for (; column->topdelta != 0xff ;)
621 {
622 // calculate unclipped screen coordinates
623 // for post
624 topdelta = column->topdelta;
625 if (topdelta <= prevdelta)
626 topdelta += prevdelta;
627 prevdelta = topdelta;
628 topscreen = sprtopscreen + spryscale*topdelta;
629 bottomscreen = topscreen + spryscale*column->length;
630
631 dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
632 dc_yh = (bottomscreen-1)>>FRACBITS;
633
634 if (windowtop != INT32_MAX && windowbottom != INT32_MAX)
635 {
636 if (windowtop > topscreen)
637 dc_yl = (windowtop + FRACUNIT - 1)>>FRACBITS;
638 if (windowbottom < bottomscreen)
639 dc_yh = (windowbottom - 1)>>FRACBITS;
640 }
641
642 if (dc_yh >= mfloorclip[dc_x])
643 dc_yh = mfloorclip[dc_x]-1;
644 if (dc_yl <= mceilingclip[dc_x])
645 dc_yl = mceilingclip[dc_x]+1;
646 if (dc_yl < 0)
647 dc_yl = 0;
648 if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop
649 dc_yh = vid.height - 1;
650
651 if (dc_yl <= dc_yh && dc_yh > 0)
652 {
653 dc_source = (UINT8 *)column + 3;
654 dc_texturemid = basetexturemid - (topdelta<<FRACBITS);
655
656 // Drawn by R_DrawColumn.
657 // This stuff is a likely cause of the splitscreen water crash bug.
658 // FIXTHIS: Figure out what "something more proper" is and do it.
659 // quick fix... something more proper should be done!!!
660 if (ylookup[dc_yl])
661 colfunc();
662 #ifdef PARANOIA
663 else
664 I_Error("R_DrawMaskedColumn: Invalid ylookup for dc_yl %d", dc_yl);
665 #endif
666 }
667 column = (column_t *)((UINT8 *)column + column->length + 4);
668 }
669
670 dc_texturemid = basetexturemid;
671 }
672
673 INT32 lengthcol; // column->length : for flipped column function pointers and multi-patch on 2sided wall = texture->height
674
R_DrawFlippedMaskedColumn(column_t * column)675 void R_DrawFlippedMaskedColumn(column_t *column)
676 {
677 INT32 topscreen;
678 INT32 bottomscreen;
679 fixed_t basetexturemid = dc_texturemid;
680 INT32 topdelta, prevdelta = -1;
681 UINT8 *d,*s;
682
683 for (; column->topdelta != 0xff ;)
684 {
685 // calculate unclipped screen coordinates
686 // for post
687 topdelta = column->topdelta;
688 if (topdelta <= prevdelta)
689 topdelta += prevdelta;
690 prevdelta = topdelta;
691 topdelta = lengthcol-column->length-topdelta;
692 topscreen = sprtopscreen + spryscale*topdelta;
693 bottomscreen = sprbotscreen == INT32_MAX ? topscreen + spryscale*column->length
694 : sprbotscreen + spryscale*column->length;
695
696 dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
697 dc_yh = (bottomscreen-1)>>FRACBITS;
698
699 if (windowtop != INT32_MAX && windowbottom != INT32_MAX)
700 {
701 if (windowtop > topscreen)
702 dc_yl = (windowtop + FRACUNIT - 1)>>FRACBITS;
703 if (windowbottom < bottomscreen)
704 dc_yh = (windowbottom - 1)>>FRACBITS;
705 }
706
707 if (dc_yh >= mfloorclip[dc_x])
708 dc_yh = mfloorclip[dc_x]-1;
709 if (dc_yl <= mceilingclip[dc_x])
710 dc_yl = mceilingclip[dc_x]+1;
711 if (dc_yl < 0)
712 dc_yl = 0;
713 if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop
714 dc_yh = vid.height - 1;
715
716 if (dc_yl <= dc_yh && dc_yh > 0)
717 {
718 dc_source = ZZ_Alloc(column->length);
719 for (s = (UINT8 *)column+2+column->length, d = dc_source; d < dc_source+column->length; --s)
720 *d++ = *s;
721 dc_texturemid = basetexturemid - (topdelta<<FRACBITS);
722
723 // Still drawn by R_DrawColumn.
724 if (ylookup[dc_yl])
725 colfunc();
726 #ifdef PARANOIA
727 else
728 I_Error("R_DrawMaskedColumn: Invalid ylookup for dc_yl %d", dc_yl);
729 #endif
730 Z_Free(dc_source);
731 }
732 column = (column_t *)((UINT8 *)column + column->length + 4);
733 }
734
735 dc_texturemid = basetexturemid;
736 }
737
R_SpriteIsFlashing(vissprite_t * vis)738 boolean R_SpriteIsFlashing(vissprite_t *vis)
739 {
740 return (!(vis->cut & SC_PRECIP)
741 && (vis->mobj->flags & (MF_ENEMY|MF_BOSS))
742 && (vis->mobj->flags2 & MF2_FRET)
743 && !(vis->mobj->flags & MF_GRENADEBOUNCE)
744 && (leveltime & 1));
745 }
746
R_GetSpriteTranslation(vissprite_t * vis)747 UINT8 *R_GetSpriteTranslation(vissprite_t *vis)
748 {
749 if (R_SpriteIsFlashing(vis)) // Bosses "flash"
750 {
751 if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
752 return R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
753 else if (vis->mobj->type == MT_METALSONIC_BATTLE)
754 return R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE);
755 else
756 return R_GetTranslationColormap(TC_BOSS, 0, GTC_CACHE);
757 }
758 else if (vis->mobj->color)
759 {
760 // New colormap stuff for skins Tails 06-07-2002
761 if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
762 return R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
763 else if (!(vis->cut & SC_PRECIP)
764 && vis->mobj->player && vis->mobj->player->dashmode >= DASHMODE_THRESHOLD
765 && (vis->mobj->player->charflags & SF_DASHMODE)
766 && ((leveltime/2) & 1))
767 {
768 if (vis->mobj->player->charflags & SF_MACHINE)
769 return R_GetTranslationColormap(TC_DASHMODE, 0, GTC_CACHE);
770 else
771 return R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
772 }
773 else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
774 {
775 size_t skinnum = (skin_t*)vis->mobj->skin-skins;
776 return R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE);
777 }
778 else // Use the defaults
779 return R_GetTranslationColormap(TC_DEFAULT, vis->mobj->color, GTC_CACHE);
780 }
781 else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome.
782 return R_GetTranslationColormap(TC_DEFAULT, SKINCOLOR_BLUE, GTC_CACHE);
783
784 return NULL;
785 }
786
787 //
788 // R_DrawVisSprite
789 // mfloorclip and mceilingclip should also be set.
790 //
R_DrawVisSprite(vissprite_t * vis)791 static void R_DrawVisSprite(vissprite_t *vis)
792 {
793 column_t *column;
794 void (*localcolfunc)(column_t *);
795 INT32 texturecolumn;
796 INT32 pwidth;
797 fixed_t frac;
798 patch_t *patch = vis->patch;
799 fixed_t this_scale = vis->thingscale;
800 INT32 x1, x2;
801 INT64 overflow_test;
802
803 if (!patch)
804 return;
805
806 // Check for overflow
807 overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
808 if (overflow_test < 0) overflow_test = -overflow_test;
809 if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
810
811 if (vis->scalestep) // handles right edge too
812 {
813 overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*(vis->scale + (vis->scalestep*(vis->x2 - vis->x1))))>>FRACBITS);
814 if (overflow_test < 0) overflow_test = -overflow_test;
815 if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // ditto
816 }
817
818 colfunc = colfuncs[BASEDRAWFUNC]; // hack: this isn't resetting properly somewhere.
819 dc_colormap = vis->colormap;
820 dc_translation = R_GetSpriteTranslation(vis);
821
822 if (R_SpriteIsFlashing(vis)) // Bosses "flash"
823 colfunc = colfuncs[COLDRAWFUNC_TRANS]; // translate certain pixels to white
824 else if (vis->mobj->color && vis->transmap) // Color mapping
825 {
826 colfunc = colfuncs[COLDRAWFUNC_TRANSTRANS];
827 dc_transmap = vis->transmap;
828 }
829 else if (vis->transmap)
830 {
831 colfunc = colfuncs[COLDRAWFUNC_FUZZY];
832 dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table
833 }
834 else if (vis->mobj->color) // translate green skin to another color
835 colfunc = colfuncs[COLDRAWFUNC_TRANS];
836 else if (vis->mobj->sprite == SPR_PLAY) // Looks like a player, but doesn't have a color? Get rid of green sonic syndrome.
837 colfunc = colfuncs[COLDRAWFUNC_TRANS];
838
839 if (vis->extra_colormap && !(vis->renderflags & RF_NOCOLORMAPS))
840 {
841 if (!dc_colormap)
842 dc_colormap = vis->extra_colormap->colormap;
843 else
844 dc_colormap = &vis->extra_colormap->colormap[dc_colormap - colormaps];
845 }
846 if (!dc_colormap)
847 dc_colormap = colormaps;
848
849 dc_texturemid = vis->texturemid;
850 dc_texheight = 0;
851
852 frac = vis->startfrac;
853 windowtop = windowbottom = sprbotscreen = INT32_MAX;
854
855 if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES)
856 this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale);
857 if (this_scale <= 0)
858 this_scale = 1;
859 if (this_scale != FRACUNIT)
860 {
861 if (!(vis->cut & SC_ISSCALED))
862 {
863 vis->scale = FixedMul(vis->scale, this_scale);
864 vis->scalestep = FixedMul(vis->scalestep, this_scale);
865 vis->xiscale = FixedDiv(vis->xiscale,this_scale);
866 vis->cut |= SC_ISSCALED;
867 }
868 dc_texturemid = FixedDiv(dc_texturemid,this_scale);
869 }
870
871 spryscale = vis->scale;
872
873 if (!(vis->scalestep))
874 {
875 sprtopscreen = centeryfrac - FixedMul(dc_texturemid, spryscale);
876 sprtopscreen += vis->shear.tan * vis->shear.offset;
877 dc_iscale = FixedDiv(FRACUNIT, vis->scale);
878 }
879
880 x1 = vis->x1;
881 x2 = vis->x2;
882
883 if (vis->x1 < 0)
884 {
885 spryscale += vis->scalestep*(-vis->x1);
886 vis->x1 = 0;
887 }
888
889 if (vis->x2 >= vid.width)
890 vis->x2 = vid.width-1;
891
892 localcolfunc = (vis->cut & SC_VFLIP) ? R_DrawFlippedMaskedColumn : R_DrawMaskedColumn;
893 lengthcol = patch->height;
894
895 // Split drawing loops for paper and non-paper to reduce conditional checks per sprite
896 if (vis->scalestep)
897 {
898 fixed_t horzscale = FixedMul(vis->spritexscale, this_scale);
899 fixed_t scalestep = FixedMul(vis->scalestep, vis->spriteyscale);
900
901 pwidth = patch->width;
902
903 // Papersprite drawing loop
904 for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, spryscale += scalestep)
905 {
906 angle_t angle = ((vis->centerangle + xtoviewangle[dc_x]) >> ANGLETOFINESHIFT) & 0xFFF;
907 texturecolumn = (vis->paperoffset - FixedMul(FINETANGENT(angle), vis->paperdistance)) / horzscale;
908
909 if (texturecolumn < 0 || texturecolumn >= pwidth)
910 continue;
911
912 if (vis->xiscale < 0) // Flipped sprite
913 texturecolumn = pwidth - 1 - texturecolumn;
914
915 sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
916 dc_iscale = (0xffffffffu / (unsigned)spryscale);
917
918 column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn]));
919
920 localcolfunc (column);
921 }
922 }
923 else if (vis->cut & SC_SHEAR)
924 {
925 #ifdef RANGECHECK
926 pwidth = patch->width;
927 #endif
928
929 // Vertically sheared sprite
930 for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale, dc_texturemid -= vis->shear.tan)
931 {
932 #ifdef RANGECHECK
933 texturecolumn = frac>>FRACBITS;
934 if (texturecolumn < 0 || texturecolumn >= pwidth)
935 I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x);
936 column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn]));
937 #else
938 column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS]));
939 #endif
940
941 sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale));
942 localcolfunc (column);
943 }
944 }
945 else
946 {
947 #ifdef RANGECHECK
948 pwidth = patch->width;
949 #endif
950
951 // Non-paper drawing loop
952 for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale, sprtopscreen += vis->shear.tan)
953 {
954 #ifdef RANGECHECK
955 texturecolumn = frac>>FRACBITS;
956 if (texturecolumn < 0 || texturecolumn >= pwidth)
957 I_Error("R_DrawSpriteRange: bad texturecolumn at %d from end", vis->x2 - dc_x);
958 column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn]));
959 #else
960 column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS]));
961 #endif
962 localcolfunc (column);
963 }
964 }
965
966 colfunc = colfuncs[BASEDRAWFUNC];
967 dc_hires = 0;
968
969 vis->x1 = x1;
970 vis->x2 = x2;
971 }
972
973 // Special precipitation drawer Tails 08-18-2002
R_DrawPrecipitationVisSprite(vissprite_t * vis)974 static void R_DrawPrecipitationVisSprite(vissprite_t *vis)
975 {
976 column_t *column;
977 #ifdef RANGECHECK
978 INT32 texturecolumn;
979 #endif
980 fixed_t frac;
981 patch_t *patch;
982 INT64 overflow_test;
983
984 //Fab : R_InitSprites now sets a wad lump number
985 patch = vis->patch;
986 if (!patch)
987 return;
988
989 // Check for overflow
990 overflow_test = (INT64)centeryfrac - (((INT64)vis->texturemid*vis->scale)>>FRACBITS);
991 if (overflow_test < 0) overflow_test = -overflow_test;
992 if ((UINT64)overflow_test&0xFFFFFFFF80000000ULL) return; // fixed point mult would overflow
993
994 if (vis->transmap)
995 {
996 colfunc = colfuncs[COLDRAWFUNC_FUZZY];
997 dc_transmap = vis->transmap; //Fab : 29-04-98: translucency table
998 }
999
1000 dc_colormap = colormaps;
1001
1002 dc_iscale = FixedDiv(FRACUNIT, vis->scale);
1003 dc_texturemid = vis->texturemid;
1004 dc_texheight = 0;
1005
1006 frac = vis->startfrac;
1007 spryscale = vis->scale;
1008 sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
1009 windowtop = windowbottom = sprbotscreen = INT32_MAX;
1010
1011 if (vis->x1 < 0)
1012 vis->x1 = 0;
1013
1014 if (vis->x2 >= vid.width)
1015 vis->x2 = vid.width-1;
1016
1017 for (dc_x = vis->x1; dc_x <= vis->x2; dc_x++, frac += vis->xiscale)
1018 {
1019 #ifdef RANGECHECK
1020 texturecolumn = frac>>FRACBITS;
1021
1022 if (texturecolumn < 0 || texturecolumn >= patch->width)
1023 I_Error("R_DrawPrecipitationSpriteRange: bad texturecolumn");
1024
1025 column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn]));
1026 #else
1027 column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS]));
1028 #endif
1029 R_DrawMaskedColumn(column);
1030 }
1031
1032 colfunc = colfuncs[BASEDRAWFUNC];
1033 }
1034
1035 //
1036 // R_SplitSprite
1037 // runs through a sector's lightlist and Knuckles
R_SplitSprite(vissprite_t * sprite)1038 static void R_SplitSprite(vissprite_t *sprite)
1039 {
1040 INT32 i, lightnum, lindex;
1041 INT16 cutfrac;
1042 sector_t *sector;
1043 vissprite_t *newsprite;
1044
1045 sector = sprite->sector;
1046
1047 for (i = 1; i < sector->numlights; i++)
1048 {
1049 fixed_t testheight;
1050
1051 if (!(sector->lightlist[i].caster->flags & FF_CUTSPRITES))
1052 continue;
1053
1054 testheight = P_GetLightZAt(§or->lightlist[i], sprite->gx, sprite->gy);
1055
1056 if (testheight >= sprite->gzt)
1057 continue;
1058 if (testheight <= sprite->gz)
1059 return;
1060
1061 cutfrac = (INT16)((centeryfrac - FixedMul(testheight - viewz, sprite->sortscale))>>FRACBITS);
1062 if (cutfrac < 0)
1063 continue;
1064 if (cutfrac > viewheight)
1065 return;
1066
1067 // Found a split! Make a new sprite, copy the old sprite to it, and
1068 // adjust the heights.
1069 newsprite = M_Memcpy(R_NewVisSprite(), sprite, sizeof (vissprite_t));
1070
1071 newsprite->cut |= (sprite->cut & SC_FLAGMASK);
1072
1073 sprite->cut |= SC_BOTTOM;
1074 sprite->gz = testheight;
1075
1076 newsprite->gzt = sprite->gz;
1077
1078 sprite->sz = cutfrac;
1079 newsprite->szt = (INT16)(sprite->sz - 1);
1080
1081 if (testheight < sprite->pzt && testheight > sprite->pz)
1082 sprite->pz = newsprite->pzt = testheight;
1083 else
1084 {
1085 newsprite->pz = newsprite->gz;
1086 newsprite->pzt = newsprite->gzt;
1087 }
1088
1089 newsprite->szt -= 8;
1090
1091 newsprite->cut |= SC_TOP;
1092 if (!(sector->lightlist[i].caster->flags & FF_NOSHADE))
1093 {
1094 lightnum = (*sector->lightlist[i].lightlevel >> LIGHTSEGSHIFT);
1095
1096 if (lightnum < 0)
1097 spritelights = scalelight[0];
1098 else if (lightnum >= LIGHTLEVELS)
1099 spritelights = scalelight[LIGHTLEVELS-1];
1100 else
1101 spritelights = scalelight[lightnum];
1102
1103 newsprite->extra_colormap = *sector->lightlist[i].extra_colormap;
1104
1105 if (!(newsprite->cut & SC_FULLBRIGHT)
1106 || (newsprite->extra_colormap && (newsprite->extra_colormap->flags & CMF_FADEFULLBRIGHTSPRITES)))
1107 {
1108 lindex = FixedMul(sprite->xscale, LIGHTRESOLUTIONFIX)>>(LIGHTSCALESHIFT);
1109
1110 if (lindex >= MAXLIGHTSCALE)
1111 lindex = MAXLIGHTSCALE-1;
1112 newsprite->colormap = spritelights[lindex];
1113 }
1114 }
1115 sprite = newsprite;
1116 }
1117 }
1118
1119 //
1120 // R_GetShadowZ(thing, shadowslope)
1121 // Get the first visible floor below the object for shadows
1122 // shadowslope is filled with the floor's slope, if provided
1123 //
R_GetShadowZ(mobj_t * thing,pslope_t ** shadowslope)1124 fixed_t R_GetShadowZ(mobj_t *thing, pslope_t **shadowslope)
1125 {
1126 boolean isflipped = thing->eflags & MFE_VERTICALFLIP;
1127 fixed_t z, groundz = isflipped ? INT32_MAX : INT32_MIN;
1128 pslope_t *slope, *groundslope = NULL;
1129 msecnode_t *node;
1130 sector_t *sector;
1131 ffloor_t *rover;
1132 #define CHECKZ (isflipped ? z > thing->z+thing->height/2 && z < groundz : z < thing->z+thing->height/2 && z > groundz)
1133
1134 for (node = thing->touching_sectorlist; node; node = node->m_sectorlist_next)
1135 {
1136 sector = node->m_sector;
1137
1138 slope = sector->heightsec != -1 ? NULL : (isflipped ? sector->c_slope : sector->f_slope);
1139
1140 if (sector->heightsec != -1)
1141 z = isflipped ? sectors[sector->heightsec].ceilingheight : sectors[sector->heightsec].floorheight;
1142 else
1143 z = isflipped ? P_GetSectorCeilingZAt(sector, thing->x, thing->y) : P_GetSectorFloorZAt(sector, thing->x, thing->y);
1144
1145 if CHECKZ
1146 {
1147 groundz = z;
1148 groundslope = slope;
1149 }
1150
1151 if (sector->ffloors)
1152 for (rover = sector->ffloors; rover; rover = rover->next)
1153 {
1154 if (!(rover->flags & FF_EXISTS) || !(rover->flags & FF_RENDERPLANES) || (rover->alpha < 90 && !(rover->flags & FF_SWIMMABLE)))
1155 continue;
1156
1157 z = isflipped ? P_GetFFloorBottomZAt(rover, thing->x, thing->y) : P_GetFFloorTopZAt(rover, thing->x, thing->y);
1158 if CHECKZ
1159 {
1160 groundz = z;
1161 groundslope = isflipped ? *rover->b_slope : *rover->t_slope;
1162 }
1163 }
1164 }
1165
1166 if (isflipped ? (thing->ceilingz < groundz - (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2)))
1167 : (thing->floorz > groundz + (!groundslope ? 0 : FixedMul(abs(groundslope->zdelta), thing->radius*3/2))))
1168 {
1169 groundz = isflipped ? thing->ceilingz : thing->floorz;
1170 groundslope = NULL;
1171 }
1172
1173 #if 0 // Unfortunately, this drops CEZ2 down to sub-17 FPS on my i7.
1174 // NOTE: this section was not updated to reflect reverse gravity support
1175 // Check polyobjects and see if groundz needs to be altered, for rings only because they don't update floorz
1176 if (thing->type == MT_RING)
1177 {
1178 INT32 xl, xh, yl, yh, bx, by;
1179
1180 xl = (unsigned)(thing->x - thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
1181 xh = (unsigned)(thing->x + thing->radius - bmaporgx)>>MAPBLOCKSHIFT;
1182 yl = (unsigned)(thing->y - thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
1183 yh = (unsigned)(thing->y + thing->radius - bmaporgy)>>MAPBLOCKSHIFT;
1184
1185 BMBOUNDFIX(xl, xh, yl, yh);
1186
1187 validcount++;
1188
1189 for (by = yl; by <= yh; by++)
1190 for (bx = xl; bx <= xh; bx++)
1191 {
1192 INT32 offset;
1193 polymaplink_t *plink; // haleyjd 02/22/06
1194
1195 if (bx < 0 || by < 0 || bx >= bmapwidth || by >= bmapheight)
1196 continue;
1197
1198 offset = by*bmapwidth + bx;
1199
1200 // haleyjd 02/22/06: consider polyobject lines
1201 plink = polyblocklinks[offset];
1202
1203 while (plink)
1204 {
1205 polyobj_t *po = plink->po;
1206
1207 if (po->validcount != validcount) // if polyobj hasn't been checked
1208 {
1209 po->validcount = validcount;
1210
1211 if (!P_MobjInsidePolyobj(po, thing) || !(po->flags & POF_RENDERPLANES))
1212 {
1213 plink = (polymaplink_t *)(plink->link.next);
1214 continue;
1215 }
1216
1217 // We're inside it! Yess...
1218 z = po->lines[0]->backsector->ceilingheight;
1219
1220 if (z < thing->z+thing->height/2 && z > groundz)
1221 {
1222 groundz = z;
1223 groundslope = NULL;
1224 }
1225 }
1226 plink = (polymaplink_t *)(plink->link.next);
1227 }
1228 }
1229 }
1230 #endif
1231
1232 if (shadowslope != NULL)
1233 *shadowslope = groundslope;
1234
1235 return groundz;
1236 #undef CHECKZ
1237 }
1238
1239 static void R_SkewShadowSprite(
1240 mobj_t *thing, pslope_t *groundslope,
1241 fixed_t groundz, INT32 spriteheight, fixed_t scalemul,
1242 fixed_t *shadowyscale, fixed_t *shadowskew)
1243 {
1244 // haha let's try some dumb stuff
1245 fixed_t xslope, zslope;
1246 angle_t sloperelang = (R_PointToAngle(thing->x, thing->y) - groundslope->xydirection) >> ANGLETOFINESHIFT;
1247
1248 xslope = FixedMul(FINESINE(sloperelang), groundslope->zdelta);
1249 zslope = FixedMul(FINECOSINE(sloperelang), groundslope->zdelta);
1250
1251 //CONS_Printf("Shadow is sloped by %d %d\n", xslope, zslope);
1252
1253 if (viewz < groundz)
1254 *shadowyscale += FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope);
1255 else
1256 *shadowyscale -= FixedMul(FixedMul(thing->radius*2 / spriteheight, scalemul), zslope);
1257
1258 *shadowyscale = abs((*shadowyscale));
1259 *shadowskew = xslope;
1260 }
1261
1262 static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, fixed_t tx, fixed_t tz)
1263 {
1264 vissprite_t *shadow;
1265 patch_t *patch;
1266 fixed_t xscale, yscale, shadowxscale, shadowyscale, shadowskew, x1, x2;
1267 INT32 light = 0;
1268 fixed_t scalemul; UINT8 trans;
1269 fixed_t floordiff;
1270 fixed_t groundz;
1271 pslope_t *groundslope;
1272 boolean isflipped = thing->eflags & MFE_VERTICALFLIP;
1273
1274 groundz = R_GetShadowZ(thing, &groundslope);
1275
1276 if (abs(groundz-viewz)/tz > 4) return; // Prevent stretchy shadows and possible crashes
1277
1278 floordiff = abs((isflipped ? thing->height : 0) + thing->z - groundz);
1279
1280 trans = floordiff / (100*FRACUNIT) + 3;
1281 if (trans >= 9) return;
1282
1283 scalemul = FixedMul(FRACUNIT - floordiff/640, scale);
1284
1285 patch = W_CachePatchName("DSHADOW", PU_SPRITE);
1286 xscale = FixedDiv(projection, tz);
1287 yscale = FixedDiv(projectiony, tz);
1288 shadowxscale = FixedMul(thing->radius*2, scalemul);
1289 shadowyscale = FixedMul(FixedMul(thing->radius*2, scalemul), FixedDiv(abs(groundz - viewz), tz));
1290 shadowyscale = min(shadowyscale, shadowxscale) / patch->height;
1291 shadowxscale /= patch->width;
1292 shadowskew = 0;
1293
1294 if (groundslope)
1295 R_SkewShadowSprite(thing, groundslope, groundz, patch->height, scalemul, &shadowyscale, &shadowskew);
1296
1297 tx -= patch->width * shadowxscale/2;
1298 x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
1299 if (x1 >= viewwidth) return;
1300
1301 tx += patch->width * shadowxscale;
1302 x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--;
1303 if (x2 < 0 || x2 <= x1) return;
1304
1305 if (shadowyscale < FRACUNIT/patch->height) return; // fix some crashes?
1306
1307 shadow = R_NewVisSprite();
1308 shadow->patch = patch;
1309 shadow->heightsec = vis->heightsec;
1310
1311 shadow->thingheight = FRACUNIT;
1312 shadow->pz = groundz + (isflipped ? -shadow->thingheight : 0);
1313 shadow->pzt = shadow->pz + shadow->thingheight;
1314
1315 shadow->mobjflags = 0;
1316 shadow->sortscale = vis->sortscale;
1317 shadow->dispoffset = vis->dispoffset - 5;
1318 shadow->gx = thing->x;
1319 shadow->gy = thing->y;
1320 shadow->gzt = (isflipped ? shadow->pzt : shadow->pz) + patch->height * shadowyscale / 2;
1321 shadow->gz = shadow->gzt - patch->height * shadowyscale;
1322 shadow->texturemid = FixedMul(thing->scale, FixedDiv(shadow->gzt - viewz, shadowyscale));
1323 if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
1324 shadow->texturemid = FixedMul(shadow->texturemid, ((skin_t *)thing->skin)->highresscale);
1325 shadow->scalestep = 0;
1326 shadow->shear.tan = shadowskew; // repurposed variable
1327
1328 shadow->mobj = thing; // Easy access! Tails 06-07-2002
1329
1330 shadow->x1 = x1 < portalclipstart ? portalclipstart : x1;
1331 shadow->x2 = x2 >= portalclipend ? portalclipend-1 : x2;
1332
1333 shadow->xscale = FixedMul(xscale, shadowxscale); //SoM: 4/17/2000
1334 shadow->scale = FixedMul(yscale, shadowyscale);
1335 shadow->thingscale = thing->scale;
1336 shadow->sector = vis->sector;
1337 shadow->szt = (INT16)((centeryfrac - FixedMul(shadow->gzt - viewz, yscale))>>FRACBITS);
1338 shadow->sz = (INT16)((centeryfrac - FixedMul(shadow->gz - viewz, yscale))>>FRACBITS);
1339 shadow->cut = SC_ISSCALED|SC_SHADOW; //check this
1340
1341 shadow->startfrac = 0;
1342 //shadow->xiscale = 0x7ffffff0 / (shadow->xscale/2);
1343 shadow->xiscale = (patch->width<<FRACBITS)/(x2-x1+1); // fuck it
1344
1345 if (shadow->x1 > x1)
1346 shadow->startfrac += shadow->xiscale*(shadow->x1-x1);
1347
1348 // reusing x1 variable
1349 x1 += (x2-x1)/2;
1350 shadow->shear.offset = shadow->x1-x1;
1351
1352 if (thing->renderflags & RF_NOCOLORMAPS)
1353 shadow->extra_colormap = NULL;
1354 else
1355 {
1356 if (thing->subsector->sector->numlights)
1357 {
1358 INT32 lightnum;
1359 light = thing->subsector->sector->numlights - 1;
1360
1361 // R_GetPlaneLight won't work on sloped lights!
1362 for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) {
1363 fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y);
1364 if (h <= shadow->gzt) {
1365 light = lightnum - 1;
1366 break;
1367 }
1368 }
1369 }
1370
1371 if (thing->subsector->sector->numlights)
1372 shadow->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap;
1373 else
1374 shadow->extra_colormap = thing->subsector->sector->extra_colormap;
1375 }
1376
1377 shadow->transmap = R_GetTranslucencyTable(trans + 1);
1378 shadow->colormap = scalelight[0][0]; // full dark!
1379
1380 objectsdrawn++;
1381 }
1382
1383 //
1384 // R_ProjectSprite
1385 // Generates a vissprite for a thing
1386 // if it might be visible.
1387 //
1388 static void R_ProjectSprite(mobj_t *thing)
1389 {
1390 mobj_t *oldthing = thing;
1391 fixed_t tr_x, tr_y;
1392 fixed_t tx, tz;
1393 fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!!
1394 fixed_t sortscale, sortsplat = 0;
1395 fixed_t sort_x = 0, sort_y = 0, sort_z;
1396
1397 INT32 x1, x2;
1398
1399 spritedef_t *sprdef;
1400 spriteframe_t *sprframe;
1401 #ifdef ROTSPRITE
1402 spriteinfo_t *sprinfo;
1403 #endif
1404 size_t lump;
1405
1406 size_t frame, rot;
1407 UINT16 flip;
1408 boolean vflip = (!(thing->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(thing));
1409 boolean mirrored = thing->mirrored;
1410 boolean hflip = (!R_ThingHorizontallyFlipped(thing) != !mirrored);
1411
1412 INT32 lindex;
1413 INT32 trans;
1414
1415 vissprite_t *vis;
1416 patch_t *patch;
1417
1418 spritecut_e cut = SC_NONE;
1419
1420 angle_t ang = 0; // compiler complaints
1421 fixed_t iscale;
1422 fixed_t scalestep;
1423 fixed_t offset, offset2;
1424
1425 fixed_t sheartan = 0;
1426 fixed_t shadowscale = FRACUNIT;
1427 fixed_t basetx, basetz; // drop shadows
1428
1429 boolean shadowdraw, shadoweffects, shadowskew;
1430 boolean splat = R_ThingIsFloorSprite(thing);
1431 boolean papersprite = (R_ThingIsPaperSprite(thing) && !splat);
1432 fixed_t paperoffset = 0, paperdistance = 0;
1433 angle_t centerangle = 0;
1434
1435 INT32 dispoffset = thing->info->dispoffset;
1436
1437 //SoM: 3/17/2000
1438 fixed_t gz = 0, gzt = 0;
1439 INT32 heightsec, phs;
1440 INT32 light = 0;
1441 fixed_t this_scale = thing->scale;
1442 fixed_t spritexscale, spriteyscale;
1443
1444 // rotsprite
1445 fixed_t spr_width, spr_height;
1446 fixed_t spr_offset, spr_topoffset;
1447
1448 #ifdef ROTSPRITE
1449 patch_t *rotsprite = NULL;
1450 INT32 rollangle = 0;
1451 #endif
1452
1453 // transform the origin point
1454 tr_x = thing->x - viewx;
1455 tr_y = thing->y - viewy;
1456
1457 basetz = tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
1458
1459 // thing is behind view plane?
1460 if (!papersprite && (tz < FixedMul(MINZ, this_scale))) // papersprite clipping is handled later
1461 return;
1462
1463 basetx = tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); // sideways distance
1464
1465 // too far off the side?
1466 if (!papersprite && abs(tx) > FixedMul(tz, fovtan)<<2) // papersprite clipping is handled later
1467 return;
1468
1469 // aspect ratio stuff
1470 xscale = FixedDiv(projection, tz);
1471 sortscale = FixedDiv(projectiony, tz);
1472
1473 // decide which patch to use for sprite relative to player
1474 #ifdef RANGECHECK
1475 if ((size_t)(thing->sprite) >= numsprites)
1476 I_Error("R_ProjectSprite: invalid sprite number %d ", thing->sprite);
1477 #endif
1478
1479 frame = thing->frame&FF_FRAMEMASK;
1480
1481 //Fab : 02-08-98: 'skin' override spritedef currently used for skin
1482 if (thing->skin && thing->sprite == SPR_PLAY)
1483 {
1484 sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
1485 #ifdef ROTSPRITE
1486 sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
1487 #endif
1488 if (frame >= sprdef->numframes) {
1489 CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid skins[\"%s\"].sprites[%sSPR2_%s] frame %s\n"), ((skin_t *)thing->skin)->name, ((thing->sprite2 & FF_SPR2SUPER) ? "FF_SPR2SUPER|": ""), spr2names[(thing->sprite2 & ~FF_SPR2SUPER)], sizeu5(frame));
1490 thing->sprite = states[S_UNKNOWN].sprite;
1491 thing->frame = states[S_UNKNOWN].frame;
1492 sprdef = &sprites[thing->sprite];
1493 #ifdef ROTSPRITE
1494 sprinfo = &spriteinfo[thing->sprite];
1495 #endif
1496 frame = thing->frame&FF_FRAMEMASK;
1497 }
1498 }
1499 else
1500 {
1501 sprdef = &sprites[thing->sprite];
1502 #ifdef ROTSPRITE
1503 sprinfo = &spriteinfo[thing->sprite];
1504 #endif
1505
1506 if (frame >= sprdef->numframes)
1507 {
1508 CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid sprite frame %s/%s for %s\n"),
1509 sizeu1(frame), sizeu2(sprdef->numframes), sprnames[thing->sprite]);
1510 if (thing->sprite == thing->state->sprite && thing->frame == thing->state->frame)
1511 {
1512 thing->state->sprite = states[S_UNKNOWN].sprite;
1513 thing->state->frame = states[S_UNKNOWN].frame;
1514 }
1515 thing->sprite = states[S_UNKNOWN].sprite;
1516 thing->frame = states[S_UNKNOWN].frame;
1517 sprdef = &sprites[thing->sprite];
1518 sprinfo = &spriteinfo[thing->sprite];
1519 frame = thing->frame&FF_FRAMEMASK;
1520 }
1521 }
1522
1523 sprframe = &sprdef->spriteframes[frame];
1524
1525 #ifdef PARANOIA
1526 if (!sprframe)
1527 I_Error("R_ProjectSprite: sprframes NULL for sprite %d\n", thing->sprite);
1528 #endif
1529
1530 if (sprframe->rotate != SRF_SINGLE || papersprite)
1531 {
1532 ang = R_PointToAngle (thing->x, thing->y) - (thing->player ? thing->player->drawangle : thing->angle);
1533 if (mirrored)
1534 ang = InvAngle(ang);
1535 }
1536
1537 if (sprframe->rotate == SRF_SINGLE)
1538 {
1539 // use single rotation for all views
1540 rot = 0; //Fab: for vis->patch below
1541 lump = sprframe->lumpid[0]; //Fab: see note above
1542 flip = sprframe->flip; // Will only be 0 or 0xFFFF
1543 }
1544 else
1545 {
1546 // choose a different rotation based on player view
1547 //ang = R_PointToAngle (thing->x, thing->y) - thing->angle;
1548
1549 if ((sprframe->rotate & SRF_RIGHT) && (ang < ANGLE_180)) // See from right
1550 rot = 6; // F7 slot
1551 else if ((sprframe->rotate & SRF_LEFT) && (ang >= ANGLE_180)) // See from left
1552 rot = 2; // F3 slot
1553 else if (sprframe->rotate & SRF_3DGE) // 16-angle mode
1554 {
1555 rot = (ang+ANGLE_180+ANGLE_11hh)>>28;
1556 rot = ((rot & 1)<<3)|(rot>>1);
1557 }
1558 else // Normal behaviour
1559 rot = (ang+ANGLE_202h)>>29;
1560
1561 //Fab: lumpid is the index for spritewidth,spriteoffset... tables
1562 lump = sprframe->lumpid[rot];
1563 flip = sprframe->flip & (1<<rot);
1564 }
1565
1566 I_Assert(lump < max_spritelumps);
1567
1568 if (thing->skin && ((skin_t *)thing->skin)->flags & SF_HIRES)
1569 this_scale = FixedMul(this_scale, ((skin_t *)thing->skin)->highresscale);
1570
1571 spr_width = spritecachedinfo[lump].width;
1572 spr_height = spritecachedinfo[lump].height;
1573 spr_offset = spritecachedinfo[lump].offset;
1574 spr_topoffset = spritecachedinfo[lump].topoffset;
1575
1576 //Fab: lumppat is the lump number of the patch to use, this is different
1577 // than lumpid for sprites-in-pwad : the graphics are patched
1578 patch = W_CachePatchNum(sprframe->lumppat[rot], PU_SPRITE);
1579
1580 #ifdef ROTSPRITE
1581 if (thing->rollangle
1582 && !(splat && !(thing->renderflags & RF_NOSPLATROLLANGLE)))
1583 {
1584 rollangle = R_GetRollAngle(thing->rollangle);
1585 rotsprite = Patch_GetRotatedSprite(sprframe, (thing->frame & FF_FRAMEMASK), rot, flip, false, sprinfo, rollangle);
1586
1587 if (rotsprite != NULL)
1588 {
1589 patch = rotsprite;
1590 cut |= SC_ISROTATED;
1591
1592 spr_width = rotsprite->width << FRACBITS;
1593 spr_height = rotsprite->height << FRACBITS;
1594 spr_offset = rotsprite->leftoffset << FRACBITS;
1595 spr_topoffset = rotsprite->topoffset << FRACBITS;
1596 spr_topoffset += FEETADJUST;
1597
1598 // flip -> rotate, not rotate -> flip
1599 flip = 0;
1600 }
1601 }
1602 #endif
1603
1604 flip = !flip != !hflip;
1605
1606 // calculate edges of the shape
1607 spritexscale = thing->spritexscale;
1608 spriteyscale = thing->spriteyscale;
1609 if (spritexscale < 1 || spriteyscale < 1)
1610 return;
1611
1612 if (thing->renderflags & RF_ABSOLUTEOFFSETS)
1613 {
1614 spr_offset = thing->spritexoffset;
1615 spr_topoffset = thing->spriteyoffset;
1616 }
1617 else
1618 {
1619 SINT8 flipoffset = 1;
1620
1621 if ((thing->renderflags & RF_FLIPOFFSETS) && flip)
1622 flipoffset = -1;
1623
1624 spr_offset += thing->spritexoffset * flipoffset;
1625 spr_topoffset += thing->spriteyoffset * flipoffset;
1626 }
1627
1628 if (flip)
1629 offset = spr_offset - spr_width;
1630 else
1631 offset = -spr_offset;
1632
1633 offset = FixedMul(offset, FixedMul(spritexscale, this_scale));
1634 offset2 = FixedMul(spr_width, FixedMul(spritexscale, this_scale));
1635
1636 if (papersprite)
1637 {
1638 fixed_t xscale2, yscale2, cosmul, sinmul, tx2, tz2;
1639 INT32 range;
1640
1641 if (ang >= ANGLE_180)
1642 {
1643 offset *= -1;
1644 offset2 *= -1;
1645 }
1646
1647 cosmul = FINECOSINE(thing->angle>>ANGLETOFINESHIFT);
1648 sinmul = FINESINE(thing->angle>>ANGLETOFINESHIFT);
1649
1650 tr_x += FixedMul(offset, cosmul);
1651 tr_y += FixedMul(offset, sinmul);
1652 tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
1653
1654 tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos);
1655
1656 // Get paperoffset (offset) and paperoffset (distance)
1657 paperoffset = -FixedMul(tr_x, cosmul) - FixedMul(tr_y, sinmul);
1658 paperdistance = -FixedMul(tr_x, sinmul) + FixedMul(tr_y, cosmul);
1659 if (paperdistance < 0)
1660 {
1661 paperoffset = -paperoffset;
1662 paperdistance = -paperdistance;
1663 }
1664 centerangle = viewangle - thing->angle;
1665
1666 tr_x += FixedMul(offset2, cosmul);
1667 tr_y += FixedMul(offset2, sinmul);
1668 tz2 = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
1669
1670 tx2 = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos);
1671
1672 if (max(tz, tz2) < FixedMul(MINZ, this_scale)) // non-papersprite clipping is handled earlier
1673 return;
1674
1675 // Needs partially clipped
1676 if (tz < FixedMul(MINZ, this_scale))
1677 {
1678 fixed_t div = FixedDiv(tz2-tz, FixedMul(MINZ, this_scale)-tz);
1679 tx += FixedDiv(tx2-tx, div);
1680 tz = FixedMul(MINZ, this_scale);
1681 }
1682 else if (tz2 < FixedMul(MINZ, this_scale))
1683 {
1684 fixed_t div = FixedDiv(tz-tz2, FixedMul(MINZ, this_scale)-tz2);
1685 tx2 += FixedDiv(tx-tx2, div);
1686 tz2 = FixedMul(MINZ, this_scale);
1687 }
1688
1689 if (tx2 < -(FixedMul(tz2, fovtan)<<2) || tx > FixedMul(tz, fovtan)<<2) // too far off the side?
1690 return;
1691
1692 yscale = FixedDiv(projectiony, tz);
1693 xscale = FixedDiv(projection, tz);
1694
1695 x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
1696
1697 // off the right side?
1698 if (x1 > viewwidth)
1699 return;
1700
1701 yscale2 = FixedDiv(projectiony, tz2);
1702 xscale2 = FixedDiv(projection, tz2);
1703
1704 x2 = (centerxfrac + FixedMul(tx2,xscale2))>>FRACBITS;
1705
1706 // off the left side
1707 if (x2 < 0)
1708 return;
1709
1710 if ((range = x2 - x1) <= 0)
1711 return;
1712
1713 range++; // fencepost problem
1714
1715 scalestep = ((yscale2 - yscale)/range) ?: 1;
1716 xscale = FixedDiv(range<<FRACBITS, abs(offset2));
1717
1718 // The following two are alternate sorting methods which might be more applicable in some circumstances. TODO - maybe enable via MF2?
1719 // sortscale = max(yscale, yscale2);
1720 // sortscale = min(yscale, yscale2);
1721 }
1722 else
1723 {
1724 scalestep = 0;
1725 yscale = sortscale;
1726 tx += offset;
1727 x1 = (centerxfrac + FixedMul(tx,xscale))>>FRACBITS;
1728
1729 // off the right side?
1730 if (x1 > viewwidth)
1731 return;
1732
1733 tx += offset2;
1734 x2 = ((centerxfrac + FixedMul(tx,xscale))>>FRACBITS); x2--;
1735
1736 // off the left side
1737 if (x2 < 0)
1738 return;
1739 }
1740
1741 // Adjust the sort scale if needed
1742 if (splat)
1743 {
1744 sort_z = (patch->height - patch->topoffset) * FRACUNIT;
1745 ang = (viewangle >> ANGLETOFINESHIFT);
1746 sort_x = FixedMul(FixedMul(FixedMul(spritexscale, this_scale), sort_z), FINECOSINE(ang));
1747 sort_y = FixedMul(FixedMul(FixedMul(spriteyscale, this_scale), sort_z), FINESINE(ang));
1748 }
1749
1750 if ((thing->flags2 & MF2_LINKDRAW) && thing->tracer) // toast 16/09/16 (SYMMETRY)
1751 {
1752 fixed_t linkscale;
1753
1754 thing = thing->tracer;
1755
1756 if (! R_ThingVisible(thing))
1757 return;
1758
1759 tr_x = (thing->x + sort_x) - viewx;
1760 tr_y = (thing->y + sort_y) - viewy;
1761 tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
1762 linkscale = FixedDiv(projectiony, tz);
1763
1764 if (tz < FixedMul(MINZ, this_scale))
1765 return;
1766
1767 if (sortscale < linkscale)
1768 dispoffset *= -1; // if it's physically behind, make sure it's ordered behind (if dispoffset > 0)
1769
1770 sortscale = linkscale; // now make sure it's linked
1771 cut |= SC_LINKDRAW;
1772 }
1773 else if (splat)
1774 {
1775 tr_x = (thing->x + sort_x) - viewx;
1776 tr_y = (thing->y + sort_y) - viewy;
1777 sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
1778 sortscale = FixedDiv(projectiony, sort_z);
1779 }
1780
1781 // Calculate the splat's sortscale
1782 if (splat)
1783 {
1784 tr_x = (thing->x - sort_x) - viewx;
1785 tr_y = (thing->y - sort_y) - viewy;
1786 sort_z = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin);
1787 sortsplat = FixedDiv(projectiony, sort_z);
1788 }
1789
1790 // PORTAL SPRITE CLIPPING
1791 if (portalrender && portalclipline)
1792 {
1793 if (x2 < portalclipstart || x1 >= portalclipend)
1794 return;
1795
1796 if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0)
1797 return;
1798 }
1799
1800 // Determine the translucency value.
1801 if (oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW) // actually only the player should use this (temporary invisibility)
1802 trans = tr_trans80; // because now the translucency is set through FF_TRANSMASK
1803 else if (oldthing->frame & FF_TRANSMASK)
1804 {
1805 trans = (oldthing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT;
1806 if (!R_BlendLevelVisible(oldthing->blendmode, trans))
1807 return;
1808 }
1809 else
1810 trans = 0;
1811
1812 // Check if this sprite needs to be rendered like a shadow
1813 shadowdraw = (!!(thing->renderflags & RF_SHADOWDRAW) && !(papersprite || splat));
1814 shadoweffects = (thing->renderflags & RF_SHADOWEFFECTS);
1815 shadowskew = (shadowdraw && thing->standingslope);
1816
1817 if (shadowdraw || shadoweffects)
1818 {
1819 fixed_t groundz = R_GetShadowZ(thing, NULL);
1820 boolean isflipped = (thing->eflags & MFE_VERTICALFLIP);
1821
1822 if (shadoweffects)
1823 {
1824 mobj_t *caster = thing->target;
1825
1826 if (caster && !P_MobjWasRemoved(caster))
1827 {
1828 fixed_t floordiff;
1829
1830 if (abs(groundz-viewz)/tz > 4)
1831 return; // Prevent stretchy shadows and possible crashes
1832
1833 floordiff = abs((isflipped ? caster->height : 0) + caster->z - groundz);
1834 trans += ((floordiff / (100*FRACUNIT)) + 3);
1835 shadowscale = FixedMul(FRACUNIT - floordiff/640, caster->scale);
1836 }
1837 else
1838 trans += 3;
1839
1840 if (trans >= NUMTRANSMAPS)
1841 return;
1842
1843 trans--;
1844 }
1845
1846 if (shadowdraw)
1847 {
1848 spritexscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spritexscale));
1849 spriteyscale = FixedMul(thing->radius * 2, FixedMul(shadowscale, spriteyscale));
1850 spriteyscale = FixedMul(spriteyscale, FixedDiv(abs(groundz - viewz), tz));
1851 spriteyscale = min(spriteyscale, spritexscale) / patch->height;
1852 spritexscale /= patch->width;
1853 }
1854 else
1855 {
1856 spritexscale = FixedMul(shadowscale, spritexscale);
1857 spriteyscale = FixedMul(shadowscale, spriteyscale);
1858 }
1859
1860 if (shadowskew)
1861 {
1862 R_SkewShadowSprite(thing, thing->standingslope, groundz, patch->height, shadowscale, &spriteyscale, &sheartan);
1863
1864 gzt = (isflipped ? (thing->z + thing->height) : thing->z) + patch->height * spriteyscale / 2;
1865 gz = gzt - patch->height * spriteyscale;
1866
1867 cut |= SC_SHEAR;
1868 }
1869 }
1870
1871 if (!shadowskew)
1872 {
1873 //SoM: 3/17/2000: Disregard sprites that are out of view..
1874 if (vflip)
1875 {
1876 // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned.
1877 // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course.
1878 // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes!
1879 gz = oldthing->z + oldthing->height - FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale));
1880 gzt = gz + FixedMul(spr_height, FixedMul(spriteyscale, this_scale));
1881 }
1882 else
1883 {
1884 gzt = oldthing->z + FixedMul(spr_topoffset, FixedMul(spriteyscale, this_scale));
1885 gz = gzt - FixedMul(spr_height, FixedMul(spriteyscale, this_scale));
1886 }
1887 }
1888
1889 if (thing->subsector->sector->cullheight)
1890 {
1891 if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt))
1892 return;
1893 }
1894
1895 if (thing->subsector->sector->numlights)
1896 {
1897 INT32 lightnum;
1898 fixed_t top = (splat) ? gz : gzt;
1899 light = thing->subsector->sector->numlights - 1;
1900
1901 // R_GetPlaneLight won't work on sloped lights!
1902 for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) {
1903 fixed_t h = P_GetLightZAt(&thing->subsector->sector->lightlist[lightnum], thing->x, thing->y);
1904 if (h <= top) {
1905 light = lightnum - 1;
1906 break;
1907 }
1908 }
1909 //light = R_GetPlaneLight(thing->subsector->sector, gzt, false);
1910 lightnum = (*thing->subsector->sector->lightlist[light].lightlevel >> LIGHTSEGSHIFT);
1911
1912 if (lightnum < 0)
1913 spritelights = scalelight[0];
1914 else if (lightnum >= LIGHTLEVELS)
1915 spritelights = scalelight[LIGHTLEVELS-1];
1916 else
1917 spritelights = scalelight[lightnum];
1918 }
1919
1920 heightsec = thing->subsector->sector->heightsec;
1921 if (viewplayer->mo && viewplayer->mo->subsector)
1922 phs = viewplayer->mo->subsector->sector->heightsec;
1923 else
1924 phs = -1;
1925
1926 if (heightsec != -1 && phs != -1) // only clip things which are in special sectors
1927 {
1928 if (viewz < sectors[phs].floorheight ?
1929 thing->z >= sectors[heightsec].floorheight :
1930 gzt < sectors[heightsec].floorheight)
1931 return;
1932 if (viewz > sectors[phs].ceilingheight ?
1933 gzt < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight :
1934 thing->z >= sectors[heightsec].ceilingheight)
1935 return;
1936 }
1937
1938 // store information in a vissprite
1939 vis = R_NewVisSprite();
1940 vis->renderflags = thing->renderflags;
1941 vis->rotateflags = sprframe->rotate;
1942 vis->heightsec = heightsec; //SoM: 3/17/2000
1943 vis->mobjflags = thing->flags;
1944 vis->sortscale = sortscale;
1945 vis->sortsplat = sortsplat;
1946 vis->dispoffset = dispoffset; // Monster Iestyn: 23/11/15
1947 vis->gx = thing->x;
1948 vis->gy = thing->y;
1949 vis->gz = gz;
1950 vis->gzt = gzt;
1951 vis->thingheight = thing->height;
1952 vis->pz = thing->z;
1953 vis->pzt = vis->pz + vis->thingheight;
1954 vis->texturemid = FixedDiv(gzt - viewz, spriteyscale);
1955 vis->scalestep = scalestep;
1956 vis->paperoffset = paperoffset;
1957 vis->paperdistance = paperdistance;
1958 vis->centerangle = centerangle;
1959 vis->viewangle = viewangle;
1960 vis->shear.tan = sheartan;
1961 vis->shear.offset = 0;
1962
1963 vis->mobj = thing; // Easy access! Tails 06-07-2002
1964
1965 vis->x1 = x1 < portalclipstart ? portalclipstart : x1;
1966 vis->x2 = x2 >= portalclipend ? portalclipend-1 : x2;
1967
1968 vis->sector = thing->subsector->sector;
1969 vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, sortscale))>>FRACBITS);
1970 vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, sortscale))>>FRACBITS);
1971 vis->cut = cut;
1972
1973 if (thing->subsector->sector->numlights)
1974 vis->extra_colormap = *thing->subsector->sector->lightlist[light].extra_colormap;
1975 else
1976 vis->extra_colormap = thing->subsector->sector->extra_colormap;
1977
1978 vis->xscale = FixedMul(spritexscale, xscale); //SoM: 4/17/2000
1979 vis->scale = FixedMul(spriteyscale, yscale); //<<detailshift;
1980 vis->thingscale = oldthing->scale;
1981
1982 vis->spritexscale = spritexscale;
1983 vis->spriteyscale = spriteyscale;
1984 vis->spritexoffset = spr_offset;
1985 vis->spriteyoffset = spr_topoffset;
1986
1987 if (shadowdraw || shadoweffects)
1988 {
1989 iscale = (patch->width<<FRACBITS)/(x2-x1+1); // fuck it
1990 x1 += (x2-x1)/2; // reusing x1 variable
1991 vis->shear.offset = vis->x1-x1;
1992 }
1993 else
1994 iscale = FixedDiv(FRACUNIT, vis->xscale);
1995
1996 vis->shadowscale = shadowscale;
1997
1998 if (flip)
1999 {
2000 vis->startfrac = spr_width-1;
2001 vis->xiscale = -iscale;
2002 }
2003 else
2004 {
2005 vis->startfrac = 0;
2006 vis->xiscale = iscale;
2007 }
2008
2009 if (vis->x1 > x1)
2010 {
2011 vis->startfrac += FixedDiv(vis->xiscale, this_scale) * (vis->x1 - x1);
2012 vis->scale += FixedMul(scalestep, spriteyscale) * (vis->x1 - x1);
2013 }
2014
2015 if ((oldthing->blendmode != AST_COPY) && cv_translucency.value)
2016 vis->transmap = R_GetBlendTable(oldthing->blendmode, trans);
2017 else
2018 vis->transmap = NULL;
2019
2020 if (R_ThingIsFullBright(oldthing) || oldthing->flags2 & MF2_SHADOW || thing->flags2 & MF2_SHADOW)
2021 vis->cut |= SC_FULLBRIGHT;
2022 else if (R_ThingIsFullDark(oldthing))
2023 vis->cut |= SC_FULLDARK;
2024
2025 //
2026 // determine the colormap (lightlevel & special effects)
2027 //
2028 if (vis->cut & SC_FULLBRIGHT
2029 && (!vis->extra_colormap || !(vis->extra_colormap->flags & CMF_FADEFULLBRIGHTSPRITES)))
2030 {
2031 // full bright: goggles
2032 vis->colormap = colormaps;
2033 }
2034 else if (vis->cut & SC_FULLDARK)
2035 vis->colormap = scalelight[0][0];
2036 else
2037 {
2038 // diminished light
2039 lindex = FixedMul(xscale, LIGHTRESOLUTIONFIX)>>(LIGHTSCALESHIFT);
2040
2041 if (lindex >= MAXLIGHTSCALE)
2042 lindex = MAXLIGHTSCALE-1;
2043
2044 vis->colormap = spritelights[lindex];
2045 }
2046
2047 if (vflip)
2048 vis->cut |= SC_VFLIP;
2049 if (splat)
2050 vis->cut |= SC_SPLAT; // I like ya cut g
2051
2052 vis->patch = patch;
2053
2054 if (thing->subsector->sector->numlights && !(shadowdraw || splat))
2055 R_SplitSprite(vis);
2056
2057 if (oldthing->shadowscale && cv_shadow.value)
2058 R_ProjectDropShadow(oldthing, vis, oldthing->shadowscale, basetx, basetz);
2059
2060 // Debug
2061 ++objectsdrawn;
2062 }
2063
2064 static void R_ProjectPrecipitationSprite(precipmobj_t *thing)
2065 {
2066 fixed_t tr_x, tr_y;
2067 fixed_t tx, tz;
2068 fixed_t xscale, yscale; //added : 02-02-98 : aaargll..if I were a math-guy!!!
2069
2070 INT32 x1, x2;
2071
2072 spritedef_t *sprdef;
2073 spriteframe_t *sprframe;
2074 size_t lump;
2075
2076 vissprite_t *vis;
2077
2078 fixed_t iscale;
2079
2080 //SoM: 3/17/2000
2081 fixed_t gz, gzt;
2082
2083 // transform the origin point
2084 tr_x = thing->x - viewx;
2085 tr_y = thing->y - viewy;
2086
2087 tz = FixedMul(tr_x, viewcos) + FixedMul(tr_y, viewsin); // near/far distance
2088
2089 // thing is behind view plane?
2090 if (tz < MINZ)
2091 return;
2092
2093 tx = FixedMul(tr_x, viewsin) - FixedMul(tr_y, viewcos); // sideways distance
2094
2095 // too far off the side?
2096 if (abs(tx) > FixedMul(tz, fovtan)<<2)
2097 return;
2098
2099 // aspect ratio stuff :
2100 xscale = FixedDiv(projection, tz);
2101 yscale = FixedDiv(projectiony, tz);
2102
2103 // decide which patch to use for sprite relative to player
2104 #ifdef RANGECHECK
2105 if ((unsigned)thing->sprite >= numsprites)
2106 I_Error("R_ProjectPrecipitationSprite: invalid sprite number %d ",
2107 thing->sprite);
2108 #endif
2109
2110 sprdef = &sprites[thing->sprite];
2111
2112 #ifdef RANGECHECK
2113 if ((UINT8)(thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
2114 I_Error("R_ProjectPrecipitationSprite: invalid sprite frame %d : %d for %s",
2115 thing->sprite, thing->frame, sprnames[thing->sprite]);
2116 #endif
2117
2118 sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
2119
2120 #ifdef PARANOIA
2121 if (!sprframe)
2122 I_Error("R_ProjectPrecipitationSprite: sprframes NULL for sprite %d\n", thing->sprite);
2123 #endif
2124
2125 // use single rotation for all views
2126 lump = sprframe->lumpid[0]; //Fab: see note above
2127
2128 // calculate edges of the shape
2129 tx -= spritecachedinfo[lump].offset;
2130 x1 = (centerxfrac + FixedMul (tx,xscale)) >>FRACBITS;
2131
2132 // off the right side?
2133 if (x1 > viewwidth)
2134 return;
2135
2136 tx += spritecachedinfo[lump].width;
2137 x2 = ((centerxfrac + FixedMul (tx,xscale)) >>FRACBITS) - 1;
2138
2139 // off the left side
2140 if (x2 < 0)
2141 return;
2142
2143 // PORTAL SPRITE CLIPPING
2144 if (portalrender && portalclipline)
2145 {
2146 if (x2 < portalclipstart || x1 >= portalclipend)
2147 return;
2148
2149 if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0)
2150 return;
2151 }
2152
2153
2154 //SoM: 3/17/2000: Disregard sprites that are out of view..
2155 gzt = thing->z + spritecachedinfo[lump].topoffset;
2156 gz = gzt - spritecachedinfo[lump].height;
2157
2158 if (thing->subsector->sector->cullheight)
2159 {
2160 if (R_DoCulling(thing->subsector->sector->cullheight, viewsector->cullheight, viewz, gz, gzt))
2161 goto weatherthink;
2162 }
2163
2164 // store information in a vissprite
2165 vis = R_NewVisSprite();
2166 vis->scale = vis->sortscale = yscale; //<<detailshift;
2167 vis->dispoffset = 0; // Monster Iestyn: 23/11/15
2168 vis->gx = thing->x;
2169 vis->gy = thing->y;
2170 vis->gz = gz;
2171 vis->gzt = gzt;
2172 vis->thingheight = 4*FRACUNIT;
2173 vis->pz = thing->z;
2174 vis->pzt = vis->pz + vis->thingheight;
2175 vis->texturemid = vis->gzt - viewz;
2176 vis->scalestep = 0;
2177 vis->paperdistance = 0;
2178 vis->shear.tan = 0;
2179 vis->shear.offset = 0;
2180
2181 vis->x1 = x1 < portalclipstart ? portalclipstart : x1;
2182 vis->x2 = x2 >= portalclipend ? portalclipend-1 : x2;
2183
2184 vis->xscale = xscale; //SoM: 4/17/2000
2185 vis->sector = thing->subsector->sector;
2186 vis->szt = (INT16)((centeryfrac - FixedMul(vis->gzt - viewz, yscale))>>FRACBITS);
2187 vis->sz = (INT16)((centeryfrac - FixedMul(vis->gz - viewz, yscale))>>FRACBITS);
2188
2189 iscale = FixedDiv(FRACUNIT, xscale);
2190
2191 vis->startfrac = 0;
2192 vis->xiscale = iscale;
2193
2194 if (vis->x1 > x1)
2195 vis->startfrac += vis->xiscale*(vis->x1-x1);
2196
2197 //Fab: lumppat is the lump number of the patch to use, this is different
2198 // than lumpid for sprites-in-pwad : the graphics are patched
2199 vis->patch = W_CachePatchNum(sprframe->lumppat[0], PU_SPRITE);
2200
2201 // specific translucency
2202 if (thing->frame & FF_TRANSMASK)
2203 vis->transmap = R_GetTranslucencyTable((thing->frame & FF_TRANSMASK) >> FF_TRANSSHIFT);
2204 else
2205 vis->transmap = NULL;
2206
2207 vis->mobj = (mobj_t *)thing;
2208 vis->mobjflags = 0;
2209 vis->cut = SC_PRECIP;
2210 vis->extra_colormap = thing->subsector->sector->extra_colormap;
2211 vis->heightsec = thing->subsector->sector->heightsec;
2212
2213 // Fullbright
2214 vis->colormap = colormaps;
2215
2216 weatherthink:
2217 // okay... this is a hack, but weather isn't networked, so it should be ok
2218 if (!(thing->precipflags & PCF_THUNK))
2219 {
2220 if (thing->precipflags & PCF_RAIN)
2221 P_RainThinker(thing);
2222 else
2223 P_SnowThinker(thing);
2224 thing->precipflags |= PCF_THUNK;
2225 }
2226 }
2227
2228 // R_AddSprites
2229 // During BSP traversal, this adds sprites by sector.
2230 //
2231 void R_AddSprites(sector_t *sec, INT32 lightlevel)
2232 {
2233 mobj_t *thing;
2234 precipmobj_t *precipthing; // Tails 08-25-2002
2235 INT32 lightnum;
2236 fixed_t limit_dist, hoop_limit_dist;
2237
2238 if (rendermode != render_soft)
2239 return;
2240
2241 // BSP is traversed by subsector.
2242 // A sector might have been split into several
2243 // subsectors during BSP building.
2244 // Thus we check whether its already added.
2245 if (sec->validcount == validcount)
2246 return;
2247
2248 // Well, now it will be done.
2249 sec->validcount = validcount;
2250
2251 if (!sec->numlights)
2252 {
2253 if (sec->heightsec == -1) lightlevel = sec->lightlevel;
2254
2255 lightnum = (lightlevel >> LIGHTSEGSHIFT);
2256
2257 if (lightnum < 0)
2258 spritelights = scalelight[0];
2259 else if (lightnum >= LIGHTLEVELS)
2260 spritelights = scalelight[LIGHTLEVELS-1];
2261 else
2262 spritelights = scalelight[lightnum];
2263 }
2264
2265 // Handle all things in sector.
2266 // If a limit exists, handle things a tiny bit different.
2267 limit_dist = (fixed_t)(cv_drawdist.value) << FRACBITS;
2268 hoop_limit_dist = (fixed_t)(cv_drawdist_nights.value) << FRACBITS;
2269 for (thing = sec->thinglist; thing; thing = thing->snext)
2270 {
2271 if (R_ThingVisibleWithinDist(thing, limit_dist, hoop_limit_dist))
2272 R_ProjectSprite(thing);
2273 }
2274
2275 // no, no infinite draw distance for precipitation. this option at zero is supposed to turn it off
2276 if ((limit_dist = (fixed_t)cv_drawdist_precip.value << FRACBITS))
2277 {
2278 for (precipthing = sec->preciplist; precipthing; precipthing = precipthing->snext)
2279 {
2280 if (R_PrecipThingVisible(precipthing, limit_dist))
2281 R_ProjectPrecipitationSprite(precipthing);
2282 }
2283 }
2284 }
2285
2286 //
2287 // R_SortVisSprites
2288 //
2289 static void R_SortVisSprites(vissprite_t* vsprsortedhead, UINT32 start, UINT32 end)
2290 {
2291 UINT32 i, linkedvissprites = 0;
2292 vissprite_t *ds, *dsprev, *dsnext, *dsfirst;
2293 vissprite_t *best = NULL;
2294 vissprite_t unsorted;
2295 fixed_t bestscale;
2296 INT32 bestdispoffset;
2297
2298 unsorted.next = unsorted.prev = &unsorted;
2299
2300 dsfirst = R_GetVisSprite(start);
2301
2302 // The first's prev and last's next will be set to
2303 // nonsense, but are fixed in a moment
2304 for (i = start, dsnext = dsfirst, ds = NULL; i < end; i++)
2305 {
2306 dsprev = ds;
2307 ds = dsnext;
2308 if (i < end - 1) dsnext = R_GetVisSprite(i + 1);
2309
2310 ds->next = dsnext;
2311 ds->prev = dsprev;
2312 ds->linkdraw = NULL;
2313 }
2314
2315 // Fix first and last. ds still points to the last one after the loop
2316 dsfirst->prev = &unsorted;
2317 unsorted.next = dsfirst;
2318 if (ds)
2319 {
2320 ds->next = &unsorted;
2321 ds->linkdraw = NULL;
2322 }
2323 unsorted.prev = ds;
2324
2325 // bundle linkdraw
2326 for (ds = unsorted.prev; ds != &unsorted; ds = ds->prev)
2327 {
2328 if (!(ds->cut & SC_LINKDRAW))
2329 continue;
2330
2331 if (ds->cut & SC_SHADOW)
2332 continue;
2333
2334 // reuse dsfirst...
2335 for (dsfirst = unsorted.prev; dsfirst != &unsorted; dsfirst = dsfirst->prev)
2336 {
2337 // don't connect if it's also a link
2338 if (dsfirst->cut & SC_LINKDRAW)
2339 continue;
2340
2341 // don't connect to your shadow!
2342 if (dsfirst->cut & SC_SHADOW)
2343 continue;
2344
2345 // don't connect if it's not the tracer
2346 if (dsfirst->mobj != ds->mobj)
2347 continue;
2348
2349 // don't connect if the tracer's top is cut off, but lower than the link's top
2350 if ((dsfirst->cut & SC_TOP)
2351 && dsfirst->szt > ds->szt)
2352 continue;
2353
2354 // don't connect if the tracer's bottom is cut off, but higher than the link's bottom
2355 if ((dsfirst->cut & SC_BOTTOM)
2356 && dsfirst->sz < ds->sz)
2357 continue;
2358
2359 break;
2360 }
2361
2362 // remove from chain
2363 ds->next->prev = ds->prev;
2364 ds->prev->next = ds->next;
2365 linkedvissprites++;
2366
2367 if (dsfirst != &unsorted)
2368 {
2369 if (!(ds->cut & SC_FULLBRIGHT))
2370 ds->colormap = dsfirst->colormap;
2371 ds->extra_colormap = dsfirst->extra_colormap;
2372
2373 // reusing dsnext...
2374 dsnext = dsfirst->linkdraw;
2375
2376 if (!dsnext || ds->dispoffset < dsnext->dispoffset)
2377 {
2378 ds->next = dsnext;
2379 dsfirst->linkdraw = ds;
2380 }
2381 else
2382 {
2383 for (; dsnext->next != NULL; dsnext = dsnext->next)
2384 if (ds->dispoffset < dsnext->next->dispoffset)
2385 break;
2386 ds->next = dsnext->next;
2387 dsnext->next = ds;
2388 }
2389 }
2390 }
2391
2392 // pull the vissprites out by scale
2393 vsprsortedhead->next = vsprsortedhead->prev = vsprsortedhead;
2394 for (i = start; i < end-linkedvissprites; i++)
2395 {
2396 bestscale = bestdispoffset = INT32_MAX;
2397 for (ds = unsorted.next; ds != &unsorted; ds = ds->next)
2398 {
2399 #ifdef PARANOIA
2400 if (ds->cut & SC_LINKDRAW)
2401 I_Error("R_SortVisSprites: no link or discardal made for linkdraw!");
2402 #endif
2403
2404 if (ds->sortscale < bestscale)
2405 {
2406 bestscale = ds->sortscale;
2407 bestdispoffset = ds->dispoffset;
2408 best = ds;
2409 }
2410 // order visprites of same scale by dispoffset, smallest first
2411 else if (ds->sortscale == bestscale && ds->dispoffset < bestdispoffset)
2412 {
2413 bestdispoffset = ds->dispoffset;
2414 best = ds;
2415 }
2416 }
2417 best->next->prev = best->prev;
2418 best->prev->next = best->next;
2419 best->next = vsprsortedhead;
2420 best->prev = vsprsortedhead->prev;
2421 vsprsortedhead->prev->next = best;
2422 vsprsortedhead->prev = best;
2423 }
2424 }
2425
2426 //
2427 // R_CreateDrawNodes
2428 // Creates and sorts a list of drawnodes for the scene being rendered.
2429 static drawnode_t *R_CreateDrawNode(drawnode_t *link);
2430
2431 static drawnode_t nodebankhead;
2432
2433 static void R_CreateDrawNodes(maskcount_t* mask, drawnode_t* head, boolean tempskip)
2434 {
2435 drawnode_t *entry;
2436 drawseg_t *ds;
2437 INT32 i, p, best, x1, x2;
2438 fixed_t bestdelta, delta;
2439 vissprite_t *rover;
2440 static vissprite_t vsprsortedhead;
2441 drawnode_t *r2;
2442 visplane_t *plane;
2443 INT32 sintersect;
2444 fixed_t scale = 0;
2445
2446 // Add the 3D floors, thicksides, and masked textures...
2447 for (ds = drawsegs + mask->drawsegs[1]; ds-- > drawsegs + mask->drawsegs[0];)
2448 {
2449 if (ds->numthicksides)
2450 {
2451 for (i = 0; i < ds->numthicksides; i++)
2452 {
2453 entry = R_CreateDrawNode(head);
2454 entry->thickseg = ds;
2455 entry->ffloor = ds->thicksides[i];
2456 }
2457 }
2458 // Check for a polyobject plane, but only if this is a front line
2459 if (ds->curline->polyseg && ds->curline->polyseg->visplane && !ds->curline->side) {
2460 plane = ds->curline->polyseg->visplane;
2461 R_PlaneBounds(plane);
2462
2463 if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low)
2464 ;
2465 else {
2466 // Put it in!
2467 entry = R_CreateDrawNode(head);
2468 entry->plane = plane;
2469 entry->seg = ds;
2470 }
2471 ds->curline->polyseg->visplane = NULL;
2472 }
2473 if (ds->maskedtexturecol)
2474 {
2475 entry = R_CreateDrawNode(head);
2476 entry->seg = ds;
2477 }
2478 if (ds->numffloorplanes)
2479 {
2480 for (i = 0; i < ds->numffloorplanes; i++)
2481 {
2482 best = -1;
2483 bestdelta = 0;
2484 for (p = 0; p < ds->numffloorplanes; p++)
2485 {
2486 if (!ds->ffloorplanes[p])
2487 continue;
2488 plane = ds->ffloorplanes[p];
2489 R_PlaneBounds(plane);
2490
2491 if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low || plane->polyobj)
2492 {
2493 ds->ffloorplanes[p] = NULL;
2494 continue;
2495 }
2496
2497 delta = abs(plane->height - viewz);
2498 if (delta > bestdelta)
2499 {
2500 best = p;
2501 bestdelta = delta;
2502 }
2503 }
2504 if (best != -1)
2505 {
2506 entry = R_CreateDrawNode(head);
2507 entry->plane = ds->ffloorplanes[best];
2508 entry->seg = ds;
2509 ds->ffloorplanes[best] = NULL;
2510 }
2511 else
2512 break;
2513 }
2514 }
2515 }
2516
2517 if (tempskip)
2518 return;
2519
2520 // find all the remaining polyobject planes and add them on the end of the list
2521 // probably this is a terrible idea if we wanted them to be sorted properly
2522 // but it works getting them in for now
2523 for (i = 0; i < numPolyObjects; i++)
2524 {
2525 if (!PolyObjects[i].visplane)
2526 continue;
2527 plane = PolyObjects[i].visplane;
2528 R_PlaneBounds(plane);
2529
2530 if (plane->low < 0 || plane->high > vid.height || plane->high > plane->low)
2531 {
2532 PolyObjects[i].visplane = NULL;
2533 continue;
2534 }
2535 entry = R_CreateDrawNode(head);
2536 entry->plane = plane;
2537 // note: no seg is set, for what should be obvious reasons
2538 PolyObjects[i].visplane = NULL;
2539 }
2540
2541 // No vissprites in this mask?
2542 if (mask->vissprites[1] - mask->vissprites[0] == 0)
2543 return;
2544
2545 R_SortVisSprites(&vsprsortedhead, mask->vissprites[0], mask->vissprites[1]);
2546
2547 for (rover = vsprsortedhead.prev; rover != &vsprsortedhead; rover = rover->prev)
2548 {
2549 if (rover->szt > vid.height || rover->sz < 0)
2550 continue;
2551
2552 sintersect = (rover->x1 + rover->x2) / 2;
2553
2554 for (r2 = head->next; r2 != head; r2 = r2->next)
2555 {
2556 if (r2->plane)
2557 {
2558 fixed_t planeobjectz, planecameraz;
2559 if (r2->plane->minx > rover->x2 || r2->plane->maxx < rover->x1)
2560 continue;
2561 if (rover->szt > r2->plane->low || rover->sz < r2->plane->high)
2562 continue;
2563
2564 // Effective height may be different for each comparison in the case of slopes
2565 planeobjectz = P_GetZAt(r2->plane->slope, rover->gx, rover->gy, r2->plane->height);
2566 planecameraz = P_GetZAt(r2->plane->slope, viewx, viewy, r2->plane->height);
2567
2568 if (rover->mobjflags & MF_NOCLIPHEIGHT)
2569 {
2570 //Objects with NOCLIPHEIGHT can appear halfway in.
2571 if (planecameraz < viewz && rover->pz+(rover->thingheight/2) >= planeobjectz)
2572 continue;
2573 if (planecameraz > viewz && rover->pzt-(rover->thingheight/2) <= planeobjectz)
2574 continue;
2575 }
2576 else
2577 {
2578 if (planecameraz < viewz && rover->pz >= planeobjectz)
2579 continue;
2580 if (planecameraz > viewz && rover->pzt <= planeobjectz)
2581 continue;
2582 }
2583
2584 // SoM: NOTE: Because a visplane's shape and scale is not directly
2585 // bound to any single linedef, a simple poll of it's frontscale is
2586 // not adequate. We must check the entire frontscale array for any
2587 // part that is in front of the sprite.
2588
2589 x1 = rover->x1;
2590 x2 = rover->x2;
2591 if (x1 < r2->plane->minx) x1 = r2->plane->minx;
2592 if (x2 > r2->plane->maxx) x2 = r2->plane->maxx;
2593
2594 if (r2->seg) // if no seg set, assume the whole thing is in front or something stupid
2595 {
2596 for (i = x1; i <= x2; i++)
2597 {
2598 if (r2->seg->frontscale[i] > rover->sortscale)
2599 break;
2600 }
2601 if (i > x2)
2602 continue;
2603 }
2604
2605 entry = R_CreateDrawNode(NULL);
2606 (entry->prev = r2->prev)->next = entry;
2607 (entry->next = r2)->prev = entry;
2608 entry->sprite = rover;
2609 break;
2610 }
2611 else if (r2->thickseg)
2612 {
2613 fixed_t topplaneobjectz, topplanecameraz, botplaneobjectz, botplanecameraz;
2614 if (rover->x1 > r2->thickseg->x2 || rover->x2 < r2->thickseg->x1)
2615 continue;
2616
2617 scale = r2->thickseg->scale1 > r2->thickseg->scale2 ? r2->thickseg->scale1 : r2->thickseg->scale2;
2618 if (scale <= rover->sortscale)
2619 continue;
2620 scale = r2->thickseg->scale1 + (r2->thickseg->scalestep * (sintersect - r2->thickseg->x1));
2621 if (scale <= rover->sortscale)
2622 continue;
2623
2624 topplaneobjectz = P_GetFFloorTopZAt (r2->ffloor, rover->gx, rover->gy);
2625 topplanecameraz = P_GetFFloorTopZAt (r2->ffloor, viewx, viewy);
2626 botplaneobjectz = P_GetFFloorBottomZAt(r2->ffloor, rover->gx, rover->gy);
2627 botplanecameraz = P_GetFFloorBottomZAt(r2->ffloor, viewx, viewy);
2628
2629 if ((topplanecameraz > viewz && botplanecameraz < viewz) ||
2630 (topplanecameraz < viewz && rover->gzt < topplaneobjectz) ||
2631 (botplanecameraz > viewz && rover->gz > botplaneobjectz))
2632 {
2633 entry = R_CreateDrawNode(NULL);
2634 (entry->prev = r2->prev)->next = entry;
2635 (entry->next = r2)->prev = entry;
2636 entry->sprite = rover;
2637 break;
2638 }
2639 }
2640 else if (r2->seg)
2641 {
2642 if (rover->x1 > r2->seg->x2 || rover->x2 < r2->seg->x1)
2643 continue;
2644
2645 scale = r2->seg->scale1 > r2->seg->scale2 ? r2->seg->scale1 : r2->seg->scale2;
2646 if (scale <= rover->sortscale)
2647 continue;
2648 scale = r2->seg->scale1 + (r2->seg->scalestep * (sintersect - r2->seg->x1));
2649
2650 if (rover->sortscale < scale)
2651 {
2652 entry = R_CreateDrawNode(NULL);
2653 (entry->prev = r2->prev)->next = entry;
2654 (entry->next = r2)->prev = entry;
2655 entry->sprite = rover;
2656 break;
2657 }
2658 }
2659 else if (r2->sprite)
2660 {
2661 boolean infront = (r2->sprite->sortscale > rover->sortscale
2662 || (r2->sprite->sortscale == rover->sortscale && r2->sprite->dispoffset > rover->dispoffset));
2663
2664 if (rover->cut & SC_SPLAT || r2->sprite->cut & SC_SPLAT)
2665 {
2666 fixed_t scale1 = (rover->cut & SC_SPLAT ? rover->sortsplat : rover->sortscale);
2667 fixed_t scale2 = (r2->sprite->cut & SC_SPLAT ? r2->sprite->sortsplat : r2->sprite->sortscale);
2668 boolean behind = (scale2 > scale1 || (scale2 == scale1 && r2->sprite->dispoffset > rover->dispoffset));
2669
2670 if (!behind)
2671 {
2672 fixed_t z1 = 0, z2 = 0;
2673
2674 if (rover->mobj->z - viewz > 0)
2675 {
2676 z1 = rover->pz;
2677 z2 = r2->sprite->pz;
2678 }
2679 else
2680 {
2681 z1 = r2->sprite->pz;
2682 z2 = rover->pz;
2683 }
2684
2685 z1 -= viewz;
2686 z2 -= viewz;
2687
2688 infront = (z1 >= z2);
2689 }
2690 }
2691 else
2692 {
2693 if (r2->sprite->x1 > rover->x2 || r2->sprite->x2 < rover->x1)
2694 continue;
2695 if (r2->sprite->szt > rover->sz || r2->sprite->sz < rover->szt)
2696 continue;
2697 }
2698
2699 if (infront)
2700 {
2701 entry = R_CreateDrawNode(NULL);
2702 (entry->prev = r2->prev)->next = entry;
2703 (entry->next = r2)->prev = entry;
2704 entry->sprite = rover;
2705 break;
2706 }
2707 }
2708 }
2709 if (r2 == head)
2710 {
2711 entry = R_CreateDrawNode(head);
2712 entry->sprite = rover;
2713 }
2714 }
2715 }
2716
2717 static drawnode_t *R_CreateDrawNode(drawnode_t *link)
2718 {
2719 drawnode_t *node = nodebankhead.next;
2720
2721 if (node == &nodebankhead)
2722 {
2723 node = malloc(sizeof (*node));
2724 if (!node)
2725 I_Error("No more free memory to CreateDrawNode");
2726 }
2727 else
2728 (nodebankhead.next = node->next)->prev = &nodebankhead;
2729
2730 if (link)
2731 {
2732 node->next = link;
2733 node->prev = link->prev;
2734 link->prev->next = node;
2735 link->prev = node;
2736 }
2737
2738 node->plane = NULL;
2739 node->seg = NULL;
2740 node->thickseg = NULL;
2741 node->ffloor = NULL;
2742 node->sprite = NULL;
2743
2744 ps_numdrawnodes++;
2745 return node;
2746 }
2747
2748 static void R_DoneWithNode(drawnode_t *node)
2749 {
2750 (node->next->prev = node->prev)->next = node->next;
2751 (node->next = nodebankhead.next)->prev = node;
2752 (node->prev = &nodebankhead)->next = node;
2753 }
2754
2755 static void R_ClearDrawNodes(drawnode_t* head)
2756 {
2757 drawnode_t *rover;
2758 drawnode_t *next;
2759
2760 for (rover = head->next; rover != head;)
2761 {
2762 next = rover->next;
2763 R_DoneWithNode(rover);
2764 rover = next;
2765 }
2766
2767 head->next = head->prev = head;
2768 }
2769
2770 void R_InitDrawNodes(void)
2771 {
2772 nodebankhead.next = nodebankhead.prev = &nodebankhead;
2773 }
2774
2775 //
2776 // R_DrawSprite
2777 //
2778 //Fab : 26-04-98:
2779 // NOTE : uses con_clipviewtop, so that when console is on,
2780 // don't draw the part of sprites hidden under the console
2781 static void R_DrawSprite(vissprite_t *spr)
2782 {
2783 mfloorclip = spr->clipbot;
2784 mceilingclip = spr->cliptop;
2785
2786 if (spr->cut & SC_SPLAT)
2787 R_DrawFloorSplat(spr);
2788 else
2789 R_DrawVisSprite(spr);
2790 }
2791
2792 // Special drawer for precipitation sprites Tails 08-18-2002
2793 static void R_DrawPrecipitationSprite(vissprite_t *spr)
2794 {
2795 mfloorclip = spr->clipbot;
2796 mceilingclip = spr->cliptop;
2797 R_DrawPrecipitationVisSprite(spr);
2798 }
2799
2800 // R_ClipVisSprite
2801 // Clips vissprites without drawing, so that portals can work. -Red
2802 void R_ClipVisSprite(vissprite_t *spr, INT32 x1, INT32 x2, drawseg_t* dsstart, portal_t* portal)
2803 {
2804 drawseg_t *ds;
2805 INT32 x;
2806 INT32 r1;
2807 INT32 r2;
2808 fixed_t scale;
2809 fixed_t lowscale;
2810 INT32 silhouette;
2811
2812 for (x = x1; x <= x2; x++)
2813 spr->clipbot[x] = spr->cliptop[x] = -2;
2814
2815 // Scan drawsegs from end to start for obscuring segs.
2816 // The first drawseg that has a greater scale
2817 // is the clip seg.
2818 //SoM: 4/8/2000:
2819 // Pointer check was originally nonportable
2820 // and buggy, by going past LEFT end of array:
2821
2822 // for (ds = ds_p-1; ds >= drawsegs; ds--) old buggy code
2823 for (ds = ds_p; ds-- > dsstart;)
2824 {
2825 // determine if the drawseg obscures the sprite
2826 if (ds->x1 > x2 ||
2827 ds->x2 < x1 ||
2828 (!ds->silhouette
2829 && !ds->maskedtexturecol))
2830 {
2831 // does not cover sprite
2832 continue;
2833 }
2834
2835 if (ds->portalpass != 66)
2836 {
2837 if (ds->portalpass > 0 && ds->portalpass <= portalrender)
2838 continue; // is a portal
2839
2840 if (ds->scale1 > ds->scale2)
2841 {
2842 lowscale = ds->scale2;
2843 scale = ds->scale1;
2844 }
2845 else
2846 {
2847 lowscale = ds->scale1;
2848 scale = ds->scale2;
2849 }
2850
2851 if (scale < spr->sortscale ||
2852 (lowscale < spr->sortscale &&
2853 !R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
2854 {
2855 // masked mid texture?
2856 /*if (ds->maskedtexturecol)
2857 R_RenderMaskedSegRange (ds, r1, r2);*/
2858 // seg is behind sprite
2859 continue;
2860 }
2861 }
2862
2863 r1 = ds->x1 < x1 ? x1 : ds->x1;
2864 r2 = ds->x2 > x2 ? x2 : ds->x2;
2865
2866 // clip this piece of the sprite
2867 silhouette = ds->silhouette;
2868
2869 if (spr->gz >= ds->bsilheight)
2870 silhouette &= ~SIL_BOTTOM;
2871
2872 if (spr->gzt <= ds->tsilheight)
2873 silhouette &= ~SIL_TOP;
2874
2875 if (silhouette == SIL_BOTTOM)
2876 {
2877 // bottom sil
2878 for (x = r1; x <= r2; x++)
2879 if (spr->clipbot[x] == -2)
2880 spr->clipbot[x] = ds->sprbottomclip[x];
2881 }
2882 else if (silhouette == SIL_TOP)
2883 {
2884 // top sil
2885 for (x = r1; x <= r2; x++)
2886 if (spr->cliptop[x] == -2)
2887 spr->cliptop[x] = ds->sprtopclip[x];
2888 }
2889 else if (silhouette == (SIL_TOP|SIL_BOTTOM))
2890 {
2891 // both
2892 for (x = r1; x <= r2; x++)
2893 {
2894 if (spr->clipbot[x] == -2)
2895 spr->clipbot[x] = ds->sprbottomclip[x];
2896 if (spr->cliptop[x] == -2)
2897 spr->cliptop[x] = ds->sprtopclip[x];
2898 }
2899 }
2900 }
2901 //SoM: 3/17/2000: Clip sprites in water.
2902 if (spr->heightsec != -1) // only things in specially marked sectors
2903 {
2904 fixed_t mh, h;
2905 INT32 phs = viewplayer->mo->subsector->sector->heightsec;
2906 if ((mh = sectors[spr->heightsec].floorheight) > spr->gz &&
2907 (h = centeryfrac - FixedMul(mh -= viewz, spr->sortscale)) >= 0 &&
2908 (h >>= FRACBITS) < viewheight)
2909 {
2910 if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight))
2911 { // clip bottom
2912 for (x = x1; x <= x2; x++)
2913 if (spr->clipbot[x] == -2 || h < spr->clipbot[x])
2914 spr->clipbot[x] = (INT16)h;
2915 }
2916 else // clip top
2917 {
2918 for (x = x1; x <= x2; x++)
2919 if (spr->cliptop[x] == -2 || h > spr->cliptop[x])
2920 spr->cliptop[x] = (INT16)h;
2921 }
2922 }
2923
2924 if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt &&
2925 (h = centeryfrac - FixedMul(mh-viewz, spr->sortscale)) >= 0 &&
2926 (h >>= FRACBITS) < viewheight)
2927 {
2928 if (phs != -1 && viewz >= sectors[phs].ceilingheight)
2929 { // clip bottom
2930 for (x = x1; x <= x2; x++)
2931 if (spr->clipbot[x] == -2 || h < spr->clipbot[x])
2932 spr->clipbot[x] = (INT16)h;
2933 }
2934 else // clip top
2935 {
2936 for (x = x1; x <= x2; x++)
2937 if (spr->cliptop[x] == -2 || h > spr->cliptop[x])
2938 spr->cliptop[x] = (INT16)h;
2939 }
2940 }
2941 }
2942 if (spr->cut & SC_TOP && spr->cut & SC_BOTTOM)
2943 {
2944 for (x = x1; x <= x2; x++)
2945 {
2946 if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x])
2947 spr->cliptop[x] = spr->szt;
2948
2949 if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x])
2950 spr->clipbot[x] = spr->sz;
2951 }
2952 }
2953 else if (spr->cut & SC_TOP)
2954 {
2955 for (x = x1; x <= x2; x++)
2956 {
2957 if (spr->cliptop[x] == -2 || spr->szt > spr->cliptop[x])
2958 spr->cliptop[x] = spr->szt;
2959 }
2960 }
2961 else if (spr->cut & SC_BOTTOM)
2962 {
2963 for (x = x1; x <= x2; x++)
2964 {
2965 if (spr->clipbot[x] == -2 || spr->sz < spr->clipbot[x])
2966 spr->clipbot[x] = spr->sz;
2967 }
2968 }
2969
2970 // all clipping has been performed, so store the values - what, did you think we were drawing them NOW?
2971
2972 // check for unclipped columns
2973 for (x = x1; x <= x2; x++)
2974 {
2975 if (spr->clipbot[x] == -2)
2976 spr->clipbot[x] = (INT16)viewheight;
2977
2978 if (spr->cliptop[x] == -2)
2979 //Fab : 26-04-98: was -1, now clips against console bottom
2980 spr->cliptop[x] = (INT16)con_clipviewtop;
2981 }
2982
2983 if (portal)
2984 {
2985 for (x = x1; x <= x2; x++)
2986 {
2987 if (spr->clipbot[x] > portal->floorclip[x - portal->start])
2988 spr->clipbot[x] = portal->floorclip[x - portal->start];
2989 if (spr->cliptop[x] < portal->ceilingclip[x - portal->start])
2990 spr->cliptop[x] = portal->ceilingclip[x - portal->start];
2991 }
2992 }
2993 }
2994
2995 void R_ClipSprites(drawseg_t* dsstart, portal_t* portal)
2996 {
2997 for (; clippedvissprites < visspritecount; clippedvissprites++)
2998 {
2999 vissprite_t *spr = R_GetVisSprite(clippedvissprites);
3000 INT32 x1 = (spr->cut & SC_SPLAT) ? 0 : spr->x1;
3001 INT32 x2 = (spr->cut & SC_SPLAT) ? viewwidth : spr->x2;
3002 R_ClipVisSprite(spr, x1, x2, dsstart, portal);
3003 }
3004 }
3005
3006 /* Check if thing may be drawn from our current view. */
3007 boolean R_ThingVisible (mobj_t *thing)
3008 {
3009 return (!(
3010 thing->sprite == SPR_NULL ||
3011 ( thing->flags2 & (MF2_DONTDRAW) ) ||
3012 (r_viewmobj && (thing == r_viewmobj || (r_viewmobj->player && r_viewmobj->player->followmobj == thing)))
3013 ));
3014 }
3015
3016 boolean R_ThingVisibleWithinDist (mobj_t *thing,
3017 fixed_t limit_dist,
3018 fixed_t hoop_limit_dist)
3019 {
3020 fixed_t approx_dist;
3021
3022 if (! R_ThingVisible(thing))
3023 return false;
3024
3025 approx_dist = P_AproxDistance(viewx-thing->x, viewy-thing->y);
3026
3027 if (thing->sprite == SPR_HOOP)
3028 {
3029 if (hoop_limit_dist && approx_dist > hoop_limit_dist)
3030 return false;
3031 }
3032 else
3033 {
3034 if (limit_dist && approx_dist > limit_dist)
3035 return false;
3036 }
3037
3038 return true;
3039 }
3040
3041 /* Check if precipitation may be drawn from our current view. */
3042 boolean R_PrecipThingVisible (precipmobj_t *precipthing,
3043 fixed_t limit_dist)
3044 {
3045 fixed_t approx_dist;
3046
3047 if (( precipthing->precipflags & PCF_INVISIBLE ))
3048 return false;
3049
3050 approx_dist = P_AproxDistance(viewx-precipthing->x, viewy-precipthing->y);
3051
3052 return ( approx_dist <= limit_dist );
3053 }
3054
3055 boolean R_ThingHorizontallyFlipped(mobj_t *thing)
3056 {
3057 return (thing->frame & FF_HORIZONTALFLIP || thing->renderflags & RF_HORIZONTALFLIP);
3058 }
3059
3060 boolean R_ThingVerticallyFlipped(mobj_t *thing)
3061 {
3062 return (thing->frame & FF_VERTICALFLIP || thing->renderflags & RF_VERTICALFLIP);
3063 }
3064
3065 boolean R_ThingIsPaperSprite(mobj_t *thing)
3066 {
3067 return (thing->frame & FF_PAPERSPRITE || thing->renderflags & RF_PAPERSPRITE);
3068 }
3069
3070 boolean R_ThingIsFloorSprite(mobj_t *thing)
3071 {
3072 return (thing->flags2 & MF2_SPLAT || thing->renderflags & RF_FLOORSPRITE);
3073 }
3074
3075 boolean R_ThingIsFullBright(mobj_t *thing)
3076 {
3077 return (thing->frame & FF_FULLBRIGHT || thing->renderflags & RF_FULLBRIGHT);
3078 }
3079
3080 boolean R_ThingIsFullDark(mobj_t *thing)
3081 {
3082 return (thing->renderflags & RF_FULLDARK);
3083 }
3084
3085 //
3086 // R_DrawMasked
3087 //
3088 static void R_DrawMaskedList (drawnode_t* head)
3089 {
3090 drawnode_t *r2;
3091 drawnode_t *next;
3092
3093 for (r2 = head->next; r2 != head; r2 = r2->next)
3094 {
3095 if (r2->plane)
3096 {
3097 next = r2->prev;
3098 R_DrawSinglePlane(r2->plane);
3099 R_DoneWithNode(r2);
3100 r2 = next;
3101 }
3102 else if (r2->seg && r2->seg->maskedtexturecol != NULL)
3103 {
3104 next = r2->prev;
3105 R_RenderMaskedSegRange(r2->seg, r2->seg->x1, r2->seg->x2);
3106 r2->seg->maskedtexturecol = NULL;
3107 R_DoneWithNode(r2);
3108 r2 = next;
3109 }
3110 else if (r2->thickseg)
3111 {
3112 next = r2->prev;
3113 R_RenderThickSideRange(r2->thickseg, r2->thickseg->x1, r2->thickseg->x2, r2->ffloor);
3114 R_DoneWithNode(r2);
3115 r2 = next;
3116 }
3117 else if (r2->sprite)
3118 {
3119 next = r2->prev;
3120
3121 // Tails 08-18-2002
3122 if (r2->sprite->cut & SC_PRECIP)
3123 R_DrawPrecipitationSprite(r2->sprite);
3124 else if (!r2->sprite->linkdraw)
3125 R_DrawSprite(r2->sprite);
3126 else // unbundle linkdraw
3127 {
3128 vissprite_t *ds = r2->sprite->linkdraw;
3129
3130 for (;
3131 (ds != NULL && r2->sprite->dispoffset > ds->dispoffset);
3132 ds = ds->next)
3133 R_DrawSprite(ds);
3134
3135 R_DrawSprite(r2->sprite);
3136
3137 for (; ds != NULL; ds = ds->next)
3138 R_DrawSprite(ds);
3139 }
3140
3141 R_DoneWithNode(r2);
3142 r2 = next;
3143 }
3144 }
3145 }
3146
3147 void R_DrawMasked(maskcount_t* masks, UINT8 nummasks)
3148 {
3149 drawnode_t *heads; /**< Drawnode lists; as many as number of views/portals. */
3150 SINT8 i;
3151
3152 heads = calloc(nummasks, sizeof(drawnode_t));
3153
3154 for (i = 0; i < nummasks; i++)
3155 {
3156 heads[i].next = heads[i].prev = &heads[i];
3157
3158 viewx = masks[i].viewx;
3159 viewy = masks[i].viewy;
3160 viewz = masks[i].viewz;
3161 viewsector = masks[i].viewsector;
3162
3163 R_CreateDrawNodes(&masks[i], &heads[i], false);
3164 }
3165
3166 //for (i = 0; i < nummasks; i++)
3167 // CONS_Printf("Mask no.%d:\ndrawsegs: %d\n vissprites: %d\n\n", i, masks[i].drawsegs[1] - masks[i].drawsegs[0], masks[i].vissprites[1] - masks[i].vissprites[0]);
3168
3169 for (; nummasks > 0; nummasks--)
3170 {
3171 viewx = masks[nummasks - 1].viewx;
3172 viewy = masks[nummasks - 1].viewy;
3173 viewz = masks[nummasks - 1].viewz;
3174 viewsector = masks[nummasks - 1].viewsector;
3175
3176 R_DrawMaskedList(&heads[nummasks - 1]);
3177 R_ClearDrawNodes(&heads[nummasks - 1]);
3178 }
3179
3180 free(heads);
3181 }
3182