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
18 // Revision 1.1 2000/02/29 18:21:05 stegerg
19 // Doom port based on ADoomPPC. Read README.AROS!
23 // Refresh of things, i.e. objects represented by sprites.
25 //-----------------------------------------------------------------------------
49 #define MINZ (FRACUNIT*4)
50 //#define BASEYCENTER 100
51 #define BASEYCENTER ((weirdaspect==1)?100:75)
53 //void R_DrawColumn (void);
54 //void R_DrawFuzzColumn (void);
72 // Sprite rotation 0 is facing the viewer,
73 // rotation 1 is one angle turn CLOCKWISE around the axis.
74 // This is not the same as the angle,
75 // which increases counter clockwise (protractor).
76 // There was a lot of stuff grabbed wrong, so I changed it...
79 fixed_t pspriteiscale
;
80 //fixed_t pspritescale2;
81 fixed_t pspriteiscale2
;
83 lighttable_t
** spritelights
;
86 // used for psprite clipping and initializing clipping
87 //short negonearray[SCREENWIDTH];
88 //short screenheightarray[SCREENWIDTH];
90 short *screenheightarray
;
94 // INITIALIZATION FUNCTIONS
97 // variables used to look up
98 // and range check thing_t sprites patches
102 FAR spriteframe_t sprtemp
[29];
110 // R_InstallSpriteLump
111 // Local function for R_InitSprites.
122 if (frame
>= 29 || rotation
> 8)
123 I_Error("R_InstallSpriteLump: "
124 "Bad frame characters in lump %i", lump
);
126 if ((int)frame
> maxframe
)
131 // the lump should be used for all rotations
132 if (sprtemp
[frame
].rotate
== false)
133 I_Error ("R_InitSprites: Sprite %s frame %c has "
134 "multip rot=0 lump", spritename
, 'A'+frame
);
136 if (sprtemp
[frame
].rotate
== true)
137 I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
138 "and a rot=0 lump", spritename
, 'A'+frame
);
140 sprtemp
[frame
].rotate
= false;
141 for (r
=0 ; r
<8 ; r
++)
143 sprtemp
[frame
].lump
[r
] = lump
- firstspritelump
;
144 sprtemp
[frame
].flip
[r
] = (byte
)flipped
;
149 // the lump is only used for one rotation
150 if (sprtemp
[frame
].rotate
== false)
151 I_Error ("R_InitSprites: Sprite %s frame %c has rotations "
152 "and a rot=0 lump", spritename
, 'A'+frame
);
154 sprtemp
[frame
].rotate
= true;
158 if (sprtemp
[frame
].lump
[rotation
] != -1)
159 I_Error ("R_InitSprites: Sprite %s : %c : %c "
160 "has two lumps mapped to it",
161 spritename
, 'A'+frame
, '1'+rotation
);
163 sprtemp
[frame
].lump
[rotation
] = lump
- firstspritelump
;
164 sprtemp
[frame
].flip
[rotation
] = (byte
)flipped
;
172 // Pass a null terminated list of sprite names
173 // (4 chars exactly) to be used.
174 // Builds the sprite rotation matrixes to account
175 // for horizontally flipped sprites.
176 // Will report an error if the lumps are inconsistant.
177 // Only called at startup.
179 // Sprite lump names are 4 characters for the actor,
180 // a letter for the frame, and a number for the rotation.
181 // A sprite that is flippable will have an additional
182 // letter/number appended.
183 // The rotation character can be 0 to signify no rotations.
185 void R_InitSpriteDefs (char** namelist
)
197 // count the number of sprite names
199 while (*check
!= NULL
)
202 numsprites
= check
-namelist
;
207 sprites
= Z_Malloc(numsprites
*sizeof(*sprites
), PU_STATIC
, NULL
);
209 start
= firstspritelump
-1;
210 end
= lastspritelump
+1;
212 // scan all the lump names for each of the names,
213 // noting the highest frame letter.
214 // Just compare 4 characters as ints
215 for (i
=0 ; i
<numsprites
; i
++)
217 spritename
= namelist
[i
];
218 memset (sprtemp
,-1, sizeof(sprtemp
));
221 intname
= *(int *)namelist
[i
];
224 // filling in the frames for whatever is found
225 for (l
=start
+1 ; l
<end
; l
++)
227 if (*(int *)lumpinfo
[l
].name
== intname
)
229 frame
= lumpinfo
[l
].name
[4] - 'A';
230 rotation
= lumpinfo
[l
].name
[5] - '0';
233 patched
= W_GetNumForName (lumpinfo
[l
].name
);
237 R_InstallSpriteLump (patched
, frame
, rotation
, false);
239 if (lumpinfo
[l
].name
[6])
241 frame
= lumpinfo
[l
].name
[6] - 'A';
242 rotation
= lumpinfo
[l
].name
[7] - '0';
243 R_InstallSpriteLump (l
, frame
, rotation
, true);
248 // check the frames that were found for completeness
251 sprites
[i
].numframes
= 0;
257 for (frame
= 0 ; frame
< maxframe
; frame
++)
259 switch ((int)sprtemp
[frame
].rotate
)
262 // no rotations were found for that frame at all
263 I_Error ("R_InitSprites: No patches found "
264 "for %s frame %c", namelist
[i
], frame
+'A');
268 // only the first rotation is needed
272 // must have all 8 frames
273 for (rotation
=0 ; rotation
<8 ; rotation
++)
274 if (sprtemp
[frame
].lump
[rotation
] == -1)
275 I_Error ("R_InitSprites: Sprite %s frame %c "
276 "is missing rotations",
277 namelist
[i
], frame
+'A');
282 // allocate space for the frames present and copy sprtemp to it
283 sprites
[i
].numframes
= maxframe
;
284 sprites
[i
].spriteframes
=
285 Z_Malloc (maxframe
* sizeof(spriteframe_t
), PU_STATIC
, NULL
);
286 memcpy (sprites
[i
].spriteframes
, sprtemp
, maxframe
*sizeof(spriteframe_t
));
297 FAR vissprite_t vissprites
[MAXVISSPRITES
];
298 vissprite_t
* vissprite_p
;
305 // Called at program start.
307 void R_InitSprites (char** namelist
)
311 for (i
=0 ; i
<SCREENWIDTH
; i
++)
316 R_InitSpriteDefs (namelist
);
323 // Called at frame start.
325 void R_ClearSprites (void)
327 vissprite_p
= vissprites
;
334 vissprite_t overflowsprite
;
336 vissprite_t
* R_NewVisSprite (void)
338 if (vissprite_p
== &vissprites
[MAXVISSPRITES
])
339 return &overflowsprite
;
342 return vissprite_p
-1;
348 // R_DrawMaskedColumn
349 // Used for sprites and masked mid textures.
350 // Masked means: partly transparent, i.e. stored
351 // in posts/runs of opaque pixels.
357 fixed_t sprtopscreen
;
359 void R_DrawMaskedColumn (column_t
* column
)
363 fixed_t basetexturemid
;
365 basetexturemid
= dc_texturemid
;
367 for ( ; column
->topdelta
!= 0xff ; )
369 // calculate unclipped screen coordinates
371 topscreen
= sprtopscreen
+ spryscale
*column
->topdelta
;
372 bottomscreen
= topscreen
+ spryscale
*column
->length
;
374 dc_yl
= (topscreen
+FRACUNIT
-1)>>FRACBITS
;
375 dc_yh
= (bottomscreen
-1)>>FRACBITS
;
377 if (dc_yh
>= mfloorclip
[dc_x
])
378 dc_yh
= mfloorclip
[dc_x
]-1;
379 if (dc_yl
<= mceilingclip
[dc_x
])
380 dc_yl
= mceilingclip
[dc_x
]+1;
384 dc_source
= (byte
*)column
+ 3;
385 dc_texturemid
= basetexturemid
- (column
->topdelta
<<FRACBITS
);
386 // dc_source = (byte *)column + 3 - column->topdelta;
388 // Drawn by either R_DrawColumn
389 // or (SHADOW) R_DrawFuzzColumn.
392 column
= (column_t
*)( (byte
*)column
+ column
->length
+ 4);
395 dc_texturemid
= basetexturemid
;
402 // mfloorclip and mceilingclip should also be set.
416 patch
= W_CacheLumpNum (vis
->patch
+firstspritelump
, PU_CACHE
);
418 dc_colormap
= vis
->colormap
;
422 // NULL colormap = shadow draw
423 colfunc
= fuzzcolfunc
;
425 else if (vis
->mobjflags
& MF_TRANSLATION
)
427 colfunc
= transcolfunc
;
428 dc_translation
= translationtables
- 256 +
429 ( (vis
->mobjflags
& MF_TRANSLATION
) >> (MF_TRANSSHIFT
-8) );
432 dc_iscale
= iabs(vis
->xiscale
)>>detailshift
;
433 dc_texturemid
= vis
->texturemid
;
434 frac
= vis
->startfrac
;
435 spryscale
= vis
->scale
;
436 sprtopscreen
= centeryfrac
- FixedMul(dc_texturemid
,spryscale
);
438 for (dc_x
=vis
->x1
; dc_x
<=vis
->x2
; dc_x
++, frac
+= vis
->xiscale
)
440 texturecolumn
= frac
>>FRACBITS
;
442 if (texturecolumn
< 0 || texturecolumn
>= SWAPSHORT(patch
->width
))
443 I_Error ("R_DrawSpriteRange: bad texturecolumn");
445 column
= (column_t
*) ((byte
*)patch
+
446 SWAPLONG(patch
->columnofs
[texturecolumn
]));
448 R_DrawMaskedColumn (column
);
451 colfunc
= basecolfunc
;
458 // Generates a vissprite for a thing
459 // if it might be visible.
461 void R_ProjectSprite (mobj_t
* thing
)
478 spriteframe_t
* sprframe
;
491 // transform the origin point
492 tr_x
= thing
->x
- viewx
;
493 tr_y
= thing
->y
- viewy
;
495 gxt
= FixedMul(tr_x
,viewcos
);
496 gyt
= -FixedMul(tr_y
,viewsin
);
500 // thing is behind view plane?
504 xscale
= FixedDiv(projection
, tz
);
506 gxt
= -FixedMul(tr_x
,viewsin
);
507 gyt
= FixedMul(tr_y
,viewcos
);
510 // too far off the side?
511 if (iabs(tx
)>(tz
<<2))
514 // decide which patch to use for sprite relative to player
516 if ((unsigned)thing
->sprite
>= numsprites
)
517 I_Error ("R_ProjectSprite: invalid sprite number %i ",
520 sprdef
= &sprites
[thing
->sprite
];
522 if ( (thing
->frame
&FF_FRAMEMASK
) >= sprdef
->numframes
)
523 I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
524 thing
->sprite
, thing
->frame
);
526 sprframe
= &sprdef
->spriteframes
[ thing
->frame
& FF_FRAMEMASK
];
528 if (sprframe
->rotate
)
530 // choose a different rotation based on player view
531 ang
= R_PointToAngle (thing
->x
, thing
->y
);
532 rot
= (ang
-thing
->angle
+(unsigned)(ANG45
/2)*9)>>29;
533 lump
= sprframe
->lump
[rot
];
534 flip
= (boolean
)sprframe
->flip
[rot
];
538 // use single rotation for all views
539 lump
= sprframe
->lump
[0];
540 flip
= (boolean
)sprframe
->flip
[0];
543 // calculate edges of the shape
544 tx
-= spriteoffset
[lump
];
545 x1
= (centerxfrac
+ FixedMul (tx
,xscale
) ) >>FRACBITS
;
547 // off the right side?
551 tx
+= spritewidth
[lump
];
552 x2
= ((centerxfrac
+ FixedMul (tx
,xscale
) ) >>FRACBITS
) - 1;
558 // store information in a vissprite
559 vis
= R_NewVisSprite ();
560 vis
->mobjflags
= thing
->flags
;
561 vis
->scale
= xscale
<<detailshift
;
565 vis
->gzt
= thing
->z
+ spritetopoffset
[lump
];
566 vis
->texturemid
= vis
->gzt
- viewz
;
567 vis
->x1
= x1
< 0 ? 0 : x1
;
568 vis
->x2
= x2
>= viewwidth
? viewwidth
-1 : x2
;
569 iscale
= FixedDiv (FRACUNIT
, xscale
);
573 vis
->startfrac
= spritewidth
[lump
]-1;
574 vis
->xiscale
= -iscale
;
579 vis
->xiscale
= iscale
;
583 vis
->startfrac
+= vis
->xiscale
*(vis
->x1
-x1
);
587 if (thing
->flags
& MF_SHADOW
)
590 vis
->colormap
= NULL
;
592 else if (fixedcolormap
)
595 vis
->colormap
= fixedcolormap
;
597 else if (thing
->frame
& FF_FULLBRIGHT
)
600 vis
->colormap
= colormaps
;
606 index
= xscale
>>(LIGHTSCALESHIFT
-detailshift
);
608 if (index
>= MAXLIGHTSCALE
)
609 index
= MAXLIGHTSCALE
-1;
611 vis
->colormap
= spritelights
[index
];
620 // During BSP traversal, this adds sprites by sector.
622 void R_AddSprites (sector_t
* sec
)
627 // BSP is traversed by subsector.
628 // A sector might have been split into several
629 // subsectors during BSP building.
630 // Thus we check whether its already added.
631 if (sec
->validcount
== validcount
)
634 // Well, now it will be done.
635 sec
->validcount
= validcount
;
637 lightnum
= (sec
->lightlevel
>> LIGHTSEGSHIFT
)+extralight
;
640 spritelights
= scalelight
[0];
641 else if (lightnum
>= LIGHTLEVELS
)
642 spritelights
= scalelight
[LIGHTLEVELS
-1];
644 spritelights
= scalelight
[lightnum
];
646 // Handle all things in sector.
647 for (thing
= sec
->thinglist
; thing
; thing
= thing
->snext
)
648 R_ProjectSprite (thing
);
655 void R_DrawPSprite (pspdef_t
* psp
)
661 spriteframe_t
* sprframe
;
667 // decide which patch to use
669 if ( (unsigned)psp
->state
->sprite
>= numsprites
)
670 I_Error ("R_ProjectSprite: invalid sprite number %i ",
673 sprdef
= &sprites
[psp
->state
->sprite
];
675 if ( (psp
->state
->frame
& FF_FRAMEMASK
) >= sprdef
->numframes
)
676 I_Error ("R_ProjectSprite: invalid sprite frame %i : %i ",
677 psp
->state
->sprite
, psp
->state
->frame
);
679 sprframe
= &sprdef
->spriteframes
[ psp
->state
->frame
& FF_FRAMEMASK
];
681 lump
= sprframe
->lump
[0];
682 flip
= (boolean
)sprframe
->flip
[0];
684 // calculate edges of the shape
685 tx
= psp
->sx
-160*FRACUNIT
;
687 tx
-= spriteoffset
[lump
];
688 x1
= (centerxfrac
+ FixedMul (tx
,pspritescale
) ) >>FRACBITS
;
690 // off the right side
694 tx
+= spritewidth
[lump
];
695 x2
= ((centerxfrac
+ FixedMul (tx
, pspritescale
) ) >>FRACBITS
) - 1;
701 // store information in a vissprite
704 vis
->texturemid
= (BASEYCENTER
<<FRACBITS
)+FRACUNIT
/2-(psp
->sy
-spritetopoffset
[lump
]);
705 vis
->x1
= x1
< 0 ? 0 : x1
;
706 vis
->x2
= x2
>= viewwidth
? viewwidth
-1 : x2
;
707 vis
->scale
= pspritescale
<<detailshift
;
711 vis
->xiscale
= -pspriteiscale
;
712 vis
->startfrac
= spritewidth
[lump
]-1;
716 vis
->xiscale
= pspriteiscale
;
721 vis
->startfrac
+= vis
->xiscale
*(vis
->x1
-x1
);
725 if (viewplayer
->powers
[pw_invisibility
] > 4*32
726 || viewplayer
->powers
[pw_invisibility
] & 8)
729 vis
->colormap
= NULL
;
731 else if (fixedcolormap
)
734 vis
->colormap
= fixedcolormap
;
736 else if (psp
->state
->frame
& FF_FULLBRIGHT
)
739 vis
->colormap
= colormaps
;
744 vis
->colormap
= spritelights
[MAXLIGHTSCALE
-1];
747 R_DrawVisSprite (vis
, vis
->x1
, vis
->x2
);
753 // R_DrawPlayerSprites
755 void R_DrawPlayerSprites (void)
763 (viewplayer
->mo
->subsector
->sector
->lightlevel
>> LIGHTSEGSHIFT
)
767 spritelights
= scalelight
[0];
768 else if (lightnum
>= LIGHTLEVELS
)
769 spritelights
= scalelight
[LIGHTLEVELS
-1];
771 spritelights
= scalelight
[lightnum
];
773 // clip to screen bounds
774 mfloorclip
= screenheightarray
;
775 mceilingclip
= negonearray
;
777 // add all active psprites
778 for (i
=0, psp
=viewplayer
->psprites
;
788 vissprite_t vsprsortedhead
;
793 void R_SortVisSprites (void)
799 vissprite_t unsorted
;
802 count
= vissprite_p
- vissprites
;
804 unsorted
.next
= unsorted
.prev
= &unsorted
;
809 for (ds
=vissprites
; ds
<vissprite_p
; ds
++)
815 vissprites
[0].prev
= &unsorted
;
816 unsorted
.next
= &vissprites
[0];
817 (vissprite_p
-1)->next
= &unsorted
;
818 unsorted
.prev
= vissprite_p
-1;
820 // pull the vissprites out by scale
821 //best = 0; // shut up the compiler warning
822 vsprsortedhead
.next
= vsprsortedhead
.prev
= &vsprsortedhead
;
823 for (i
=0 ; i
<count
; i
++)
826 for (ds
=unsorted
.next
,best
=ds
; ds
!= &unsorted
; ds
=ds
->next
)
828 if (ds
->scale
< bestscale
)
830 bestscale
= ds
->scale
;
834 best
->next
->prev
= best
->prev
;
835 best
->prev
->next
= best
->next
;
836 best
->next
= &vsprsortedhead
;
837 best
->prev
= vsprsortedhead
.prev
;
838 vsprsortedhead
.prev
->next
= best
;
839 vsprsortedhead
.prev
= best
;
848 void R_DrawSprite (vissprite_t
* spr
)
851 // short clipbot[SCREENWIDTH];
852 // short cliptop[SCREENWIDTH];
853 static short clipbot
[MAXSCREENWIDTH
];
854 static short cliptop
[MAXSCREENWIDTH
];
862 // clipbot = I_malloc (SCREENWIDTH * sizeof(short));
863 // cliptop = I_malloc (SCREENWIDTH * sizeof(short));
865 for (x
= spr
->x1
; x
<=spr
->x2
; x
++)
866 clipbot
[x
] = cliptop
[x
] = -2;
868 // Scan drawsegs from end to start for obscuring segs.
869 // The first drawseg that has a greater scale
871 for (ds
=ds_p
-1 ; ds
>= drawsegs
; ds
--)
873 // determine if the drawseg obscures the sprite
877 && !ds
->maskedtexturecol
) )
879 // does not cover sprite
883 r1
= ds
->x1
< spr
->x1
? spr
->x1
: ds
->x1
;
884 r2
= ds
->x2
> spr
->x2
? spr
->x2
: ds
->x2
;
886 if (ds
->scale1
> ds
->scale2
)
888 lowscale
= ds
->scale2
;
893 lowscale
= ds
->scale1
;
897 if (scale
< spr
->scale
898 || ( lowscale
< spr
->scale
899 && !R_PointOnSegSide (spr
->gx
, spr
->gy
, ds
->curline
) ) )
901 // masked mid texture?
902 if (ds
->maskedtexturecol
)
903 R_RenderMaskedSegRange (ds
, r1
, r2
);
904 // seg is behind sprite
909 // clip this piece of the sprite
910 silhouette
= ds
->silhouette
;
912 if (spr
->gz
>= ds
->bsilheight
)
913 silhouette
&= ~SIL_BOTTOM
;
915 if (spr
->gzt
<= ds
->tsilheight
)
916 silhouette
&= ~SIL_TOP
;
921 for (x
=r1
; x
<=r2
; x
++)
922 if (clipbot
[x
] == -2)
923 clipbot
[x
] = ds
->sprbottomclip
[x
];
925 else if (silhouette
== 2)
928 for (x
=r1
; x
<=r2
; x
++)
929 if (cliptop
[x
] == -2)
930 cliptop
[x
] = ds
->sprtopclip
[x
];
932 else if (silhouette
== 3)
935 for (x
=r1
; x
<=r2
; x
++)
937 if (clipbot
[x
] == -2)
938 clipbot
[x
] = ds
->sprbottomclip
[x
];
939 if (cliptop
[x
] == -2)
940 cliptop
[x
] = ds
->sprtopclip
[x
];
946 // all clipping has been performed, so draw the sprite
948 // check for unclipped columns
949 for (x
= spr
->x1
; x
<=spr
->x2
; x
++)
951 if (clipbot
[x
] == -2)
952 clipbot
[x
] = viewheight
;
954 if (cliptop
[x
] == -2)
958 mfloorclip
= clipbot
;
959 mceilingclip
= cliptop
;
960 R_DrawVisSprite (spr
, spr
->x1
, spr
->x2
);
972 void R_DrawMasked (void)
979 if (vissprite_p
> vissprites
)
981 // draw all vissprites back to front
982 for (spr
= vsprsortedhead
.next
;
983 spr
!= &vsprsortedhead
;
991 // render any remaining masked mid textures
992 for (ds
=ds_p
-1 ; ds
>= drawsegs
; ds
--)
993 if (ds
->maskedtexturecol
)
994 R_RenderMaskedSegRange (ds
, ds
->x1
, ds
->x2
);
996 // draw the psprites on top of everything
997 // but does not draw on side views
998 if (!viewangleoffset
)
999 R_DrawPlayerSprites ();