mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-24 13:01:48 +00:00
Move classes in r_visiblesprite to their own files
This commit is contained in:
parent
32b91dd978
commit
6f1836b68b
13 changed files with 870 additions and 747 deletions
|
@ -848,6 +848,7 @@ set( FASTMATH_PCH_SOURCES
|
||||||
swrenderer/scene/r_3dfloors.cpp
|
swrenderer/scene/r_3dfloors.cpp
|
||||||
swrenderer/scene/r_bsp.cpp
|
swrenderer/scene/r_bsp.cpp
|
||||||
swrenderer/scene/r_portal.cpp
|
swrenderer/scene/r_portal.cpp
|
||||||
|
swrenderer/scene/r_translucent.cpp
|
||||||
swrenderer/line/r_line.cpp
|
swrenderer/line/r_line.cpp
|
||||||
swrenderer/line/r_walldraw.cpp
|
swrenderer/line/r_walldraw.cpp
|
||||||
swrenderer/line/r_wallsetup.cpp
|
swrenderer/line/r_wallsetup.cpp
|
||||||
|
@ -856,6 +857,7 @@ set( FASTMATH_PCH_SOURCES
|
||||||
swrenderer/segments/r_drawsegment.cpp
|
swrenderer/segments/r_drawsegment.cpp
|
||||||
swrenderer/segments/r_portalsegment.cpp
|
swrenderer/segments/r_portalsegment.cpp
|
||||||
swrenderer/things/r_visiblesprite.cpp
|
swrenderer/things/r_visiblesprite.cpp
|
||||||
|
swrenderer/things/r_visiblespritelist.cpp
|
||||||
swrenderer/things/r_voxel.cpp
|
swrenderer/things/r_voxel.cpp
|
||||||
swrenderer/things/r_particle.cpp
|
swrenderer/things/r_particle.cpp
|
||||||
swrenderer/things/r_playersprite.cpp
|
swrenderer/things/r_playersprite.cpp
|
||||||
|
|
|
@ -43,6 +43,7 @@
|
||||||
#include "segments/r_clipsegment.h"
|
#include "segments/r_clipsegment.h"
|
||||||
#include "scene/r_3dfloors.h"
|
#include "scene/r_3dfloors.h"
|
||||||
#include "scene/r_portal.h"
|
#include "scene/r_portal.h"
|
||||||
|
#include "scene/r_translucent.h"
|
||||||
#include "r_sky.h"
|
#include "r_sky.h"
|
||||||
#include "drawers/r_draw_rgba.h"
|
#include "drawers/r_draw_rgba.h"
|
||||||
#include "st_stuff.h"
|
#include "st_stuff.h"
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "swrenderer/plane/r_visibleplane.h"
|
#include "swrenderer/plane/r_visibleplane.h"
|
||||||
#include "swrenderer/things/r_visiblesprite.h"
|
#include "swrenderer/things/r_visiblesprite.h"
|
||||||
#include "swrenderer/scene/r_bsp.h"
|
#include "swrenderer/scene/r_bsp.h"
|
||||||
|
#include "swrenderer/scene/r_translucent.h"
|
||||||
#include "swrenderer/r_main.h"
|
#include "swrenderer/r_main.h"
|
||||||
#include "swrenderer/r_memory.h"
|
#include "swrenderer/r_memory.h"
|
||||||
|
|
||||||
|
|
616
src/swrenderer/scene/r_translucent.cpp
Normal file
616
src/swrenderer/scene/r_translucent.cpp
Normal file
|
@ -0,0 +1,616 @@
|
||||||
|
//
|
||||||
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||||
|
//
|
||||||
|
// This source is available for distribution and/or modification
|
||||||
|
// only under the terms of the DOOM Source Code License as
|
||||||
|
// published by id Software. All rights reserved.
|
||||||
|
//
|
||||||
|
// The source is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "p_lnspec.h"
|
||||||
|
#include "templates.h"
|
||||||
|
#include "doomdef.h"
|
||||||
|
#include "m_swap.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
#include "w_wad.h"
|
||||||
|
#include "g_levellocals.h"
|
||||||
|
#include "p_maputl.h"
|
||||||
|
#include "swrenderer/r_main.h"
|
||||||
|
#include "swrenderer/things/r_visiblesprite.h"
|
||||||
|
#include "swrenderer/things/r_visiblespritelist.h"
|
||||||
|
#include "swrenderer/things/r_voxel.h"
|
||||||
|
#include "swrenderer/things/r_particle.h"
|
||||||
|
#include "swrenderer/things/r_sprite.h"
|
||||||
|
#include "swrenderer/things/r_wallsprite.h"
|
||||||
|
#include "swrenderer/things/r_playersprite.h"
|
||||||
|
#include "swrenderer/segments/r_drawsegment.h"
|
||||||
|
#include "swrenderer/scene/r_portal.h"
|
||||||
|
#include "swrenderer/scene/r_translucent.h"
|
||||||
|
#include "swrenderer/plane/r_visibleplane.h"
|
||||||
|
#include "swrenderer/r_memory.h"
|
||||||
|
|
||||||
|
EXTERN_CVAR(Int, r_drawfuzz)
|
||||||
|
EXTERN_CVAR(Bool, r_drawvoxels)
|
||||||
|
EXTERN_CVAR(Bool, r_blendmethod)
|
||||||
|
|
||||||
|
CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
||||||
|
|
||||||
|
namespace swrenderer
|
||||||
|
{
|
||||||
|
bool RenderTranslucent::DrewAVoxel;
|
||||||
|
TArray<drawseg_t *> RenderTranslucent::portaldrawsegs;
|
||||||
|
|
||||||
|
void RenderTranslucent::Deinit()
|
||||||
|
{
|
||||||
|
VisibleSpriteList::Deinit();
|
||||||
|
SortedVisibleSpriteList::Deinit();
|
||||||
|
RenderVoxel::Deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTranslucent::Clear()
|
||||||
|
{
|
||||||
|
VisibleSpriteList::Clear();
|
||||||
|
DrewAVoxel = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTranslucent::CollectPortals()
|
||||||
|
{
|
||||||
|
// This function collects all drawsegs that may be of interest to R_ClipSpriteColumnWithPortals
|
||||||
|
// Having that function over the entire list of drawsegs can break down performance quite drastically.
|
||||||
|
// This is doing the costly stuff only once so that R_ClipSpriteColumnWithPortals can
|
||||||
|
// a) exit early if no relevant info is found and
|
||||||
|
// b) skip most of the collected drawsegs which have no portal attached.
|
||||||
|
portaldrawsegs.Clear();
|
||||||
|
for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below
|
||||||
|
{
|
||||||
|
// I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...)
|
||||||
|
// crashes at the first frame of the first map of Action2.wad
|
||||||
|
if (!seg->curline) continue;
|
||||||
|
|
||||||
|
line_t* line = seg->curline->linedef;
|
||||||
|
// ignore minisegs from GL nodes.
|
||||||
|
if (!line) continue;
|
||||||
|
|
||||||
|
// check if this line will clip sprites to itself
|
||||||
|
if (!line->isVisualPortal() && line->special != Line_Mirror)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// don't clip sprites with portal's back side (it's transparent)
|
||||||
|
if (seg->curline->sidedef != line->sidedef[0])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
portaldrawsegs.Push(seg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderTranslucent::ClipSpriteColumnWithPortals(int x, vissprite_t* spr)
|
||||||
|
{
|
||||||
|
RenderPortal *renderportal = RenderPortal::Instance();
|
||||||
|
|
||||||
|
// [ZZ] 10.01.2016: don't clip sprites from the root of a skybox.
|
||||||
|
if (renderportal->CurrentPortalInSkybox)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (drawseg_t *seg : portaldrawsegs)
|
||||||
|
{
|
||||||
|
// ignore segs from other portals
|
||||||
|
if (seg->CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// (all checks that are already done in R_CollectPortals have been removed for performance reasons.)
|
||||||
|
|
||||||
|
// don't clip if the sprite is in front of the portal
|
||||||
|
if (!P_PointOnLineSidePrecise(spr->gpos.X, spr->gpos.Y, seg->curline->linedef))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// now if current column is covered by this drawseg, we clip it away
|
||||||
|
if ((x >= seg->x1) && (x < seg->x2))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTranslucent::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;
|
||||||
|
FSWColormap *colormap = spr->Style.BaseColormap;
|
||||||
|
int colormapnum = spr->Style.ColormapNum;
|
||||||
|
F3DFloor *rover;
|
||||||
|
FDynamicColormap *mybasecolormap;
|
||||||
|
|
||||||
|
Clip3DFloors *clip3d = Clip3DFloors::Instance();
|
||||||
|
|
||||||
|
// [RH] Check for particles
|
||||||
|
if (!spr->bIsVoxel && spr->pic == nullptr)
|
||||||
|
{
|
||||||
|
// kg3D - reject invisible parts
|
||||||
|
if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gpos.Z <= clip3d->sclipBottom) return;
|
||||||
|
if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gpos.Z >= clip3d->sclipTop) return;
|
||||||
|
RenderParticle::Render(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 == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// kg3D - reject invisible parts
|
||||||
|
if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gzt <= clip3d->sclipBottom) return;
|
||||||
|
if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gzb >= clip3d->sclipTop) return;
|
||||||
|
|
||||||
|
// kg3D - correct colors now
|
||||||
|
if (!fixedcolormap && fixedlightlev < 0 && spr->sector->e && spr->sector->e->XFloor.lightlist.Size())
|
||||||
|
{
|
||||||
|
if (!(clip3d->fake3D & FAKE3D_CLIPTOP))
|
||||||
|
{
|
||||||
|
clip3d->sclipTop = spr->sector->ceilingplane.ZatPoint(ViewPos);
|
||||||
|
}
|
||||||
|
sector_t *sec = nullptr;
|
||||||
|
for (i = spr->sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (clip3d->sclipTop <= spr->sector->e->XFloor.lightlist[i].plane.Zat0())
|
||||||
|
{
|
||||||
|
rover = spr->sector->e->XFloor.lightlist[i].caster;
|
||||||
|
if (rover)
|
||||||
|
{
|
||||||
|
if (rover->flags & FF_DOUBLESHADOW && clip3d->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.BaseColormap = mybasecolormap;
|
||||||
|
spr->Style.ColormapNum = fixedlightlev >> COLORMAPSHIFT;
|
||||||
|
}
|
||||||
|
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
|
||||||
|
{ // full bright
|
||||||
|
spr->Style.BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : mybasecolormap;
|
||||||
|
spr->Style.ColormapNum = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // diminished light
|
||||||
|
int spriteshade = LIGHT2SHADE(sec->lightlevel + r_actualextralight);
|
||||||
|
spr->Style.BaseColormap = mybasecolormap;
|
||||||
|
spr->Style.ColormapNum = GETPALOOKUP(r_SpriteVisibility / MAX(MINZ, (double)spr->depth), spriteshade);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [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
|
||||||
|
|
||||||
|
double scale = InvZtoScale * spr->idepth;
|
||||||
|
double hzb = DBL_MIN, hzt = DBL_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 != WaterFakeSide::AboveCeiling)
|
||||||
|
{
|
||||||
|
double hz = spr->heightsec->floorplane.ZatPoint(spr->gpos);
|
||||||
|
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
||||||
|
|
||||||
|
if (spr->FakeFlatStat == WaterFakeSide::BelowFloor)
|
||||||
|
{ // seen below floor: clip top
|
||||||
|
if (!spr->bIsVoxel && h > topclip)
|
||||||
|
{
|
||||||
|
topclip = short(MIN(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 != WaterFakeSide::BelowFloor && !(spr->heightsec->MoreFlags & SECF_FAKEFLOORONLY))
|
||||||
|
{
|
||||||
|
double hz = spr->heightsec->ceilingplane.ZatPoint(spr->gpos);
|
||||||
|
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
||||||
|
|
||||||
|
if (spr->FakeFlatStat == WaterFakeSide::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(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 = ((FLOAT2FIXED(CenterY) - FixedMul (spr->texturemid - (spr->pic->GetHeight() << FRACBITS) + spr->floorclip, spr->yscale)) >> FRACBITS);
|
||||||
|
int clip = xs_RoundToInt(CenterY - (spr->texturemid - spr->pic->GetHeight() + spr->floorclip) * spr->yscale);
|
||||||
|
if (clip < botclip)
|
||||||
|
{
|
||||||
|
botclip = MAX<short>(0, clip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clip3d->fake3D & FAKE3D_CLIPBOTTOM)
|
||||||
|
{
|
||||||
|
if (!spr->bIsVoxel)
|
||||||
|
{
|
||||||
|
double hz = clip3d->sclipBottom;
|
||||||
|
if (spr->fakefloor)
|
||||||
|
{
|
||||||
|
double floorz = spr->fakefloor->top.plane->Zat0();
|
||||||
|
if (ViewPos.Z > floorz && floorz == clip3d->sclipBottom)
|
||||||
|
{
|
||||||
|
hz = spr->fakefloor->bottom.plane->Zat0();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
||||||
|
if (h < botclip)
|
||||||
|
{
|
||||||
|
botclip = MAX<short>(0, h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hzb = MAX(hzb, clip3d->sclipBottom);
|
||||||
|
}
|
||||||
|
if (clip3d->fake3D & FAKE3D_CLIPTOP)
|
||||||
|
{
|
||||||
|
if (!spr->bIsVoxel)
|
||||||
|
{
|
||||||
|
double hz = clip3d->sclipTop;
|
||||||
|
if (spr->fakeceiling != nullptr)
|
||||||
|
{
|
||||||
|
double ceilingZ = spr->fakeceiling->bottom.plane->Zat0();
|
||||||
|
if (ViewPos.Z < ceilingZ && ceilingZ == clip3d->sclipTop)
|
||||||
|
{
|
||||||
|
hz = spr->fakeceiling->top.plane->Zat0();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
||||||
|
if (h > topclip)
|
||||||
|
{
|
||||||
|
topclip = short(MIN(h, viewheight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hzt = MIN(hzt, clip3d->sclipTop);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (topclip >= botclip)
|
||||||
|
{
|
||||||
|
spr->Style.BaseColormap = colormap;
|
||||||
|
spr->Style.ColormapNum = colormapnum;
|
||||||
|
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
|
||||||
|
{
|
||||||
|
// [ZZ] portal handling here
|
||||||
|
//if (ds->CurrentPortalUniq != spr->CurrentPortalUniq)
|
||||||
|
// continue;
|
||||||
|
// [ZZ] WARNING: uncommenting the two above lines, totally breaks sprite clipping
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
float 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) &&
|
||||||
|
(spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) -
|
||||||
|
(spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0))
|
||||||
|
{
|
||||||
|
RenderPortal *renderportal = RenderPortal::Instance();
|
||||||
|
|
||||||
|
// seg is behind sprite, so draw the mid texture if it has one
|
||||||
|
if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq && // [ZZ] instead, portal uniq check is made here
|
||||||
|
(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)
|
||||||
|
{
|
||||||
|
if (!spr->bWallSprite)
|
||||||
|
{
|
||||||
|
RenderSprite::Render(spr, clipbot, cliptop);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RenderWallSprite::Render(spr, clipbot, cliptop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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.BaseColormap = colormap;
|
||||||
|
spr->Style.ColormapNum = colormapnum;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add everything outside the left and right edges to the clipping array
|
||||||
|
// for R_DrawVisVoxel().
|
||||||
|
if (x1 > 0)
|
||||||
|
{
|
||||||
|
fillshort(cliptop, x1, viewheight);
|
||||||
|
}
|
||||||
|
if (x2 < viewwidth - 1)
|
||||||
|
{
|
||||||
|
fillshort(cliptop + x2, viewwidth - x2, viewheight);
|
||||||
|
}
|
||||||
|
int minvoxely = spr->gzt <= hzt ? 0 : xs_RoundToInt((spr->gzt - hzt) / spr->yscale);
|
||||||
|
int maxvoxely = spr->gzb > hzb ? INT_MAX : xs_RoundToInt((spr->gzt - hzb) / spr->yscale);
|
||||||
|
RenderVoxel::Render(spr, minvoxely, maxvoxely, cliptop, clipbot);
|
||||||
|
}
|
||||||
|
spr->Style.BaseColormap = colormap;
|
||||||
|
spr->Style.ColormapNum = colormapnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTranslucent::DrawMaskedSingle(bool renew)
|
||||||
|
{
|
||||||
|
RenderPortal *renderportal = RenderPortal::Instance();
|
||||||
|
|
||||||
|
for (int i = SortedVisibleSpriteList::vsprcount; i > 0; i--)
|
||||||
|
{
|
||||||
|
if (SortedVisibleSpriteList::spritesorter[i - 1]->CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
||||||
|
continue; // probably another time
|
||||||
|
DrawSprite(SortedVisibleSpriteList::spritesorter[i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render any remaining masked mid textures
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
if (renew)
|
||||||
|
{
|
||||||
|
Clip3DFloors::Instance()->fake3D |= FAKE3D_REFRESHCLIP;
|
||||||
|
}
|
||||||
|
for (drawseg_t *ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
||||||
|
{
|
||||||
|
// [ZZ] the same as above
|
||||||
|
if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
||||||
|
continue;
|
||||||
|
// kg3D - no fake segs
|
||||||
|
if (ds->fake) continue;
|
||||||
|
if (ds->maskedtexturecol != -1 || ds->bFogBoundary)
|
||||||
|
{
|
||||||
|
R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderTranslucent::Render()
|
||||||
|
{
|
||||||
|
CollectPortals();
|
||||||
|
SortedVisibleSpriteList::Sort(DrewAVoxel ? SortedVisibleSpriteList::sv_compare2d : SortedVisibleSpriteList::sv_compare, VisibleSpriteList::firstvissprite - VisibleSpriteList::vissprites);
|
||||||
|
|
||||||
|
Clip3DFloors *clip3d = Clip3DFloors::Instance();
|
||||||
|
if (clip3d->height_top == nullptr)
|
||||||
|
{ // kg3D - no visible 3D floors, normal rendering
|
||||||
|
DrawMaskedSingle(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // kg3D - correct sorting
|
||||||
|
// ceilings
|
||||||
|
for (HeightLevel *hl = clip3d->height_cur; hl != nullptr && hl->height >= ViewPos.Z; hl = hl->prev)
|
||||||
|
{
|
||||||
|
if (hl->next)
|
||||||
|
{
|
||||||
|
clip3d->fake3D = FAKE3D_CLIPBOTTOM | FAKE3D_CLIPTOP;
|
||||||
|
clip3d->sclipTop = hl->next->height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clip3d->fake3D = FAKE3D_CLIPBOTTOM;
|
||||||
|
}
|
||||||
|
clip3d->sclipBottom = hl->height;
|
||||||
|
DrawMaskedSingle(true);
|
||||||
|
R_DrawHeightPlanes(hl->height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// floors
|
||||||
|
clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP;
|
||||||
|
clip3d->sclipTop = clip3d->height_top->height;
|
||||||
|
DrawMaskedSingle(true);
|
||||||
|
for (HeightLevel *hl = clip3d->height_top; hl != nullptr && hl->height < ViewPos.Z; hl = hl->next)
|
||||||
|
{
|
||||||
|
R_DrawHeightPlanes(hl->height);
|
||||||
|
if (hl->next)
|
||||||
|
{
|
||||||
|
clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP | FAKE3D_CLIPBOTTOM;
|
||||||
|
clip3d->sclipTop = hl->next->height;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPBOTTOM;
|
||||||
|
}
|
||||||
|
clip3d->sclipBottom = hl->height;
|
||||||
|
DrawMaskedSingle(true);
|
||||||
|
}
|
||||||
|
clip3d->DeleteHeights();
|
||||||
|
clip3d->fake3D = 0;
|
||||||
|
}
|
||||||
|
RenderPlayerSprite::RenderPlayerSprites();
|
||||||
|
}
|
||||||
|
}
|
46
src/swrenderer/scene/r_translucent.h
Normal file
46
src/swrenderer/scene/r_translucent.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
//
|
||||||
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||||
|
//
|
||||||
|
// This source is available for distribution and/or modification
|
||||||
|
// only under the terms of the DOOM Source Code License as
|
||||||
|
// published by id Software. All rights reserved.
|
||||||
|
//
|
||||||
|
// The source is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tarray.h"
|
||||||
|
|
||||||
|
#define MINZ double((2048*4) / double(1 << 20))
|
||||||
|
|
||||||
|
struct particle_t;
|
||||||
|
struct FVoxel;
|
||||||
|
|
||||||
|
namespace swrenderer
|
||||||
|
{
|
||||||
|
struct vissprite_t;
|
||||||
|
struct drawseg_t;
|
||||||
|
|
||||||
|
class RenderTranslucent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Deinit();
|
||||||
|
static void Clear();
|
||||||
|
static void Render();
|
||||||
|
|
||||||
|
static bool DrewAVoxel;
|
||||||
|
|
||||||
|
static bool ClipSpriteColumnWithPortals(int x, vissprite_t* spr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void CollectPortals();
|
||||||
|
static void DrawSprite(vissprite_t *spr);
|
||||||
|
static void DrawMaskedSingle(bool renew);
|
||||||
|
|
||||||
|
static TArray<drawseg_t *> portaldrawsegs;
|
||||||
|
};
|
||||||
|
}
|
|
@ -40,6 +40,7 @@
|
||||||
#include "p_effect.h"
|
#include "p_effect.h"
|
||||||
#include "swrenderer/scene/r_bsp.h"
|
#include "swrenderer/scene/r_bsp.h"
|
||||||
#include "swrenderer/scene/r_3dfloors.h"
|
#include "swrenderer/scene/r_3dfloors.h"
|
||||||
|
#include "swrenderer/scene/r_translucent.h"
|
||||||
#include "swrenderer/drawers/r_draw_rgba.h"
|
#include "swrenderer/drawers/r_draw_rgba.h"
|
||||||
#include "swrenderer/drawers/r_draw_pal.h"
|
#include "swrenderer/drawers/r_draw_pal.h"
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "p_effect.h"
|
#include "p_effect.h"
|
||||||
#include "swrenderer/scene/r_bsp.h"
|
#include "swrenderer/scene/r_bsp.h"
|
||||||
#include "swrenderer/scene/r_3dfloors.h"
|
#include "swrenderer/scene/r_3dfloors.h"
|
||||||
|
#include "swrenderer/scene/r_translucent.h"
|
||||||
#include "swrenderer/drawers/r_draw_rgba.h"
|
#include "swrenderer/drawers/r_draw_rgba.h"
|
||||||
#include "swrenderer/drawers/r_draw_pal.h"
|
#include "swrenderer/drawers/r_draw_pal.h"
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
|
|
|
@ -34,699 +34,6 @@
|
||||||
#include "swrenderer/plane/r_visibleplane.h"
|
#include "swrenderer/plane/r_visibleplane.h"
|
||||||
#include "swrenderer/r_memory.h"
|
#include "swrenderer/r_memory.h"
|
||||||
|
|
||||||
EXTERN_CVAR(Int, r_drawfuzz)
|
|
||||||
EXTERN_CVAR(Bool, r_drawvoxels)
|
|
||||||
EXTERN_CVAR(Bool, r_blendmethod)
|
|
||||||
|
|
||||||
CVAR(Bool, r_fullbrightignoresectorcolor, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG);
|
|
||||||
CVAR(Bool, r_splitsprites, true, CVAR_ARCHIVE)
|
|
||||||
|
|
||||||
namespace swrenderer
|
namespace swrenderer
|
||||||
{
|
{
|
||||||
void VisibleSpriteList::Deinit()
|
|
||||||
{
|
|
||||||
// Free vissprites
|
|
||||||
for (int i = 0; i < MaxVisSprites; ++i)
|
|
||||||
{
|
|
||||||
delete vissprites[i];
|
|
||||||
}
|
|
||||||
free(vissprites);
|
|
||||||
vissprites = nullptr;
|
|
||||||
vissprite_p = lastvissprite = nullptr;
|
|
||||||
MaxVisSprites = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void VisibleSpriteList::Clear()
|
|
||||||
{
|
|
||||||
vissprite_p = firstvissprite;
|
|
||||||
}
|
|
||||||
|
|
||||||
vissprite_t *VisibleSpriteList::Add()
|
|
||||||
{
|
|
||||||
if (vissprite_p == lastvissprite)
|
|
||||||
{
|
|
||||||
ptrdiff_t firstvisspritenum = firstvissprite - vissprites;
|
|
||||||
ptrdiff_t prevvisspritenum = vissprite_p - vissprites;
|
|
||||||
|
|
||||||
MaxVisSprites = MaxVisSprites ? MaxVisSprites * 2 : 128;
|
|
||||||
vissprites = (vissprite_t **)M_Realloc(vissprites, MaxVisSprites * sizeof(vissprite_t));
|
|
||||||
lastvissprite = &vissprites[MaxVisSprites];
|
|
||||||
firstvissprite = &vissprites[firstvisspritenum];
|
|
||||||
vissprite_p = &vissprites[prevvisspritenum];
|
|
||||||
DPrintf(DMSG_NOTIFY, "MaxVisSprites increased to %d\n", MaxVisSprites);
|
|
||||||
|
|
||||||
// Allocate sprites from the new pile
|
|
||||||
for (vissprite_t **p = vissprite_p; p < lastvissprite; ++p)
|
|
||||||
{
|
|
||||||
*p = new vissprite_t;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vissprite_p++;
|
|
||||||
return *(vissprite_p - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int VisibleSpriteList::MaxVisSprites;
|
|
||||||
vissprite_t **VisibleSpriteList::vissprites;
|
|
||||||
vissprite_t **VisibleSpriteList::firstvissprite;
|
|
||||||
vissprite_t **VisibleSpriteList::vissprite_p;
|
|
||||||
vissprite_t **VisibleSpriteList::lastvissprite;
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
void SortedVisibleSpriteList::Deinit()
|
|
||||||
{
|
|
||||||
delete[] spritesorter;
|
|
||||||
spritesortersize = 0;
|
|
||||||
spritesorter = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is the standard version, which does a simple test based on depth.
|
|
||||||
bool SortedVisibleSpriteList::sv_compare(vissprite_t *a, vissprite_t *b)
|
|
||||||
{
|
|
||||||
return a->idepth > b->idepth;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is an alternate version, for when one or more voxel is in view.
|
|
||||||
// It does a 2D distance test based on whichever one is furthest from
|
|
||||||
// the viewpoint.
|
|
||||||
bool SortedVisibleSpriteList::sv_compare2d(vissprite_t *a, vissprite_t *b)
|
|
||||||
{
|
|
||||||
return DVector2(a->deltax, a->deltay).LengthSquared() < DVector2(b->deltax, b->deltay).LengthSquared();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SortedVisibleSpriteList::Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
vissprite_t **spr;
|
|
||||||
|
|
||||||
vsprcount = int(VisibleSpriteList::vissprite_p - &VisibleSpriteList::vissprites[first]);
|
|
||||||
|
|
||||||
if (vsprcount == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (spritesortersize < VisibleSpriteList::MaxVisSprites)
|
|
||||||
{
|
|
||||||
if (spritesorter != nullptr)
|
|
||||||
delete[] spritesorter;
|
|
||||||
spritesorter = new vissprite_t *[VisibleSpriteList::MaxVisSprites];
|
|
||||||
spritesortersize = VisibleSpriteList::MaxVisSprites;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(i_compatflags & COMPATF_SPRITESORT))
|
|
||||||
{
|
|
||||||
for (i = 0, spr = VisibleSpriteList::firstvissprite; i < vsprcount; i++, spr++)
|
|
||||||
{
|
|
||||||
spritesorter[i] = *spr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// If the compatibility option is on sprites of equal distance need to
|
|
||||||
// be sorted in inverse order. This is most easily achieved by
|
|
||||||
// filling the sort array backwards before the sort.
|
|
||||||
for (i = 0, spr = VisibleSpriteList::firstvissprite + vsprcount - 1; i < vsprcount; i++, spr--)
|
|
||||||
{
|
|
||||||
spritesorter[i] = *spr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::stable_sort(&spritesorter[0], &spritesorter[vsprcount], compare);
|
|
||||||
}
|
|
||||||
|
|
||||||
vissprite_t **SortedVisibleSpriteList::spritesorter;
|
|
||||||
int SortedVisibleSpriteList::spritesortersize = 0;
|
|
||||||
int SortedVisibleSpriteList::vsprcount;
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool RenderTranslucent::DrewAVoxel;
|
|
||||||
TArray<drawseg_t *> RenderTranslucent::portaldrawsegs;
|
|
||||||
|
|
||||||
void RenderTranslucent::Deinit()
|
|
||||||
{
|
|
||||||
VisibleSpriteList::Deinit();
|
|
||||||
SortedVisibleSpriteList::Deinit();
|
|
||||||
RenderVoxel::Deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderTranslucent::Clear()
|
|
||||||
{
|
|
||||||
VisibleSpriteList::Clear();
|
|
||||||
DrewAVoxel = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderTranslucent::CollectPortals()
|
|
||||||
{
|
|
||||||
// This function collects all drawsegs that may be of interest to R_ClipSpriteColumnWithPortals
|
|
||||||
// Having that function over the entire list of drawsegs can break down performance quite drastically.
|
|
||||||
// This is doing the costly stuff only once so that R_ClipSpriteColumnWithPortals can
|
|
||||||
// a) exit early if no relevant info is found and
|
|
||||||
// b) skip most of the collected drawsegs which have no portal attached.
|
|
||||||
portaldrawsegs.Clear();
|
|
||||||
for (drawseg_t* seg = ds_p; seg-- > firstdrawseg; ) // copied code from killough below
|
|
||||||
{
|
|
||||||
// I don't know what makes this happen (some old top-down portal code or possibly skybox code? something adds null lines...)
|
|
||||||
// crashes at the first frame of the first map of Action2.wad
|
|
||||||
if (!seg->curline) continue;
|
|
||||||
|
|
||||||
line_t* line = seg->curline->linedef;
|
|
||||||
// ignore minisegs from GL nodes.
|
|
||||||
if (!line) continue;
|
|
||||||
|
|
||||||
// check if this line will clip sprites to itself
|
|
||||||
if (!line->isVisualPortal() && line->special != Line_Mirror)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// don't clip sprites with portal's back side (it's transparent)
|
|
||||||
if (seg->curline->sidedef != line->sidedef[0])
|
|
||||||
continue;
|
|
||||||
|
|
||||||
portaldrawsegs.Push(seg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RenderTranslucent::ClipSpriteColumnWithPortals(int x, vissprite_t* spr)
|
|
||||||
{
|
|
||||||
RenderPortal *renderportal = RenderPortal::Instance();
|
|
||||||
|
|
||||||
// [ZZ] 10.01.2016: don't clip sprites from the root of a skybox.
|
|
||||||
if (renderportal->CurrentPortalInSkybox)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (drawseg_t *seg : portaldrawsegs)
|
|
||||||
{
|
|
||||||
// ignore segs from other portals
|
|
||||||
if (seg->CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// (all checks that are already done in R_CollectPortals have been removed for performance reasons.)
|
|
||||||
|
|
||||||
// don't clip if the sprite is in front of the portal
|
|
||||||
if (!P_PointOnLineSidePrecise(spr->gpos.X, spr->gpos.Y, seg->curline->linedef))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// now if current column is covered by this drawseg, we clip it away
|
|
||||||
if ((x >= seg->x1) && (x < seg->x2))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderTranslucent::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;
|
|
||||||
FSWColormap *colormap = spr->Style.BaseColormap;
|
|
||||||
int colormapnum = spr->Style.ColormapNum;
|
|
||||||
F3DFloor *rover;
|
|
||||||
FDynamicColormap *mybasecolormap;
|
|
||||||
|
|
||||||
Clip3DFloors *clip3d = Clip3DFloors::Instance();
|
|
||||||
|
|
||||||
// [RH] Check for particles
|
|
||||||
if (!spr->bIsVoxel && spr->pic == nullptr)
|
|
||||||
{
|
|
||||||
// kg3D - reject invisible parts
|
|
||||||
if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gpos.Z <= clip3d->sclipBottom) return;
|
|
||||||
if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gpos.Z >= clip3d->sclipTop) return;
|
|
||||||
RenderParticle::Render(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 == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// kg3D - reject invisible parts
|
|
||||||
if ((clip3d->fake3D & FAKE3D_CLIPBOTTOM) && spr->gzt <= clip3d->sclipBottom) return;
|
|
||||||
if ((clip3d->fake3D & FAKE3D_CLIPTOP) && spr->gzb >= clip3d->sclipTop) return;
|
|
||||||
|
|
||||||
// kg3D - correct colors now
|
|
||||||
if (!fixedcolormap && fixedlightlev < 0 && spr->sector->e && spr->sector->e->XFloor.lightlist.Size())
|
|
||||||
{
|
|
||||||
if (!(clip3d->fake3D & FAKE3D_CLIPTOP))
|
|
||||||
{
|
|
||||||
clip3d->sclipTop = spr->sector->ceilingplane.ZatPoint(ViewPos);
|
|
||||||
}
|
|
||||||
sector_t *sec = nullptr;
|
|
||||||
for (i = spr->sector->e->XFloor.lightlist.Size() - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (clip3d->sclipTop <= spr->sector->e->XFloor.lightlist[i].plane.Zat0())
|
|
||||||
{
|
|
||||||
rover = spr->sector->e->XFloor.lightlist[i].caster;
|
|
||||||
if (rover)
|
|
||||||
{
|
|
||||||
if (rover->flags & FF_DOUBLESHADOW && clip3d->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.BaseColormap = mybasecolormap;
|
|
||||||
spr->Style.ColormapNum = fixedlightlev >> COLORMAPSHIFT;
|
|
||||||
}
|
|
||||||
else if (!foggy && (spr->renderflags & RF_FULLBRIGHT))
|
|
||||||
{ // full bright
|
|
||||||
spr->Style.BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : mybasecolormap;
|
|
||||||
spr->Style.ColormapNum = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // diminished light
|
|
||||||
int spriteshade = LIGHT2SHADE(sec->lightlevel + r_actualextralight);
|
|
||||||
spr->Style.BaseColormap = mybasecolormap;
|
|
||||||
spr->Style.ColormapNum = GETPALOOKUP(r_SpriteVisibility / MAX(MINZ, (double)spr->depth), spriteshade);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// [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
|
|
||||||
|
|
||||||
double scale = InvZtoScale * spr->idepth;
|
|
||||||
double hzb = DBL_MIN, hzt = DBL_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 != WaterFakeSide::AboveCeiling)
|
|
||||||
{
|
|
||||||
double hz = spr->heightsec->floorplane.ZatPoint(spr->gpos);
|
|
||||||
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
|
||||||
|
|
||||||
if (spr->FakeFlatStat == WaterFakeSide::BelowFloor)
|
|
||||||
{ // seen below floor: clip top
|
|
||||||
if (!spr->bIsVoxel && h > topclip)
|
|
||||||
{
|
|
||||||
topclip = short(MIN(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 != WaterFakeSide::BelowFloor && !(spr->heightsec->MoreFlags & SECF_FAKEFLOORONLY))
|
|
||||||
{
|
|
||||||
double hz = spr->heightsec->ceilingplane.ZatPoint(spr->gpos);
|
|
||||||
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
|
||||||
|
|
||||||
if (spr->FakeFlatStat == WaterFakeSide::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(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 = ((FLOAT2FIXED(CenterY) - FixedMul (spr->texturemid - (spr->pic->GetHeight() << FRACBITS) + spr->floorclip, spr->yscale)) >> FRACBITS);
|
|
||||||
int clip = xs_RoundToInt(CenterY - (spr->texturemid - spr->pic->GetHeight() + spr->floorclip) * spr->yscale);
|
|
||||||
if (clip < botclip)
|
|
||||||
{
|
|
||||||
botclip = MAX<short>(0, clip);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (clip3d->fake3D & FAKE3D_CLIPBOTTOM)
|
|
||||||
{
|
|
||||||
if (!spr->bIsVoxel)
|
|
||||||
{
|
|
||||||
double hz = clip3d->sclipBottom;
|
|
||||||
if (spr->fakefloor)
|
|
||||||
{
|
|
||||||
double floorz = spr->fakefloor->top.plane->Zat0();
|
|
||||||
if (ViewPos.Z > floorz && floorz == clip3d->sclipBottom)
|
|
||||||
{
|
|
||||||
hz = spr->fakefloor->bottom.plane->Zat0();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
|
||||||
if (h < botclip)
|
|
||||||
{
|
|
||||||
botclip = MAX<short>(0, h);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hzb = MAX(hzb, clip3d->sclipBottom);
|
|
||||||
}
|
|
||||||
if (clip3d->fake3D & FAKE3D_CLIPTOP)
|
|
||||||
{
|
|
||||||
if (!spr->bIsVoxel)
|
|
||||||
{
|
|
||||||
double hz = clip3d->sclipTop;
|
|
||||||
if (spr->fakeceiling != nullptr)
|
|
||||||
{
|
|
||||||
double ceilingZ = spr->fakeceiling->bottom.plane->Zat0();
|
|
||||||
if (ViewPos.Z < ceilingZ && ceilingZ == clip3d->sclipTop)
|
|
||||||
{
|
|
||||||
hz = spr->fakeceiling->top.plane->Zat0();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale);
|
|
||||||
if (h > topclip)
|
|
||||||
{
|
|
||||||
topclip = short(MIN(h, viewheight));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
hzt = MIN(hzt, clip3d->sclipTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (topclip >= botclip)
|
|
||||||
{
|
|
||||||
spr->Style.BaseColormap = colormap;
|
|
||||||
spr->Style.ColormapNum = colormapnum;
|
|
||||||
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
|
|
||||||
{
|
|
||||||
// [ZZ] portal handling here
|
|
||||||
//if (ds->CurrentPortalUniq != spr->CurrentPortalUniq)
|
|
||||||
// continue;
|
|
||||||
// [ZZ] WARNING: uncommenting the two above lines, totally breaks sprite clipping
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
float 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) &&
|
|
||||||
(spr->gpos.Y - ds->curline->v1->fY()) * (ds->curline->v2->fX() - ds->curline->v1->fX()) -
|
|
||||||
(spr->gpos.X - ds->curline->v1->fX()) * (ds->curline->v2->fY() - ds->curline->v1->fY()) <= 0))
|
|
||||||
{
|
|
||||||
RenderPortal *renderportal = RenderPortal::Instance();
|
|
||||||
|
|
||||||
// seg is behind sprite, so draw the mid texture if it has one
|
|
||||||
if (ds->CurrentPortalUniq == renderportal->CurrentPortalUniq && // [ZZ] instead, portal uniq check is made here
|
|
||||||
(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)
|
|
||||||
{
|
|
||||||
if (!spr->bWallSprite)
|
|
||||||
{
|
|
||||||
RenderSprite::Render(spr, clipbot, cliptop);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RenderWallSprite::Render(spr, clipbot, cliptop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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.BaseColormap = colormap;
|
|
||||||
spr->Style.ColormapNum = colormapnum;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Add everything outside the left and right edges to the clipping array
|
|
||||||
// for R_DrawVisVoxel().
|
|
||||||
if (x1 > 0)
|
|
||||||
{
|
|
||||||
fillshort(cliptop, x1, viewheight);
|
|
||||||
}
|
|
||||||
if (x2 < viewwidth - 1)
|
|
||||||
{
|
|
||||||
fillshort(cliptop + x2, viewwidth - x2, viewheight);
|
|
||||||
}
|
|
||||||
int minvoxely = spr->gzt <= hzt ? 0 : xs_RoundToInt((spr->gzt - hzt) / spr->yscale);
|
|
||||||
int maxvoxely = spr->gzb > hzb ? INT_MAX : xs_RoundToInt((spr->gzt - hzb) / spr->yscale);
|
|
||||||
RenderVoxel::Render(spr, minvoxely, maxvoxely, cliptop, clipbot);
|
|
||||||
}
|
|
||||||
spr->Style.BaseColormap = colormap;
|
|
||||||
spr->Style.ColormapNum = colormapnum;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderTranslucent::DrawMaskedSingle(bool renew)
|
|
||||||
{
|
|
||||||
RenderPortal *renderportal = RenderPortal::Instance();
|
|
||||||
|
|
||||||
for (int i = SortedVisibleSpriteList::vsprcount; i > 0; i--)
|
|
||||||
{
|
|
||||||
if (SortedVisibleSpriteList::spritesorter[i - 1]->CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
|
||||||
continue; // probably another time
|
|
||||||
DrawSprite(SortedVisibleSpriteList::spritesorter[i - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render any remaining masked mid textures
|
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
if (renew)
|
|
||||||
{
|
|
||||||
Clip3DFloors::Instance()->fake3D |= FAKE3D_REFRESHCLIP;
|
|
||||||
}
|
|
||||||
for (drawseg_t *ds = ds_p; ds-- > firstdrawseg; ) // new -- killough
|
|
||||||
{
|
|
||||||
// [ZZ] the same as above
|
|
||||||
if (ds->CurrentPortalUniq != renderportal->CurrentPortalUniq)
|
|
||||||
continue;
|
|
||||||
// kg3D - no fake segs
|
|
||||||
if (ds->fake) continue;
|
|
||||||
if (ds->maskedtexturecol != -1 || ds->bFogBoundary)
|
|
||||||
{
|
|
||||||
R_RenderMaskedSegRange(ds, ds->x1, ds->x2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderTranslucent::Render()
|
|
||||||
{
|
|
||||||
CollectPortals();
|
|
||||||
SortedVisibleSpriteList::Sort(DrewAVoxel ? SortedVisibleSpriteList::sv_compare2d : SortedVisibleSpriteList::sv_compare, VisibleSpriteList::firstvissprite - VisibleSpriteList::vissprites);
|
|
||||||
|
|
||||||
Clip3DFloors *clip3d = Clip3DFloors::Instance();
|
|
||||||
if (clip3d->height_top == nullptr)
|
|
||||||
{ // kg3D - no visible 3D floors, normal rendering
|
|
||||||
DrawMaskedSingle(false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ // kg3D - correct sorting
|
|
||||||
// ceilings
|
|
||||||
for (HeightLevel *hl = clip3d->height_cur; hl != nullptr && hl->height >= ViewPos.Z; hl = hl->prev)
|
|
||||||
{
|
|
||||||
if (hl->next)
|
|
||||||
{
|
|
||||||
clip3d->fake3D = FAKE3D_CLIPBOTTOM | FAKE3D_CLIPTOP;
|
|
||||||
clip3d->sclipTop = hl->next->height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clip3d->fake3D = FAKE3D_CLIPBOTTOM;
|
|
||||||
}
|
|
||||||
clip3d->sclipBottom = hl->height;
|
|
||||||
DrawMaskedSingle(true);
|
|
||||||
R_DrawHeightPlanes(hl->height);
|
|
||||||
}
|
|
||||||
|
|
||||||
// floors
|
|
||||||
clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP;
|
|
||||||
clip3d->sclipTop = clip3d->height_top->height;
|
|
||||||
DrawMaskedSingle(true);
|
|
||||||
for (HeightLevel *hl = clip3d->height_top; hl != nullptr && hl->height < ViewPos.Z; hl = hl->next)
|
|
||||||
{
|
|
||||||
R_DrawHeightPlanes(hl->height);
|
|
||||||
if (hl->next)
|
|
||||||
{
|
|
||||||
clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPTOP | FAKE3D_CLIPBOTTOM;
|
|
||||||
clip3d->sclipTop = hl->next->height;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clip3d->fake3D = FAKE3D_DOWN2UP | FAKE3D_CLIPBOTTOM;
|
|
||||||
}
|
|
||||||
clip3d->sclipBottom = hl->height;
|
|
||||||
DrawMaskedSingle(true);
|
|
||||||
}
|
|
||||||
clip3d->DeleteHeights();
|
|
||||||
clip3d->fake3D = 0;
|
|
||||||
}
|
|
||||||
RenderPlayerSprite::RenderPlayerSprites();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "swrenderer/line/r_line.h"
|
#include "swrenderer/line/r_line.h"
|
||||||
#include "swrenderer/scene/r_bsp.h"
|
#include "swrenderer/scene/r_bsp.h"
|
||||||
|
#include "swrenderer/things/r_visiblespritelist.h"
|
||||||
|
|
||||||
#define MINZ double((2048*4) / double(1 << 20))
|
#define MINZ double((2048*4) / double(1 << 20))
|
||||||
|
|
||||||
|
@ -23,8 +24,6 @@ struct FVoxel;
|
||||||
|
|
||||||
namespace swrenderer
|
namespace swrenderer
|
||||||
{
|
{
|
||||||
struct drawseg_t;
|
|
||||||
|
|
||||||
struct vissprite_t
|
struct vissprite_t
|
||||||
{
|
{
|
||||||
struct posang
|
struct posang
|
||||||
|
@ -89,56 +88,4 @@ namespace swrenderer
|
||||||
|
|
||||||
vissprite_t() {}
|
vissprite_t() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class VisibleSpriteList
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static int MaxVisSprites;
|
|
||||||
static vissprite_t **vissprites;
|
|
||||||
static vissprite_t **firstvissprite;
|
|
||||||
static vissprite_t **vissprite_p;
|
|
||||||
|
|
||||||
static void Deinit();
|
|
||||||
static void Clear();
|
|
||||||
static vissprite_t *Add();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static vissprite_t **lastvissprite;
|
|
||||||
};
|
|
||||||
|
|
||||||
class SortedVisibleSpriteList
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void Deinit();
|
|
||||||
|
|
||||||
static void Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first);
|
|
||||||
|
|
||||||
static bool sv_compare(vissprite_t *a, vissprite_t *b);
|
|
||||||
static bool sv_compare2d(vissprite_t *a, vissprite_t *b);
|
|
||||||
|
|
||||||
static vissprite_t **spritesorter;
|
|
||||||
static int vsprcount;
|
|
||||||
|
|
||||||
private:
|
|
||||||
static int spritesortersize;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RenderTranslucent
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void Deinit();
|
|
||||||
static void Clear();
|
|
||||||
static void Render();
|
|
||||||
|
|
||||||
static bool DrewAVoxel;
|
|
||||||
|
|
||||||
static bool ClipSpriteColumnWithPortals(int x, vissprite_t* spr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void CollectPortals();
|
|
||||||
static void DrawSprite(vissprite_t *spr);
|
|
||||||
static void DrawMaskedSingle(bool renew);
|
|
||||||
|
|
||||||
static TArray<drawseg_t *> portaldrawsegs;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
146
src/swrenderer/things/r_visiblespritelist.cpp
Normal file
146
src/swrenderer/things/r_visiblespritelist.cpp
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
//
|
||||||
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||||
|
//
|
||||||
|
// This source is available for distribution and/or modification
|
||||||
|
// only under the terms of the DOOM Source Code License as
|
||||||
|
// published by id Software. All rights reserved.
|
||||||
|
//
|
||||||
|
// The source is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "p_lnspec.h"
|
||||||
|
#include "templates.h"
|
||||||
|
#include "doomdef.h"
|
||||||
|
#include "m_swap.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
#include "w_wad.h"
|
||||||
|
#include "g_levellocals.h"
|
||||||
|
#include "p_maputl.h"
|
||||||
|
#include "swrenderer/r_main.h"
|
||||||
|
#include "swrenderer/things/r_visiblesprite.h"
|
||||||
|
#include "swrenderer/things/r_visiblespritelist.h"
|
||||||
|
#include "swrenderer/r_memory.h"
|
||||||
|
|
||||||
|
namespace swrenderer
|
||||||
|
{
|
||||||
|
void VisibleSpriteList::Deinit()
|
||||||
|
{
|
||||||
|
// Free vissprites
|
||||||
|
for (int i = 0; i < MaxVisSprites; ++i)
|
||||||
|
{
|
||||||
|
delete vissprites[i];
|
||||||
|
}
|
||||||
|
free(vissprites);
|
||||||
|
vissprites = nullptr;
|
||||||
|
vissprite_p = lastvissprite = nullptr;
|
||||||
|
MaxVisSprites = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisibleSpriteList::Clear()
|
||||||
|
{
|
||||||
|
vissprite_p = firstvissprite;
|
||||||
|
}
|
||||||
|
|
||||||
|
vissprite_t *VisibleSpriteList::Add()
|
||||||
|
{
|
||||||
|
if (vissprite_p == lastvissprite)
|
||||||
|
{
|
||||||
|
ptrdiff_t firstvisspritenum = firstvissprite - vissprites;
|
||||||
|
ptrdiff_t prevvisspritenum = vissprite_p - vissprites;
|
||||||
|
|
||||||
|
MaxVisSprites = MaxVisSprites ? MaxVisSprites * 2 : 128;
|
||||||
|
vissprites = (vissprite_t **)M_Realloc(vissprites, MaxVisSprites * sizeof(vissprite_t));
|
||||||
|
lastvissprite = &vissprites[MaxVisSprites];
|
||||||
|
firstvissprite = &vissprites[firstvisspritenum];
|
||||||
|
vissprite_p = &vissprites[prevvisspritenum];
|
||||||
|
DPrintf(DMSG_NOTIFY, "MaxVisSprites increased to %d\n", MaxVisSprites);
|
||||||
|
|
||||||
|
// Allocate sprites from the new pile
|
||||||
|
for (vissprite_t **p = vissprite_p; p < lastvissprite; ++p)
|
||||||
|
{
|
||||||
|
*p = new vissprite_t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vissprite_p++;
|
||||||
|
return *(vissprite_p - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int VisibleSpriteList::MaxVisSprites;
|
||||||
|
vissprite_t **VisibleSpriteList::vissprites;
|
||||||
|
vissprite_t **VisibleSpriteList::firstvissprite;
|
||||||
|
vissprite_t **VisibleSpriteList::vissprite_p;
|
||||||
|
vissprite_t **VisibleSpriteList::lastvissprite;
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
void SortedVisibleSpriteList::Deinit()
|
||||||
|
{
|
||||||
|
delete[] spritesorter;
|
||||||
|
spritesortersize = 0;
|
||||||
|
spritesorter = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the standard version, which does a simple test based on depth.
|
||||||
|
bool SortedVisibleSpriteList::sv_compare(vissprite_t *a, vissprite_t *b)
|
||||||
|
{
|
||||||
|
return a->idepth > b->idepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is an alternate version, for when one or more voxel is in view.
|
||||||
|
// It does a 2D distance test based on whichever one is furthest from
|
||||||
|
// the viewpoint.
|
||||||
|
bool SortedVisibleSpriteList::sv_compare2d(vissprite_t *a, vissprite_t *b)
|
||||||
|
{
|
||||||
|
return DVector2(a->deltax, a->deltay).LengthSquared() < DVector2(b->deltax, b->deltay).LengthSquared();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SortedVisibleSpriteList::Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
vissprite_t **spr;
|
||||||
|
|
||||||
|
vsprcount = int(VisibleSpriteList::vissprite_p - &VisibleSpriteList::vissprites[first]);
|
||||||
|
|
||||||
|
if (vsprcount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (spritesortersize < VisibleSpriteList::MaxVisSprites)
|
||||||
|
{
|
||||||
|
if (spritesorter != nullptr)
|
||||||
|
delete[] spritesorter;
|
||||||
|
spritesorter = new vissprite_t *[VisibleSpriteList::MaxVisSprites];
|
||||||
|
spritesortersize = VisibleSpriteList::MaxVisSprites;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(i_compatflags & COMPATF_SPRITESORT))
|
||||||
|
{
|
||||||
|
for (i = 0, spr = VisibleSpriteList::firstvissprite; i < vsprcount; i++, spr++)
|
||||||
|
{
|
||||||
|
spritesorter[i] = *spr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// If the compatibility option is on sprites of equal distance need to
|
||||||
|
// be sorted in inverse order. This is most easily achieved by
|
||||||
|
// filling the sort array backwards before the sort.
|
||||||
|
for (i = 0, spr = VisibleSpriteList::firstvissprite + vsprcount - 1; i < vsprcount; i++, spr--)
|
||||||
|
{
|
||||||
|
spritesorter[i] = *spr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::stable_sort(&spritesorter[0], &spritesorter[vsprcount], compare);
|
||||||
|
}
|
||||||
|
|
||||||
|
vissprite_t **SortedVisibleSpriteList::spritesorter;
|
||||||
|
int SortedVisibleSpriteList::spritesortersize = 0;
|
||||||
|
int SortedVisibleSpriteList::vsprcount;
|
||||||
|
}
|
53
src/swrenderer/things/r_visiblespritelist.h
Normal file
53
src/swrenderer/things/r_visiblespritelist.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
||||||
|
//
|
||||||
|
// This source is available for distribution and/or modification
|
||||||
|
// only under the terms of the DOOM Source Code License as
|
||||||
|
// published by id Software. All rights reserved.
|
||||||
|
//
|
||||||
|
// The source is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
||||||
|
// for more details.
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace swrenderer
|
||||||
|
{
|
||||||
|
struct drawseg_t;
|
||||||
|
struct vissprite_t;
|
||||||
|
|
||||||
|
class VisibleSpriteList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int MaxVisSprites;
|
||||||
|
static vissprite_t **vissprites;
|
||||||
|
static vissprite_t **firstvissprite;
|
||||||
|
static vissprite_t **vissprite_p;
|
||||||
|
|
||||||
|
static void Deinit();
|
||||||
|
static void Clear();
|
||||||
|
static vissprite_t *Add();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static vissprite_t **lastvissprite;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SortedVisibleSpriteList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void Deinit();
|
||||||
|
|
||||||
|
static void Sort(bool(*compare)(vissprite_t *, vissprite_t *), size_t first);
|
||||||
|
|
||||||
|
static bool sv_compare(vissprite_t *a, vissprite_t *b);
|
||||||
|
static bool sv_compare2d(vissprite_t *a, vissprite_t *b);
|
||||||
|
|
||||||
|
static vissprite_t **spritesorter;
|
||||||
|
static int vsprcount;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static int spritesortersize;
|
||||||
|
};
|
||||||
|
}
|
|
@ -37,6 +37,7 @@
|
||||||
#include "swrenderer/things/r_visiblesprite.h"
|
#include "swrenderer/things/r_visiblesprite.h"
|
||||||
#include "swrenderer/things/r_voxel.h"
|
#include "swrenderer/things/r_voxel.h"
|
||||||
#include "swrenderer/scene/r_portal.h"
|
#include "swrenderer/scene/r_portal.h"
|
||||||
|
#include "swrenderer/scene/r_translucent.h"
|
||||||
#include "swrenderer/r_main.h"
|
#include "swrenderer/r_main.h"
|
||||||
|
|
||||||
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
|
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "p_effect.h"
|
#include "p_effect.h"
|
||||||
#include "swrenderer/scene/r_bsp.h"
|
#include "swrenderer/scene/r_bsp.h"
|
||||||
#include "swrenderer/scene/r_3dfloors.h"
|
#include "swrenderer/scene/r_3dfloors.h"
|
||||||
|
#include "swrenderer/scene/r_translucent.h"
|
||||||
#include "swrenderer/drawers/r_draw_rgba.h"
|
#include "swrenderer/drawers/r_draw_rgba.h"
|
||||||
#include "swrenderer/drawers/r_draw_pal.h"
|
#include "swrenderer/drawers/r_draw_pal.h"
|
||||||
#include "v_palette.h"
|
#include "v_palette.h"
|
||||||
|
|
Loading…
Reference in a new issue