aboutsummaryrefslogtreecommitdiff
path: root/src/r_things.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/r_things.c')
-rw-r--r--src/r_things.c1077
1 files changed, 1077 insertions, 0 deletions
diff --git a/src/r_things.c b/src/r_things.c
new file mode 100644
index 0000000..68b1011
--- /dev/null
+++ b/src/r_things.c
@@ -0,0 +1,1077 @@
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
48typedef 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
64fixed_t pspritescale;
65fixed_t pspriteiscale;
66// proff 11/06/98: Added for high-res
67fixed_t pspriteyscale;
68
69// constant arrays
70// used for psprite clipping and initializing clipping
71
72int negonearray[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow
73int 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
81spritedef_t *sprites;
82int numsprites;
83
84#define MAX_SPRITE_FRAMES 29 /* Macroized -- killough 1/25/98 */
85
86static spriteframe_t sprtemp[MAX_SPRITE_FRAMES];
87static int maxframe;
88
89//
90// R_InstallSpriteLump
91// Local function for R_InitSprites.
92//
93
94static void R_InstallSpriteLump(int lump, unsigned frame,
95 unsigned rotation, boolean 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] = (byte) 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] = (byte) 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
152static 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
265static vissprite_t *vissprites, **vissprite_ptrs; // killough
266static size_t num_vissprite, num_vissprite_alloc, num_vissprite_ptrs;
267
268//
269// R_InitSprites
270// Called at program start.
271//
272
273void 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
286void R_ClearSprites (void)
287{
288 num_vissprite = 0; // killough
289}
290
291//
292// R_NewVisSprite
293//
294
295static 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
318int *mfloorclip; // dropoff overflow
319int *mceilingclip; // dropoff overflow
320fixed_t spryscale;
321fixed_t sprtopscreen;
322
323void 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
379static 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->isplayersprite) {
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 if (vis->mobjflags & MF_TRANSLUCENT && general_translucency) // phares
417 {
418 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_TRANSLUCENT, filter, filterz);
419 tranmap = main_tranmap; // killough 4/11/98
420 }
421 else
422 colfunc = R_GetDrawColumnFunc(RDC_PIPELINE_STANDARD, filter, filterz); // killough 3/14/98, 4/11/98
423
424// proff 11/06/98: Changed for high-res
425 dcvars.iscale = FixedDiv (FRACUNIT, vis->scale);
426 dcvars.texturemid = vis->texturemid;
427 frac = vis->startfrac;
428 if (filter == RDRAW_FILTER_LINEAR)
429 frac -= (FRACUNIT>>1);
430 spryscale = vis->scale;
431 sprtopscreen = centeryfrac - FixedMul(dcvars.texturemid,spryscale);
432
433 for (dcvars.x=vis->x1 ; dcvars.x<=vis->x2 ; dcvars.x++, frac += vis->xiscale)
434 {
435 texturecolumn = frac>>FRACBITS;
436 dcvars.texu = frac;
437
438 R_DrawMaskedColumn(
439 patch,
440 colfunc,
441 &dcvars,
442 R_GetPatchColumnClamped(patch, texturecolumn),
443 R_GetPatchColumnClamped(patch, texturecolumn-1),
444 R_GetPatchColumnClamped(patch, texturecolumn+1)
445 );
446 }
447 R_UnlockPatchNum(vis->patch+firstspritelump); // cph - release lump
448}
449
450//
451// R_ProjectSprite
452// Generates a vissprite for a thing if it might be visible.
453//
454
455static void R_ProjectSprite (mobj_t* thing, int lightlevel)
456{
457 fixed_t gzt; // killough 3/27/98
458 fixed_t tx;
459 fixed_t xscale;
460 int x1;
461 int x2;
462 spritedef_t *sprdef;
463 spriteframe_t *sprframe;
464 int lump;
465 boolean flip;
466 vissprite_t *vis;
467 fixed_t iscale;
468 int heightsec; // killough 3/27/98
469
470 // transform the origin point
471 fixed_t tr_x, tr_y;
472 fixed_t fx, fy, fz;
473 fixed_t gxt, gyt;
474 fixed_t tz;
475 int width;
476
477 if (movement_smooth)
478 {
479 fx = thing->PrevX + FixedMul (tic_vars.frac, thing->x - thing->PrevX);
480 fy = thing->PrevY + FixedMul (tic_vars.frac, thing->y - thing->PrevY);
481 fz = thing->PrevZ + FixedMul (tic_vars.frac, thing->z - thing->PrevZ);
482 }
483 else
484 {
485 fx = thing->x;
486 fy = thing->y;
487 fz = thing->z;
488 }
489 tr_x = fx - viewx;
490 tr_y = fy - viewy;
491
492 gxt = FixedMul(tr_x,viewcos);
493 gyt = -FixedMul(tr_y,viewsin);
494
495 tz = gxt-gyt;
496
497 // thing is behind view plane?
498 if (tz < MINZ)
499 return;
500
501 xscale = FixedDiv(projection, tz);
502
503 gxt = -FixedMul(tr_x,viewsin);
504 gyt = FixedMul(tr_y,viewcos);
505 tx = -(gyt+gxt);
506
507 // too far off the side?
508 if (D_abs(tx)>(tz<<2))
509 return;
510
511 // decide which patch to use for sprite relative to player
512#ifdef RANGECHECK
513 if ((unsigned) thing->sprite >= (unsigned)numsprites)
514 I_Error ("R_ProjectSprite: Invalid sprite number %i", thing->sprite);
515#endif
516
517 sprdef = &sprites[thing->sprite];
518
519#ifdef RANGECHECK
520 if ((thing->frame&FF_FRAMEMASK) >= sprdef->numframes)
521 I_Error ("R_ProjectSprite: Invalid sprite frame %i : %i", thing->sprite,
522 thing->frame);
523#endif
524
525 if (!sprdef->spriteframes)
526 I_Error ("R_ProjectSprite: Missing spriteframes %i : %i", thing->sprite,
527 thing->frame);
528
529 sprframe = &sprdef->spriteframes[thing->frame & FF_FRAMEMASK];
530
531 if (sprframe->rotate)
532 {
533 // choose a different rotation based on player view
534 angle_t ang = R_PointToAngle(fx, fy);
535 unsigned rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
536 lump = sprframe->lump[rot];
537 flip = (boolean) sprframe->flip[rot];
538 }
539 else
540 {
541 // use single rotation for all views
542 lump = sprframe->lump[0];
543 flip = (boolean) sprframe->flip[0];
544 }
545
546 {
547 const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump);
548
549 /* calculate edges of the shape
550 * cph 2003/08/1 - fraggle points out that this offset must be flipped
551 * if the sprite is flipped; e.g. FreeDoom imp is messed up by this. */
552 if (flip) {
553 tx -= (patch->width - patch->leftoffset) << FRACBITS;
554 } else {
555 tx -= patch->leftoffset << FRACBITS;
556 }
557 x1 = (centerxfrac + FixedMul(tx,xscale)) >> FRACBITS;
558
559 tx += patch->width<<FRACBITS;
560 x2 = ((centerxfrac + FixedMul (tx,xscale) ) >> FRACBITS) - 1;
561
562 gzt = fz + (patch->topoffset << FRACBITS);
563 width = patch->width;
564 R_UnlockPatchNum(lump+firstspritelump);
565 }
566
567 // off the side?
568 if (x1 > viewwidth || x2 < 0)
569 return;
570
571 // killough 4/9/98: clip things which are out of view due to height
572 // e6y: fix of hanging decoration disappearing in Batman Doom MAP02
573 // centeryfrac -> viewheightfrac
574 if (fz > viewz + FixedDiv(viewheightfrac, xscale) ||
575 gzt < viewz - FixedDiv(viewheightfrac-viewheight, xscale))
576 return;
577
578 // killough 3/27/98: exclude things totally separated
579 // from the viewer, by either water or fake ceilings
580 // killough 4/11/98: improve sprite clipping for underwater/fake ceilings
581
582 heightsec = thing->subsector->sector->heightsec;
583
584 if (heightsec != -1) // only clip things which are in special sectors
585 {
586 int phs = viewplayer->mo->subsector->sector->heightsec;
587 if (phs != -1 && viewz < sectors[phs].floorheight ?
588 fz >= sectors[heightsec].floorheight :
589 gzt < sectors[heightsec].floorheight)
590 return;
591 if (phs != -1 && viewz > sectors[phs].ceilingheight ?
592 gzt < sectors[heightsec].ceilingheight &&
593 viewz >= sectors[heightsec].ceilingheight :
594 fz >= sectors[heightsec].ceilingheight)
595 return;
596 }
597
598 // store information in a vissprite
599 vis = R_NewVisSprite ();
600
601#ifdef GL_DOOM
602 if (V_GetMode() == VID_MODEGL)
603 {
604 // proff 11/99: add sprite for OpenGL
605 vis->thing = thing;
606 vis->flip = flip;
607 vis->scale = FixedDiv(projectiony, tz);
608 vis->patch = lump;
609 gld_AddSprite(vis);
610
611 return;
612 }
613#endif
614 // killough 3/27/98: save sector for special clipping later
615 vis->heightsec = heightsec;
616
617 vis->mobjflags = thing->flags;
618// proff 11/06/98: Changed for high-res
619 vis->scale = FixedDiv(projectiony, tz);
620 vis->gx = fx;
621 vis->gy = fy;
622 vis->gz = fz;
623 vis->gzt = gzt; // killough 3/27/98
624 vis->texturemid = vis->gzt - viewz;
625 vis->x1 = x1 < 0 ? 0 : x1;
626 vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
627 iscale = FixedDiv (FRACUNIT, xscale);
628
629 if (flip)
630 {
631 vis->startfrac = (width<<FRACBITS)-1;
632 vis->xiscale = -iscale;
633 }
634 else
635 {
636 vis->startfrac = 0;
637 vis->xiscale = iscale;
638 }
639
640 if (vis->x1 > x1)
641 vis->startfrac += vis->xiscale*(vis->x1-x1);
642 vis->patch = lump;
643
644 // get light level
645 if (thing->flags & MF_SHADOW)
646 vis->colormap = NULL; // shadow draw
647 else if (fixedcolormap)
648 vis->colormap = fixedcolormap; // fixed map
649 else if (thing->frame & FF_FULLBRIGHT)
650 vis->colormap = fullcolormap; // full bright // killough 3/20/98
651 else
652 { // diminished light
653 vis->colormap = R_ColourMap(lightlevel,xscale);
654 }
655}
656
657//
658// R_AddSprites
659// During BSP traversal, this adds sprites by sector.
660//
661// killough 9/18/98: add lightlevel as parameter, fixing underwater lighting
662void R_AddSprites(subsector_t* subsec, int lightlevel)
663{
664 sector_t* sec=subsec->sector;
665 mobj_t *thing;
666
667 // BSP is traversed by subsector.
668 // A sector might have been split into several
669 // subsectors during BSP building.
670 // Thus we check whether its already added.
671
672 if (sec->validcount == validcount)
673 return;
674
675 // Well, now it will be done.
676 sec->validcount = validcount;
677
678 // Handle all things in sector.
679
680 for (thing = sec->thinglist; thing; thing = thing->snext)
681 R_ProjectSprite(thing, lightlevel);
682}
683
684//
685// R_DrawPSprite
686//
687
688static void R_DrawPSprite (pspdef_t *psp, int lightlevel)
689{
690 int x1, x2;
691 spritedef_t *sprdef;
692 spriteframe_t *sprframe;
693 int lump;
694 boolean flip;
695 vissprite_t *vis;
696 vissprite_t avis;
697 int width;
698 fixed_t topoffset;
699
700 avis.isplayersprite = true;
701
702 // decide which patch to use
703
704#ifdef RANGECHECK
705 if ( (unsigned)psp->state->sprite >= (unsigned)numsprites)
706 I_Error ("R_ProjectSprite: Invalid sprite number %i", psp->state->sprite);
707#endif
708
709 sprdef = &sprites[psp->state->sprite];
710
711#ifdef RANGECHECK
712 if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
713 I_Error ("R_ProjectSprite: Invalid sprite frame %i : %li",
714 psp->state->sprite, psp->state->frame);
715#endif
716
717 sprframe = &sprdef->spriteframes[psp->state->frame & FF_FRAMEMASK];
718
719 lump = sprframe->lump[0];
720 flip = (boolean) sprframe->flip[0];
721
722 {
723 const rpatch_t* patch = R_CachePatchNum(lump+firstspritelump);
724 // calculate edges of the shape
725 fixed_t tx;
726 tx = psp->sx-160*FRACUNIT;
727
728 tx -= patch->leftoffset<<FRACBITS;
729 x1 = (centerxfrac + FixedMul (tx,pspritescale))>>FRACBITS;
730
731 tx += patch->width<<FRACBITS;
732 x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
733
734 width = patch->width;
735 topoffset = patch->topoffset<<FRACBITS;
736 R_UnlockPatchNum(lump+firstspritelump);
737 }
738
739 // off the side
740 if (x2 < 0 || x1 > viewwidth)
741 return;
742
743 // store information in a vissprite
744 vis = &avis;
745 vis->mobjflags = 0;
746 // killough 12/98: fix psprite positioning problem
747 vis->texturemid = (BASEYCENTER<<FRACBITS) /* + FRACUNIT/2 */ -
748 (psp->sy-topoffset);
749 vis->x1 = x1 < 0 ? 0 : x1;
750 vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
751// proff 11/06/98: Added for high-res
752 vis->scale = pspriteyscale;
753
754 if (flip)
755 {
756 vis->xiscale = -pspriteiscale;
757 vis->startfrac = (width<<FRACBITS)-1;
758 }
759 else
760 {
761 vis->xiscale = pspriteiscale;
762 vis->startfrac = 0;
763 }
764
765 if (vis->x1 > x1)
766 vis->startfrac += vis->xiscale*(vis->x1-x1);
767
768 vis->patch = lump;
769
770 if (viewplayer->powers[pw_invisibility] > 4*32
771 || viewplayer->powers[pw_invisibility] & 8)
772 vis->colormap = NULL; // shadow draw
773 else if (fixedcolormap)
774 vis->colormap = fixedcolormap; // fixed color
775 else if (psp->state->frame & FF_FULLBRIGHT)
776 vis->colormap = fullcolormap; // full bright // killough 3/20/98
777 else
778 // add a fudge factor to better match the original game
779 vis->colormap = R_ColourMap(lightlevel,
780 FixedMul(pspritescale, 0x2b000)); // local light
781
782 // proff 11/99: don't use software stuff in OpenGL
783 if (V_GetMode() != VID_MODEGL)
784 {
785 R_DrawVisSprite(vis, vis->x1, vis->x2);
786 }
787#ifdef GL_DOOM
788 else
789 {
790 int lightlevel;
791 sector_t tmpsec;
792 int floorlightlevel, ceilinglightlevel;
793
794 if ((vis->colormap==fixedcolormap) || (vis->colormap==fullcolormap))
795 lightlevel=255;
796 else
797 {
798// lightlevel = (viewplayer->mo->subsector->sector->lightlevel) + (extralight << LIGHTSEGSHIFT);
799 R_FakeFlat( viewplayer->mo->subsector->sector, &tmpsec,
800 &floorlightlevel, &ceilinglightlevel, false);
801 lightlevel = ((floorlightlevel+ceilinglightlevel) >> 1) + (extralight << LIGHTSEGSHIFT);
802
803 if (lightlevel < 0)
804 lightlevel = 0;
805 else if (lightlevel >= 255)
806 lightlevel = 255;
807 }
808 gld_DrawWeapon(lump,vis,lightlevel);
809 }
810#endif
811}
812
813//
814// R_DrawPlayerSprites
815//
816
817void R_DrawPlayerSprites(void)
818{
819 int i, lightlevel = viewplayer->mo->subsector->sector->lightlevel;
820 pspdef_t *psp;
821
822 // clip to screen bounds
823 mfloorclip = screenheightarray;
824 mceilingclip = negonearray;
825
826 // add all active psprites
827 for (i=0, psp=viewplayer->psprites; i<NUMPSPRITES; i++,psp++)
828 if (psp->state)
829 R_DrawPSprite (psp, lightlevel);
830}
831
832//
833// R_SortVisSprites
834//
835// Rewritten by Lee Killough to avoid using unnecessary
836// linked lists, and to use faster sorting algorithm.
837//
838
839#ifdef DJGPP
840
841// killough 9/22/98: inlined memcpy of pointer arrays
842// CPhipps - added memory as modified
843#define bcopyp(d, s, n) asm(" cld; rep; movsl;" :: "D"(d), "S"(s), "c"(n) : "%cc", "%esi", "%edi", "%ecx", "memory")
844
845#else
846
847#define bcopyp(d, s, n) memcpy(d, s, (n) * sizeof(void *))
848
849#endif
850
851// killough 9/2/98: merge sort
852
853static void msort(vissprite_t **s, vissprite_t **t, int n)
854{
855 if (n >= 16)
856 {
857 int n1 = n/2, n2 = n - n1;
858 vissprite_t **s1 = s, **s2 = s + n1, **d = t;
859
860 msort(s1, t, n1);
861 msort(s2, t, n2);
862
863 while ((*s1)->scale > (*s2)->scale ?
864 (*d++ = *s1++, --n1) : (*d++ = *s2++, --n2));
865
866 if (n2)
867 bcopyp(d, s2, n2);
868 else
869 bcopyp(d, s1, n1);
870
871 bcopyp(s, t, n);
872 }
873 else
874 {
875 int i;
876 for (i = 1; i < n; i++)
877 {
878 vissprite_t *temp = s[i];
879 if (s[i-1]->scale < temp->scale)
880 {
881 int j = i;
882 while ((s[j] = s[j-1])->scale < temp->scale && --j);
883 s[j] = temp;
884 }
885 }
886 }
887}
888
889void R_SortVisSprites (void)
890{
891 if (num_vissprite)
892 {
893 int i = num_vissprite;
894
895 // If we need to allocate more pointers for the vissprites,
896 // allocate as many as were allocated for sprites -- killough
897 // killough 9/22/98: allocate twice as many
898
899 if (num_vissprite_ptrs < num_vissprite*2)
900 {
901 free(vissprite_ptrs); // better than realloc -- no preserving needed
902 vissprite_ptrs = malloc((num_vissprite_ptrs = num_vissprite_alloc*2)
903 * sizeof *vissprite_ptrs);
904 }
905
906 while (--i>=0)
907 vissprite_ptrs[i] = vissprites+i;
908
909 // killough 9/22/98: replace qsort with merge sort, since the keys
910 // are roughly in order to begin with, due to BSP rendering.
911
912 msort(vissprite_ptrs, vissprite_ptrs + num_vissprite, num_vissprite);
913 }
914}
915
916//
917// R_DrawSprite
918//
919
920static void R_DrawSprite (vissprite_t* spr)
921{
922 drawseg_t *ds;
923 int clipbot[MAX_SCREENWIDTH]; // killough 2/8/98: // dropoff overflow
924 int cliptop[MAX_SCREENWIDTH]; // change to MAX_* // dropoff overflow
925 int x;
926 int r1;
927 int r2;
928 fixed_t scale;
929 fixed_t lowscale;
930
931 for (x = spr->x1 ; x<=spr->x2 ; x++)
932 clipbot[x] = cliptop[x] = -2;
933
934 // Scan drawsegs from end to start for obscuring segs.
935 // The first drawseg that has a greater scale is the clip seg.
936
937 // Modified by Lee Killough:
938 // (pointer check was originally nonportable
939 // and buggy, by going past LEFT end of array):
940
941 // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code
942
943 for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough
944 { // determine if the drawseg obscures the sprite
945 if (ds->x1 > spr->x2 || ds->x2 < spr->x1 ||
946 (!ds->silhouette && !ds->maskedtexturecol))
947 continue; // does not cover sprite
948
949 r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
950 r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
951
952 if (ds->scale1 > ds->scale2)
953 {
954 lowscale = ds->scale2;
955 scale = ds->scale1;
956 }
957 else
958 {
959 lowscale = ds->scale1;
960 scale = ds->scale2;
961 }
962
963 if (scale < spr->scale || (lowscale < spr->scale &&
964 !R_PointOnSegSide (spr->gx, spr->gy, ds->curline)))
965 {
966 if (ds->maskedtexturecol) // masked mid texture?
967 R_RenderMaskedSegRange(ds, r1, r2);
968 continue; // seg is behind sprite
969 }
970
971 // clip this piece of the sprite
972 // killough 3/27/98: optimized and made much shorter
973
974 if (ds->silhouette&SIL_BOTTOM && spr->gz < ds->bsilheight) //bottom sil
975 for (x=r1 ; x<=r2 ; x++)
976 if (clipbot[x] == -2)
977 clipbot[x] = ds->sprbottomclip[x];
978
979 if (ds->silhouette&SIL_TOP && spr->gzt > ds->tsilheight) // top sil
980 for (x=r1 ; x<=r2 ; x++)
981 if (cliptop[x] == -2)
982 cliptop[x] = ds->sprtopclip[x];
983 }
984
985 // killough 3/27/98:
986 // Clip the sprite against deep water and/or fake ceilings.
987 // killough 4/9/98: optimize by adding mh
988 // killough 4/11/98: improve sprite clipping for underwater/fake ceilings
989 // killough 11/98: fix disappearing sprites
990
991 if (spr->heightsec != -1) // only things in specially marked sectors
992 {
993 fixed_t h,mh;
994 int phs = viewplayer->mo->subsector->sector->heightsec;
995 if ((mh = sectors[spr->heightsec].floorheight) > spr->gz &&
996 (h = centeryfrac - FixedMul(mh-=viewz, spr->scale)) >= 0 &&
997 (h >>= FRACBITS) < viewheight) {
998 if (mh <= 0 || (phs != -1 && viewz > sectors[phs].floorheight))
999 { // clip bottom
1000 for (x=spr->x1 ; x<=spr->x2 ; x++)
1001 if (clipbot[x] == -2 || h < clipbot[x])
1002 clipbot[x] = h;
1003 }
1004 else // clip top
1005 if (phs != -1 && viewz <= sectors[phs].floorheight) // killough 11/98
1006 for (x=spr->x1 ; x<=spr->x2 ; x++)
1007 if (cliptop[x] == -2 || h > cliptop[x])
1008 cliptop[x] = h;
1009 }
1010
1011 if ((mh = sectors[spr->heightsec].ceilingheight) < spr->gzt &&
1012 (h = centeryfrac - FixedMul(mh-viewz, spr->scale)) >= 0 &&
1013 (h >>= FRACBITS) < viewheight) {
1014 if (phs != -1 && viewz >= sectors[phs].ceilingheight)
1015 { // clip bottom
1016 for (x=spr->x1 ; x<=spr->x2 ; x++)
1017 if (clipbot[x] == -2 || h < clipbot[x])
1018 clipbot[x] = h;
1019 }
1020 else // clip top
1021 for (x=spr->x1 ; x<=spr->x2 ; x++)
1022 if (cliptop[x] == -2 || h > cliptop[x])
1023 cliptop[x] = h;
1024 }
1025 }
1026 // killough 3/27/98: end special clipping for deep water / fake ceilings
1027
1028 // all clipping has been performed, so draw the sprite
1029 // check for unclipped columns
1030
1031 for (x = spr->x1 ; x<=spr->x2 ; x++) {
1032 if (clipbot[x] == -2)
1033 clipbot[x] = viewheight;
1034
1035 if (cliptop[x] == -2)
1036 cliptop[x] = -1;
1037 }
1038
1039 mfloorclip = clipbot;
1040 mceilingclip = cliptop;
1041 R_DrawVisSprite (spr, spr->x1, spr->x2);
1042}
1043
1044//
1045// R_DrawMasked
1046//
1047
1048void R_DrawMasked(void)
1049{
1050 int i;
1051 drawseg_t *ds;
1052
1053 R_SortVisSprites();
1054
1055 // draw all vissprites back to front
1056
1057 rendered_vissprites = num_vissprite;
1058 for (i = num_vissprite ;--i>=0; )
1059 R_DrawSprite(vissprite_ptrs[i]); // killough
1060
1061 // render any remaining masked mid textures
1062
1063 // Modified by Lee Killough:
1064 // (pointer check was originally nonportable
1065 // and buggy, by going past LEFT end of array):
1066
1067 // for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code
1068
1069 for (ds=ds_p ; ds-- > drawsegs ; ) // new -- killough
1070 if (ds->maskedtexturecol)
1071 R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
1072
1073 // draw the psprites on top of everything
1074 // but does not draw on side views
1075 if (!viewangleoffset)
1076 R_DrawPlayerSprites ();
1077}