in doom_py/src/vizdoom/src/r_things.cpp [1822:2232]
void R_DrawSprite (vissprite_t *spr)
{
static short clipbot[MAXWIDTH];
static short cliptop[MAXWIDTH];
drawseg_t *ds;
int i;
int x1, x2;
int r1, r2;
short topclip, botclip;
short *clip1, *clip2;
lighttable_t *colormap = spr->Style.colormap;
F3DFloor *rover;
FDynamicColormap *mybasecolormap;
// [RH] Check for particles
if (!spr->bIsVoxel && spr->pic == NULL)
{
// kg3D - reject invisible parts
if ((fake3D & FAKE3D_CLIPBOTTOM) && spr->gz <= sclipBottom) return;
if ((fake3D & FAKE3D_CLIPTOP) && spr->gz >= sclipTop) return;
R_DrawParticle (spr);
return;
}
x1 = spr->x1;
x2 = spr->x2;
// [RH] Quickly reject sprites with bad x ranges.
if (x1 >= x2)
return;
// [RH] Sprites split behind a one-sided line can also be discarded.
if (spr->sector == NULL)
return;
// kg3D - reject invisible parts
if ((fake3D & FAKE3D_CLIPBOTTOM) && spr->gzt <= sclipBottom) return;
if ((fake3D & FAKE3D_CLIPTOP) && spr->gzb >= sclipTop) return;
// kg3D - correct colors now
if (!fixedcolormap && fixedlightlev < 0 && spr->sector->e && spr->sector->e->XFloor.lightlist.Size())
{
if (!(fake3D & FAKE3D_CLIPTOP))
{
sclipTop = spr->sector->ceilingplane.ZatPoint(viewx, viewy);
}
sector_t *sec = NULL;
for (i = spr->sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
{
if (sclipTop <= spr->sector->e->XFloor.lightlist[i].plane.Zat0())
{
rover = spr->sector->e->XFloor.lightlist[i].caster;
if (rover)
{
if (rover->flags & FF_DOUBLESHADOW && sclipTop <= rover->bottom.plane->Zat0())
{
break;
}
sec = rover->model;
if (rover->flags & FF_FADEWALLS)
{
mybasecolormap = sec->ColorMap;
}
else
{
mybasecolormap = spr->sector->e->XFloor.lightlist[i].extra_colormap;
}
}
break;
}
}
// found new values, recalculate
if (sec)
{
INTBOOL invertcolormap = (spr->Style.RenderStyle.Flags & STYLEF_InvertOverlay);
if (spr->Style.RenderStyle.Flags & STYLEF_InvertSource)
{
invertcolormap = !invertcolormap;
}
// Sprites that are added to the scene must fade to black.
if (spr->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate);
}
if (spr->Style.RenderStyle.Flags & STYLEF_FadeToBlack)
{
if (invertcolormap)
{ // Fade to white
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(255,255,255), mybasecolormap->Desaturate);
invertcolormap = false;
}
else
{ // Fade to black
mybasecolormap = GetSpecialLights(mybasecolormap->Color, MAKERGB(0,0,0), mybasecolormap->Desaturate);
}
}
// get light level
if (invertcolormap)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate);
}
if (fixedlightlev >= 0)
{
spr->Style.colormap = mybasecolormap->Maps + fixedlightlev;
}
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
{ // full bright
spr->Style.colormap = mybasecolormap->Maps;
}
else
{ // diminished light
spriteshade = LIGHT2SHADE(sec->lightlevel + r_actualextralight);
spr->Style.colormap = mybasecolormap->Maps + (GETPALOOKUP (
(fixed_t)DivScale12 (r_SpriteVisibility, MAX(MINZ, spr->depth)), spriteshade) << COLORMAPSHIFT);
}
}
}
// [RH] Initialize the clipping arrays to their largest possible range
// instead of using a special "not clipped" value. This eliminates
// visual anomalies when looking down and should be faster, too.
topclip = 0;
botclip = viewheight;
// killough 3/27/98:
// Clip the sprite against deep water and/or fake ceilings.
// [RH] rewrote this to be based on which part of the sector is really visible
fixed_t scale = MulScale19 (InvZtoScale, spr->idepth);
fixed_t hzb = FIXED_MIN, hzt = FIXED_MAX;
if (spr->bIsVoxel && spr->floorclip != 0)
{
hzb = spr->gzb;
}
if (spr->heightsec && !(spr->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC))
{ // only things in specially marked sectors
if (spr->FakeFlatStat != FAKED_AboveCeiling)
{
fixed_t hz = spr->heightsec->floorplane.ZatPoint (spr->gx, spr->gy);
fixed_t h = (centeryfrac - FixedMul (hz-viewz, scale)) >> FRACBITS;
if (spr->FakeFlatStat == FAKED_BelowFloor)
{ // seen below floor: clip top
if (!spr->bIsVoxel && h > topclip)
{
topclip = MIN<short> (h, viewheight);
}
hzt = MIN(hzt, hz);
}
else
{ // seen in the middle: clip bottom
if (!spr->bIsVoxel && h < botclip)
{
botclip = MAX<short> (0, h);
}
hzb = MAX(hzb, hz);
}
}
if (spr->FakeFlatStat != FAKED_BelowFloor && !(spr->heightsec->MoreFlags & SECF_FAKEFLOORONLY))
{
fixed_t hz = spr->heightsec->ceilingplane.ZatPoint (spr->gx, spr->gy);
fixed_t h = (centeryfrac - FixedMul (hz-viewz, scale)) >> FRACBITS;
if (spr->FakeFlatStat == FAKED_AboveCeiling)
{ // seen above ceiling: clip bottom
if (!spr->bIsVoxel && h < botclip)
{
botclip = MAX<short> (0, h);
}
hzb = MAX(hzb, hz);
}
else
{ // seen in the middle: clip top
if (!spr->bIsVoxel && h > topclip)
{
topclip = MIN<short> (h, viewheight);
}
hzt = MIN(hzt, hz);
}
}
}
// killough 3/27/98: end special clipping for deep water / fake ceilings
else if (!spr->bIsVoxel && spr->floorclip)
{ // [RH] Move floorclip stuff from R_DrawVisSprite to here
int clip = ((centeryfrac - FixedMul (spr->texturemid -
(spr->pic->GetHeight() << FRACBITS) +
spr->floorclip, spr->yscale)) >> FRACBITS);
if (clip < botclip)
{
botclip = MAX<short> (0, clip);
}
}
if (fake3D & FAKE3D_CLIPBOTTOM)
{
if (!spr->bIsVoxel)
{
fixed_t h = sclipBottom;
if (spr->fakefloor)
{
fixed_t floorz = spr->fakefloor->top.plane->Zat0();
if (viewz > floorz && floorz == sclipBottom )
{
h = spr->fakefloor->bottom.plane->Zat0();
}
}
h = (centeryfrac - FixedMul(h-viewz, scale)) >> FRACBITS;
if (h < botclip)
{
botclip = MAX<short>(0, h);
}
}
hzb = MAX(hzb, sclipBottom);
}
if (fake3D & FAKE3D_CLIPTOP)
{
if (!spr->bIsVoxel)
{
fixed_t h = sclipTop;
if (spr->fakeceiling != NULL)
{
fixed_t ceilingz = spr->fakeceiling->bottom.plane->Zat0();
if (viewz < ceilingz && ceilingz == sclipTop)
{
h = spr->fakeceiling->top.plane->Zat0();
}
}
h = (centeryfrac - FixedMul (h-viewz, scale)) >> FRACBITS;
if (h > topclip)
{
topclip = MIN<short>(h, viewheight);
}
}
hzt = MIN(hzt, sclipTop);
}
#if 0
// [RH] Sprites that were split by a drawseg should also be clipped
// by the sector's floor and ceiling. (Not sure how/if to handle this
// with fake floors, since those already do clipping.)
if (spr->bSplitSprite &&
(spr->heightsec == NULL || (spr->heightsec->MoreFlags & SECF_IGNOREHEIGHTSEC)))
{
fixed_t h = spr->sector->floorplane.ZatPoint (spr->gx, spr->gy);
h = (centeryfrac - FixedMul (h-viewz, scale)) >> FRACBITS;
if (h < botclip)
{
botclip = MAX<short> (0, h);
}
h = spr->sector->ceilingplane.ZatPoint (spr->gx, spr->gy);
h = (centeryfrac - FixedMul (h-viewz, scale)) >> FRACBITS;
if (h > topclip)
{
topclip = MIN<short> (h, viewheight);
}
}
#endif
if (topclip >= botclip)
{
spr->Style.colormap = colormap;
return;
}
i = x2 - x1;
clip1 = clipbot + x1;
clip2 = cliptop + x1;
do
{
*clip1++ = botclip;
*clip2++ = topclip;
} while (--i);
// Scan drawsegs from end to start for obscuring segs.
// The first drawseg that is closer than the sprite is the clip seg.
// Modified by Lee Killough:
// (pointer check was originally nonportable
// and buggy, by going past LEFT end of array):
// for (ds=ds_p-1 ; ds >= drawsegs ; ds--) old buggy code
for (ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
{
// kg3D - no clipping on fake segs
if(ds->fake) continue;
// determine if the drawseg obscures the sprite
if (ds->x1 >= x2 || ds->x2 <= x1 ||
(!(ds->silhouette & SIL_BOTH) && ds->maskedtexturecol == -1 &&
!ds->bFogBoundary) )
{
// does not cover sprite
continue;
}
r1 = MAX<int> (ds->x1, x1);
r2 = MIN<int> (ds->x2, x2);
fixed_t neardepth, fardepth;
if (!spr->bWallSprite)
{
if (ds->sz1 < ds->sz2)
{
neardepth = ds->sz1, fardepth = ds->sz2;
}
else
{
neardepth = ds->sz2, fardepth = ds->sz1;
}
}
// Check if sprite is in front of draw seg:
if ((!spr->bWallSprite && neardepth > spr->depth) || ((spr->bWallSprite || fardepth > spr->depth) &&
DMulScale32(spr->gy - ds->curline->v1->y, ds->curline->v2->x - ds->curline->v1->x,
ds->curline->v1->x - spr->gx, ds->curline->v2->y - ds->curline->v1->y) <= 0))
{
// seg is behind sprite, so draw the mid texture if it has one
if (ds->maskedtexturecol != -1 || ds->bFogBoundary)
R_RenderMaskedSegRange (ds, r1, r2);
continue;
}
// clip this piece of the sprite
// killough 3/27/98: optimized and made much shorter
// [RH] Optimized further (at least for VC++;
// other compilers should be at least as good as before)
if (ds->silhouette & SIL_BOTTOM) //bottom sil
{
clip1 = clipbot + r1;
clip2 = openings + ds->sprbottomclip + r1 - ds->x1;
i = r2 - r1;
do
{
if (*clip1 > *clip2)
*clip1 = *clip2;
clip1++;
clip2++;
} while (--i);
}
if (ds->silhouette & SIL_TOP) // top sil
{
clip1 = cliptop + r1;
clip2 = openings + ds->sprtopclip + r1 - ds->x1;
i = r2 - r1;
do
{
if (*clip1 < *clip2)
*clip1 = *clip2;
clip1++;
clip2++;
} while (--i);
}
}
// all clipping has been performed, so draw the sprite
if (!spr->bIsVoxel)
{
mfloorclip = clipbot;
mceilingclip = cliptop;
if (!spr->bWallSprite)
{
R_DrawVisSprite(spr);
}
else
{
R_DrawWallSprite(spr);
}
}
else
{
// If it is completely clipped away, don't bother drawing it.
if (cliptop[x2] >= clipbot[x2])
{
for (i = x1; i < x2; ++i)
{
if (cliptop[i] < clipbot[i])
{
break;
}
}
if (i == x2)
{
spr->Style.colormap = colormap;
return;
}
}
// Add everything outside the left and right edges to the clipping array
// for R_DrawVisVoxel().
if (x1 > 0)
{
clearbufshort(cliptop, x1, viewheight);
}
if (x2 < viewwidth - 1)
{
clearbufshort(cliptop + x2, viewwidth - x2, viewheight);
}
int minvoxely = spr->gzt <= hzt ? 0 : (spr->gzt - hzt) / spr->yscale;
int maxvoxely = spr->gzb > hzb ? INT_MAX : (spr->gzt - hzb) / spr->yscale;
R_DrawVisVoxel(spr, minvoxely, maxvoxely, cliptop, clipbot);
}
spr->Style.colormap = colormap;
}