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