1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
6 // Copyright (C) 1993-1996 by id Software, Inc.
8 // This source is available for distribution and/or modification
9 // only under the terms of the DOOM Source Code License as
10 // published by id Software. All rights reserved.
12 // The source is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
20 // Refresh of things, i.e. objects represented by sprites.
22 //-----------------------------------------------------------------------------
26 rcsid[] = "$Id: r_things.c,v 1.5 1997/02/03 16:47:56 b1 Exp $";
41 #define MINZ (FRACUNIT*4)
42 #define BASEYCENTER 100
44 //void R_DrawColumn (void);
45 //void R_DrawFuzzColumn (void);
62 // Sprite rotation 0 is facing the viewer,
63 // rotation 1 is one angle turn CLOCKWISE around the axis.
64 // This is not the same as the angle,
65 // which increases counter clockwise (protractor).
66 // There was a lot of stuff grabbed wrong, so I changed it...
69 fixed_t pspriteiscale;
71 lighttable_t** spritelights;
74 // used for psprite clipping and initializing clipping
75 short negonearray[SCREENWIDTH];
76 short screenheightarray[SCREENWIDTH];
80 // INITIALIZATION FUNCTIONS
83 // variables used to look up
84 // and range check thing_t sprites patches
88 spriteframe_t sprtemp[29];
96 // R_InstallSpriteLump
97 // Local function for R_InitSprites.
108 if (frame >= 29 || rotation > 8)
109 I_Error("R_InstallSpriteLump: "
110 "Bad frame characters in lump %i", lump);
112 if ((int)frame > maxframe)
117 // the lump should be used for all rotations
118 if (sprtemp[frame].rotate == false)
119 I_Error ("R_InitSprites: Sprite %s frame %c has "
120 "multip rot=0 lump", spritename, 'A'+frame);
122 if (sprtemp[frame].rotate == true)
123 I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
124 "and a rot=0 lump", spritename, 'A'+frame);
126 sprtemp[frame].rotate = false;
127 for (r=0 ; r<8 ; r++)
129 sprtemp[frame].lump[r] = lump - firstspritelump;
130 sprtemp[frame].flip[r] = (byte)flipped;
135 // the lump is only used for one rotation
136 if (sprtemp[frame].rotate == false)
137 I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
138 "and a rot=0 lump", spritename, 'A'+frame);
140 sprtemp[frame].rotate = true;
144 if (sprtemp[frame].lump[rotation] != -1)
145 I_Error ("R_InitSprites: Sprite %s : %c : %c "
146 "has two lumps mapped to it",
147 spritename, 'A'+frame, '1'+rotation);
149 sprtemp[frame].lump[rotation] = lump - firstspritelump;
150 sprtemp[frame].flip[rotation] = (byte)flipped;
158 // Pass a null terminated list of sprite names
159 // (4 chars exactly) to be used.
160 // Builds the sprite rotation matrixes to account
161 // for horizontally flipped sprites.
162 // Will report an error if the lumps are inconsistant.
163 // Only called at startup.
165 // Sprite lump names are 4 characters for the actor,
166 // a letter for the frame, and a number for the rotation.
167 // A sprite that is flippable will have an additional
168 // letter/number appended.
169 // The rotation character can be 0 to signify no rotations.
171 void R_InitSpriteDefs (char** namelist)
184 This would work if the namelist was NULL terminated which it is not.
185 The array comes from info.c which is limited to NUMSPRITES, so simply
186 use NUMSPRITES for numsprites.. simple.
188 This is left here in case a decision is made to make it NULL terminated.
190 // count the number of sprite names
192 while (*check != NULL)
195 numsprites = check-namelist;
200 numsprites = NUMSPRITES;
202 sprites = Z_Malloc(numsprites *sizeof(*sprites), PU_STATIC, NULL);
204 start = firstspritelump-1;
205 end = lastspritelump+1;
207 // scan all the lump names for each of the names,
208 // noting the highest frame letter.
209 // Just compare 4 characters as ints
210 for (i=0 ; i<numsprites ; i++)
212 spritename = namelist[i];
213 memset (sprtemp,-1, sizeof(sprtemp));
216 intname = *(int *)namelist[i];
219 // filling in the frames for whatever is found
220 for (l=start+1 ; l<end ; l++)
222 if (*(int *)lumpinfo[l].name == intname)
224 frame = lumpinfo[l].name[4] - 'A';
225 rotation = lumpinfo[l].name[5] - '0';
228 patched = W_GetNumForName (lumpinfo[l].name);
232 R_InstallSpriteLump (patched, frame, rotation, false);
234 if (lumpinfo[l].name[6])
236 frame = lumpinfo[l].name[6] - 'A';
237 rotation = lumpinfo[l].name[7] - '0';
238 R_InstallSpriteLump (l, frame, rotation, true);
243 // check the frames that were found for completeness
246 sprites[i].numframes = 0;
252 for (frame = 0 ; frame < maxframe ; frame++)
254 switch ((int)sprtemp[frame].rotate)
257 // no rotations were found for that frame at all
258 I_Error ("R_InitSprites: No patches found "
259 "for %s frame %c", namelist[i], frame+'A');
263 // only the first rotation is needed
267 // must have all 8 frames
268 for (rotation=0 ; rotation<8 ; rotation++)
269 if (sprtemp[frame].lump[rotation] == -1)
270 I_Error ("R_InitSprites: Sprite %s frame %c "
271 "is missing rotations",
272 namelist[i], frame+'A');
277 // allocate space for the frames present and copy sprtemp to it
278 sprites[i].numframes = maxframe;
279 sprites[i].spriteframes =
280 Z_Malloc (maxframe * sizeof(spriteframe_t), PU_STATIC, NULL);
281 memcpy (sprites[i].spriteframes, sprtemp, maxframe*sizeof(spriteframe_t));
292 vissprite_t vissprites[MAXVISSPRITES];
293 vissprite_t* vissprite_p;
300 // Called at program start.
302 void R_InitSprites (char** namelist)
306 for (i=0 ; i<SCREENWIDTH ; i++)
311 R_InitSpriteDefs (namelist);
318 // Called at frame start.
320 void R_ClearSprites (void)
322 vissprite_p = vissprites;
329 vissprite_t overflowsprite;
331 vissprite_t* R_NewVisSprite (void)
333 if (vissprite_p == &vissprites[MAXVISSPRITES])
334 return &overflowsprite;
337 return vissprite_p-1;
343 // R_DrawMaskedColumn
344 // Used for sprites and masked mid textures.
345 // Masked means: partly transparent, i.e. stored
346 // in posts/runs of opaque pixels.
352 fixed_t sprtopscreen;
354 void R_DrawMaskedColumn (column_t* column)
358 fixed_t basetexturemid;
360 basetexturemid = dc_texturemid;
362 for ( ; column->topdelta != 0xff ; )
364 // calculate unclipped screen coordinates
366 topscreen = sprtopscreen + spryscale*column->topdelta;
367 bottomscreen = topscreen + spryscale*column->length;
369 dc_yl = (topscreen+FRACUNIT-1)>>FRACBITS;
370 dc_yh = (bottomscreen-1)>>FRACBITS;
372 if (dc_yh >= mfloorclip[dc_x])
373 dc_yh = mfloorclip[dc_x]-1;
374 if (dc_yl <= mceilingclip[dc_x])
375 dc_yl = mceilingclip[dc_x]+1;
379 dc_source = (byte *)column + 3;
380 dc_texturemid = basetexturemid - (column->topdelta<<FRACBITS);
381 // dc_source = (byte *)column + 3 - column->topdelta;
383 // Drawn by either R_DrawColumn
384 // or (SHADOW) R_DrawFuzzColumn.
387 column = (column_t *)( (byte *)column + column->length + 4);
390 dc_texturemid = basetexturemid;
397 // mfloorclip and mceilingclip should also be set.
411 patch = W_CacheLumpNum (vis->patch+firstspritelump, PU_CACHE);
413 dc_colormap = vis->colormap;
417 // NULL colormap = shadow draw
418 colfunc = fuzzcolfunc;
420 else if (vis->mobjflags & MF_TRANSLATION)
422 colfunc = R_DrawTranslatedColumn;
423 dc_translation = translationtables - 256 +
424 ( (vis->mobjflags & MF_TRANSLATION) >> (MF_TRANSSHIFT-8) );
427 dc_iscale = abs(vis->xiscale)>>detailshift;
428 dc_texturemid = vis->texturemid;
429 frac = vis->startfrac;
430 spryscale = vis->scale;
431 sprtopscreen = centeryfrac - FixedMul(dc_texturemid,spryscale);
433 for (dc_x=vis->x1 ; dc_x<=vis->x2 ; dc_x++, frac += vis->xiscale)
435 texturecolumn = frac>>FRACBITS;
437 if (texturecolumn < 0 || texturecolumn >= SHORT(patch->width))
438 I_Error ("R_DrawSpriteRange: bad texturecolumn");
440 column = (column_t *) ((byte *)patch +
441 LONG(patch->columnofs[texturecolumn]));
442 R_DrawMaskedColumn (column);
445 colfunc = basecolfunc;
452 // Generates a vissprite for a thing
453 // if it might be visible.
455 void R_ProjectSprite (mobj_t* thing)
472 spriteframe_t* sprframe;
485 // transform the origin point
486 tr_x = thing->x - viewx;
487 tr_y = thing->y - viewy;
489 gxt = FixedMul(tr_x,viewcos);
490 gyt = -FixedMul(tr_y,viewsin);
494 // thing is behind view plane?
498 xscale = FixedDiv(projection, tz);
500 gxt = -FixedMul(tr_x,viewsin);
501 gyt = FixedMul(tr_y,viewcos);
504 // too far off the side?
508 // decide which patch to use for sprite relative to player
510 if ((unsigned)thing->sprite >= numsprites)
511 I_Error ("R_ProjectSprite: invalid sprite number %i ",
514 sprdef = &sprites[thing->sprite];
516 if ( (thing->frame&FF_FRAMEMASK) >= sprdef->numframes )
517 I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
518 thing->sprite, thing->frame);
520 sprframe = &sprdef->spriteframes[ thing->frame & FF_FRAMEMASK];
522 if (sprframe->rotate)
524 // choose a different rotation based on player view
525 ang = R_PointToAngle (thing->x, thing->y);
526 rot = (ang-thing->angle+(unsigned)(ANG45/2)*9)>>29;
527 lump = sprframe->lump[rot];
528 flip = (boolean)sprframe->flip[rot];
532 // use single rotation for all views
533 lump = sprframe->lump[0];
534 flip = (boolean)sprframe->flip[0];
537 // calculate edges of the shape
538 tx -= spriteoffset[lump];
539 x1 = (centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS;
541 // off the right side?
545 tx += spritewidth[lump];
546 x2 = ((centerxfrac + FixedMul (tx,xscale) ) >>FRACBITS) - 1;
552 // store information in a vissprite
553 vis = R_NewVisSprite ();
554 vis->mobjflags = thing->flags;
555 vis->scale = xscale<<detailshift;
559 vis->gzt = thing->z + spritetopoffset[lump];
560 vis->texturemid = vis->gzt - viewz;
561 vis->x1 = x1 < 0 ? 0 : x1;
562 vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
563 iscale = FixedDiv (FRACUNIT, xscale);
567 vis->startfrac = spritewidth[lump]-1;
568 vis->xiscale = -iscale;
573 vis->xiscale = iscale;
577 vis->startfrac += vis->xiscale*(vis->x1-x1);
581 if (thing->flags & MF_SHADOW)
584 vis->colormap = NULL;
586 else if (fixedcolormap)
589 vis->colormap = fixedcolormap;
591 else if (thing->frame & FF_FULLBRIGHT)
594 vis->colormap = colormaps;
600 index = xscale>>(LIGHTSCALESHIFT-detailshift);
602 if (index >= MAXLIGHTSCALE)
603 index = MAXLIGHTSCALE-1;
605 vis->colormap = spritelights[index];
614 // During BSP traversal, this adds sprites by sector.
616 void R_AddSprites (sector_t* sec)
621 // BSP is traversed by subsector.
622 // A sector might have been split into several
623 // subsectors during BSP building.
624 // Thus we check whether its already added.
625 if (sec->validcount == validcount)
628 // Well, now it will be done.
629 sec->validcount = validcount;
631 lightnum = (sec->lightlevel >> LIGHTSEGSHIFT)+extralight;
634 spritelights = scalelight[0];
635 else if (lightnum >= LIGHTLEVELS)
636 spritelights = scalelight[LIGHTLEVELS-1];
638 spritelights = scalelight[lightnum];
640 // Handle all things in sector.
641 for (thing = sec->thinglist ; thing ; thing = thing->snext)
642 R_ProjectSprite (thing);
649 void R_DrawPSprite (pspdef_t* psp)
655 spriteframe_t* sprframe;
661 // decide which patch to use
663 if ( (unsigned)psp->state->sprite >= numsprites)
664 I_Error ("R_ProjectSprite: invalid sprite number %i ",
667 sprdef = &sprites[psp->state->sprite];
669 if ( (psp->state->frame & FF_FRAMEMASK) >= sprdef->numframes)
670 I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
671 psp->state->sprite, psp->state->frame);
673 sprframe = &sprdef->spriteframes[ psp->state->frame & FF_FRAMEMASK ];
675 lump = sprframe->lump[0];
676 flip = (boolean)sprframe->flip[0];
678 // calculate edges of the shape
679 tx = psp->sx-160*FRACUNIT;
681 tx -= spriteoffset[lump];
682 x1 = (centerxfrac + FixedMul (tx,pspritescale) ) >>FRACBITS;
684 // off the right side
688 tx += spritewidth[lump];
689 x2 = ((centerxfrac + FixedMul (tx, pspritescale) ) >>FRACBITS) - 1;
695 // store information in a vissprite
698 vis->texturemid = (BASEYCENTER<<FRACBITS)+FRACUNIT/2-(psp->sy-spritetopoffset[lump]);
699 vis->x1 = x1 < 0 ? 0 : x1;
700 vis->x2 = x2 >= viewwidth ? viewwidth-1 : x2;
701 vis->scale = pspritescale<<detailshift;
705 vis->xiscale = -pspriteiscale;
706 vis->startfrac = spritewidth[lump]-1;
710 vis->xiscale = pspriteiscale;
715 vis->startfrac += vis->xiscale*(vis->x1-x1);
719 if (viewplayer->powers[pw_invisibility] > 4*32
720 || viewplayer->powers[pw_invisibility] & 8)
723 vis->colormap = NULL;
725 else if (fixedcolormap)
728 vis->colormap = fixedcolormap;
730 else if (psp->state->frame & FF_FULLBRIGHT)
733 vis->colormap = colormaps;
738 vis->colormap = spritelights[MAXLIGHTSCALE-1];
741 R_DrawVisSprite (vis, vis->x1, vis->x2);
747 // R_DrawPlayerSprites
749 void R_DrawPlayerSprites (void)
757 (viewplayer->mo->subsector->sector->lightlevel >> LIGHTSEGSHIFT)
761 spritelights = scalelight[0];
762 else if (lightnum >= LIGHTLEVELS)
763 spritelights = scalelight[LIGHTLEVELS-1];
765 spritelights = scalelight[lightnum];
767 // clip to screen bounds
768 mfloorclip = screenheightarray;
769 mceilingclip = negonearray;
771 // add all active psprites
772 for (i=0, psp=viewplayer->psprites;
787 vissprite_t vsprsortedhead;
790 void R_SortVisSprites (void)
796 vissprite_t unsorted;
799 count = vissprite_p - vissprites;
801 unsorted.next = unsorted.prev = &unsorted;
806 for (ds=vissprites ; ds<vissprite_p ; ds++)
812 vissprites[0].prev = &unsorted;
813 unsorted.next = &vissprites[0];
814 (vissprite_p-1)->next = &unsorted;
815 unsorted.prev = vissprite_p-1;
817 // pull the vissprites out by scale
818 vsprsortedhead.next = vsprsortedhead.prev = &vsprsortedhead;
819 for (best=nil,i=0 ; i<count ; i++)
822 for (ds=unsorted.next ; ds!= &unsorted ; ds=ds->next)
824 if (ds->scale < bestscale)
826 bestscale = ds->scale;
830 best->next->prev = best->prev;
831 best->prev->next = best->next;
832 best->next = &vsprsortedhead;
833 best->prev = vsprsortedhead.prev;
834 vsprsortedhead.prev->next = best;
835 vsprsortedhead.prev = best;
844 void R_DrawSprite (vissprite_t* spr)
847 short clipbot[SCREENWIDTH];
848 short cliptop[SCREENWIDTH];
856 for (x = spr->x1 ; x<=spr->x2 ; x++)
857 clipbot[x] = cliptop[x] = -2;
859 // Scan drawsegs from end to start for obscuring segs.
860 // The first drawseg that has a greater scale
862 for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
864 // determine if the drawseg obscures the sprite
868 && !ds->maskedtexturecol) )
870 // does not cover sprite
874 r1 = ds->x1 < spr->x1 ? spr->x1 : ds->x1;
875 r2 = ds->x2 > spr->x2 ? spr->x2 : ds->x2;
877 if (ds->scale1 > ds->scale2)
879 lowscale = ds->scale2;
884 lowscale = ds->scale1;
888 if (scale < spr->scale
889 || ( lowscale < spr->scale
890 && !R_PointOnSegSide (spr->gx, spr->gy, ds->curline) ) )
892 // masked mid texture?
893 if (ds->maskedtexturecol)
894 R_RenderMaskedSegRange (ds, r1, r2);
895 // seg is behind sprite
900 // clip this piece of the sprite
901 silhouette = ds->silhouette;
903 if (spr->gz >= ds->bsilheight)
904 silhouette &= ~SIL_BOTTOM;
906 if (spr->gzt <= ds->tsilheight)
907 silhouette &= ~SIL_TOP;
912 for (x=r1 ; x<=r2 ; x++)
913 if (clipbot[x] == -2)
914 clipbot[x] = ds->sprbottomclip[x];
916 else if (silhouette == 2)
919 for (x=r1 ; x<=r2 ; x++)
920 if (cliptop[x] == -2)
921 cliptop[x] = ds->sprtopclip[x];
923 else if (silhouette == 3)
926 for (x=r1 ; x<=r2 ; x++)
928 if (clipbot[x] == -2)
929 clipbot[x] = ds->sprbottomclip[x];
930 if (cliptop[x] == -2)
931 cliptop[x] = ds->sprtopclip[x];
937 // all clipping has been performed, so draw the sprite
939 // check for unclipped columns
940 for (x = spr->x1 ; x<=spr->x2 ; x++)
942 if (clipbot[x] == -2)
943 clipbot[x] = viewheight;
945 if (cliptop[x] == -2)
949 mfloorclip = clipbot;
950 mceilingclip = cliptop;
951 R_DrawVisSprite (spr, spr->x1, spr->x2);
960 void R_DrawMasked (void)
967 if (vissprite_p > vissprites)
969 // draw all vissprites back to front
970 for (spr = vsprsortedhead.next ;
971 spr != &vsprsortedhead ;
979 // render any remaining masked mid textures
980 for (ds=ds_p-1 ; ds >= drawsegs ; ds--)
981 if (ds->maskedtexturecol)
982 R_RenderMaskedSegRange (ds, ds->x1, ds->x2);
984 // draw the psprites on top of everything
985 // but does not draw on side views
986 if (!viewangleoffset)
987 R_DrawPlayerSprites ();