Detach voxel and wallsprite projection from (normal) sprite projection and move the type decision making to RenderBSP::AddSprites

This commit is contained in:
Magnus Norddahl 2017-01-11 17:59:29 +01:00
parent dce3a1c81c
commit 4b96d7377f
6 changed files with 424 additions and 280 deletions

View File

@ -36,6 +36,8 @@
#include "swrenderer/drawers/r_draw.h"
#include "swrenderer/plane/r_visibleplane.h"
#include "swrenderer/things/r_sprite.h"
#include "swrenderer/things/r_wallsprite.h"
#include "swrenderer/things/r_voxel.h"
#include "swrenderer/things/r_particle.h"
#include "swrenderer/segments/r_clipsegment.h"
#include "swrenderer/line/r_wallsetup.h"
@ -45,6 +47,7 @@
#include "g_level.h"
#include "p_effect.h"
#include "c_console.h"
#include "p_maputl.h"
// State.
#include "doomstat.h"
@ -57,6 +60,7 @@
#include "g_levellocals.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
EXTERN_CVAR(Bool, r_drawvoxels);
namespace swrenderer
{
@ -855,9 +859,170 @@ namespace swrenderer
if (rover->bottom.plane->ZatPoint(0., 0.) >= thing->Top()) fakeceiling = rover;
}
}
R_ProjectSprite(thing, fakeside, fakefloor, fakeceiling, sec, spriteshade);
if (IsPotentiallyVisible(thing))
{
ThingSprite sprite;
if (GetThingSprite(thing, sprite))
{
if ((sprite.renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
{
R_ProjectWallSprite(thing, sprite.pos, sprite.picnum, sprite.spriteScale, sprite.renderflags, spriteshade);
}
else if (sprite.voxel)
{
R_ProjectVoxel(thing, sprite.pos, sprite.voxel, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, spriteshade);
}
else
{
R_ProjectSprite(thing, sprite.pos, sprite.tex, sprite.spriteScale, sprite.renderflags, fakeside, fakefloor, fakeceiling, sec, spriteshade);
}
}
}
fakeceiling = nullptr;
fakefloor = nullptr;
}
}
bool RenderBSP::IsPotentiallyVisible(AActor *thing)
{
// Don't waste time projecting sprites that are definitely not visible.
if (thing == nullptr ||
(thing->renderflags & RF_INVISIBLE) ||
!thing->RenderStyle.IsVisible(thing->Alpha) ||
!thing->IsVisibleToPlayer() ||
!thing->IsInsideVisibleAngles())
{
return false;
}
// [ZZ] Or less definitely not visible (hue)
// [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal.
RenderPortal *renderportal = RenderPortal::Instance();
if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && !!P_PointOnLineSidePrecise(thing->Pos(), renderportal->CurrentPortal->dst))
return false;
return true;
}
bool RenderBSP::GetThingSprite(AActor *thing, ThingSprite &sprite)
{
sprite.pos = thing->InterpolatedPosition(r_TicFracF);
sprite.pos.Z += thing->GetBobOffset(r_TicFracF);
sprite.spritenum = thing->sprite;
sprite.tex = nullptr;
sprite.voxel = nullptr;
sprite.spriteScale = thing->Scale;
sprite.renderflags = thing->renderflags;
if (thing->picnum.isValid())
{
sprite.picnum = thing->picnum;
sprite.tex = TexMan(sprite.picnum);
if (sprite.tex->UseType == FTexture::TEX_Null)
{
return false;
}
if (sprite.tex->Rotations != 0xFFFF)
{
// choose a different rotation based on player view
spriteframe_t *sprframe = &SpriteFrames[sprite.tex->Rotations];
DAngle ang = (sprite.pos - ViewPos).Angle();
angle_t rot;
if (sprframe->Texture[0] == sprframe->Texture[1])
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28;
}
else
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
}
sprite.picnum = sprframe->Texture[rot];
if (sprframe->Flip & (1 << rot))
{
sprite.renderflags ^= RF_XFLIP;
}
sprite.tex = TexMan[sprite.picnum]; // Do not animate the rotation
}
}
else
{
// decide which texture to use for the sprite
if ((unsigned)sprite.spritenum >= sprites.Size())
{
DPrintf(DMSG_ERROR, "R_ProjectSprite: invalid sprite number %u\n", sprite.spritenum);
return false;
}
spritedef_t *sprdef = &sprites[sprite.spritenum];
if (thing->frame >= sprdef->numframes)
{
// If there are no frames at all for this sprite, don't draw it.
return false;
}
else
{
//picnum = SpriteFrames[sprdef->spriteframes + thing->frame].Texture[0];
// choose a different rotation based on player view
spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + thing->frame];
DAngle ang = (sprite.pos - ViewPos).Angle();
angle_t rot;
if (sprframe->Texture[0] == sprframe->Texture[1])
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28;
}
else
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
}
sprite.picnum = sprframe->Texture[rot];
if (sprframe->Flip & (1 << rot))
{
sprite.renderflags ^= RF_XFLIP;
}
sprite.tex = TexMan[sprite.picnum]; // Do not animate the rotation
if (r_drawvoxels)
{
sprite.voxel = sprframe->Voxel;
}
}
if (sprite.voxel == nullptr && (sprite.tex == nullptr || sprite.tex->UseType == FTexture::TEX_Null))
{
return false;
}
if (sprite.spriteScale.Y < 0)
{
sprite.spriteScale.Y = -sprite.spriteScale.Y;
sprite.renderflags ^= RF_YFLIP;
}
if (thing->player != nullptr)
{
P_CheckPlayerSprite(thing, sprite.spritenum, sprite.spriteScale);
}
if (sprite.spriteScale.X < 0)
{
sprite.spriteScale.X = -sprite.spriteScale.X;
sprite.renderflags ^= RF_XFLIP;
}
}
return true;
}
}

View File

@ -19,6 +19,8 @@
#include "swrenderer/line/r_line.h"
#include "swrenderer/scene/r_3dfloors.h"
struct FVoxelDef;
namespace swrenderer
{
struct visplane_t;
@ -35,6 +37,17 @@ namespace swrenderer
AboveCeiling
};
struct ThingSprite
{
DVector3 pos;
int spritenum;
FTexture *tex;
FVoxelDef *voxel;
FTextureID picnum;
DVector2 spriteScale;
int renderflags;
};
class RenderBSP
{
public:
@ -59,6 +72,9 @@ namespace swrenderer
void AddSprites(sector_t *sec, int lightlevel, WaterFakeSide fakeside);
static bool IsPotentiallyVisible(AActor *thing);
static bool GetThingSprite(AActor *thing, ThingSprite &sprite);
subsector_t *InSubsector = nullptr;
sector_t *frontsector = nullptr;
WaterFakeSide FakeSide = WaterFakeSide::Center;

View File

@ -47,194 +47,32 @@
#include "r_data/colormaps.h"
#include "r_data/voxels.h"
#include "p_local.h"
#include "p_maputl.h"
#include "r_voxel.h"
#include "swrenderer/segments/r_drawsegment.h"
#include "swrenderer/scene/r_portal.h"
#include "swrenderer/things/r_sprite.h"
#include "swrenderer/r_memory.h"
EXTERN_CVAR(Bool, r_drawvoxels)
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
namespace swrenderer
{
void R_ProjectSprite(AActor *thing, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade)
void R_ProjectSprite(AActor *thing, const DVector3 &pos, FTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade)
{
double tr_x;
double tr_y;
double gzt; // killough 3/27/98
double gzb; // [RH] use bottom of sprite, not actor
double tx;// , tx2;
double tz;
double xscale = 1, yscale = 1;
int x1;
int x2;
FTextureID picnum;
FTexture *tex;
FVoxelDef *voxel;
vissprite_t* vis;
fixed_t iscale;
sector_t* heightsec; // killough 3/27/98
// Don't waste time projecting sprites that are definitely not visible.
if (thing == nullptr ||
(thing->renderflags & RF_INVISIBLE) ||
!thing->RenderStyle.IsVisible(thing->Alpha) ||
!thing->IsVisibleToPlayer() ||
!thing->IsInsideVisibleAngles())
{
return;
}
RenderPortal *renderportal = RenderPortal::Instance();
// [ZZ] Or less definitely not visible (hue)
// [ZZ] 10.01.2016: don't try to clip stuff inside a skybox against the current portal.
if (!renderportal->CurrentPortalInSkybox && renderportal->CurrentPortal && !!P_PointOnLineSidePrecise(thing->Pos(), renderportal->CurrentPortal->dst))
return;
// [RH] Interpolate the sprite's position to make it look smooth
DVector3 pos = thing->InterpolatedPosition(r_TicFracF);
pos.Z += thing->GetBobOffset(r_TicFracF);
tex = nullptr;
voxel = nullptr;
int spritenum = thing->sprite;
DVector2 spriteScale = thing->Scale;
int renderflags = thing->renderflags;
if (spriteScale.Y < 0)
{
spriteScale.Y = -spriteScale.Y;
renderflags ^= RF_YFLIP;
}
if (thing->player != nullptr)
{
P_CheckPlayerSprite(thing, spritenum, spriteScale);
}
if (thing->picnum.isValid())
{
picnum = thing->picnum;
tex = TexMan(picnum);
if (tex->UseType == FTexture::TEX_Null)
{
return;
}
if (tex->Rotations != 0xFFFF)
{
// choose a different rotation based on player view
spriteframe_t *sprframe = &SpriteFrames[tex->Rotations];
DAngle ang = (pos - ViewPos).Angle();
angle_t rot;
if (sprframe->Texture[0] == sprframe->Texture[1])
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28;
}
else
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
}
picnum = sprframe->Texture[rot];
if (sprframe->Flip & (1 << rot))
{
renderflags ^= RF_XFLIP;
}
tex = TexMan[picnum]; // Do not animate the rotation
}
}
else
{
// decide which texture to use for the sprite
if ((unsigned)spritenum >= sprites.Size())
{
DPrintf(DMSG_ERROR, "R_ProjectSprite: invalid sprite number %u\n", spritenum);
return;
}
spritedef_t *sprdef = &sprites[spritenum];
if (thing->frame >= sprdef->numframes)
{
// If there are no frames at all for this sprite, don't draw it.
return;
}
else
{
//picnum = SpriteFrames[sprdef->spriteframes + thing->frame].Texture[0];
// choose a different rotation based on player view
spriteframe_t *sprframe = &SpriteFrames[sprdef->spriteframes + thing->frame];
DAngle ang = (pos - ViewPos).Angle();
angle_t rot;
if (sprframe->Texture[0] == sprframe->Texture[1])
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + 45.0 / 2 * 9).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + 45.0 / 2 * 9).BAMs() >> 28;
}
else
{
if (thing->flags7 & MF7_SPRITEANGLE)
rot = (thing->SpriteAngle + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
else
rot = (ang - (thing->Angles.Yaw + thing->SpriteRotation) + (45.0 / 2 * 9 - 180.0 / 16)).BAMs() >> 28;
}
picnum = sprframe->Texture[rot];
if (sprframe->Flip & (1 << rot))
{
renderflags ^= RF_XFLIP;
}
tex = TexMan[picnum]; // Do not animate the rotation
if (r_drawvoxels)
{
voxel = sprframe->Voxel;
}
}
}
if (spriteScale.X < 0)
{
spriteScale.X = -spriteScale.X;
renderflags ^= RF_XFLIP;
}
if (voxel == nullptr && (tex == nullptr || tex->UseType == FTexture::TEX_Null))
{
return;
}
if ((renderflags & RF_SPRITETYPEMASK) == RF_WALLSPRITE)
{
R_ProjectWallSprite(thing, pos, picnum, spriteScale, renderflags, spriteshade);
return;
}
// transform the origin point
tr_x = pos.X - ViewPos.X;
tr_y = pos.Y - ViewPos.Y;
double tr_x = pos.X - ViewPos.X;
double tr_y = pos.Y - ViewPos.Y;
tz = tr_x * ViewTanCos + tr_y * ViewTanSin;
double tz = tr_x * ViewTanCos + tr_y * ViewTanSin;
// thing is behind view plane?
if (voxel == nullptr && tz < MINZ)
if (tz < MINZ)
return;
tx = tr_x * ViewSin - tr_y * ViewCos;
double tx = tr_x * ViewSin - tr_y * ViewCos;
// [RH] Flip for mirrors
RenderPortal *renderportal = RenderPortal::Instance();
if (renderportal->MirrorFlags & RF_XFLIP)
{
tx = -tx;
@ -242,37 +80,22 @@ namespace swrenderer
//tx2 = tx >> 4;
// too far off the side?
// if it's a voxel, it can be further off the side
if ((voxel == nullptr && (fabs(tx / 64) > fabs(tz))) ||
(voxel != nullptr && (fabs(tx / 128) > fabs(tz))))
if (fabs(tx / 64) > fabs(tz))
{
return;
}
if (voxel == nullptr)
{
// [RH] Added scaling
int scaled_to = tex->GetScaledTopOffset();
int scaled_bo = scaled_to - tex->GetScaledHeight();
gzt = pos.Z + spriteScale.Y * scaled_to;
gzb = pos.Z + spriteScale.Y * scaled_bo;
}
else
{
xscale = spriteScale.X * voxel->Scale;
yscale = spriteScale.Y * voxel->Scale;
double piv = voxel->Voxel->Mips[0].Pivot.Z;
gzt = pos.Z + yscale * piv - thing->Floorclip;
gzb = pos.Z + yscale * (piv - voxel->Voxel->Mips[0].SizeZ);
if (gzt <= gzb)
return;
}
// [RH] Added scaling
int scaled_to = tex->GetScaledTopOffset();
int scaled_bo = scaled_to - tex->GetScaledHeight();
double gzt = pos.Z + spriteScale.Y * scaled_to;
double gzb = pos.Z + spriteScale.Y * scaled_bo;
// killough 3/27/98: exclude things totally separated
// from the viewer, by either water or fake ceilings
// killough 4/11/98: improve sprite clipping for underwater/fake ceilings
heightsec = thing->Sector->GetHeightSec();
sector_t *heightsec = thing->Sector->GetHeightSec();
if (heightsec != nullptr) // only clip things which are in special sectors
{
@ -295,95 +118,66 @@ namespace swrenderer
}
}
if (voxel == nullptr)
double xscale = CenterX / tz;
// [RH] Reject sprites that are off the top or bottom of the screen
if (globaluclip * tz > ViewPos.Z - gzb || globaldclip * tz < ViewPos.Z - gzt)
{
xscale = CenterX / tz;
return;
}
// [RH] Reject sprites that are off the top or bottom of the screen
if (globaluclip * tz > ViewPos.Z - gzb || globaldclip * tz < ViewPos.Z - gzt)
{
return;
}
// [RH] Flip for mirrors
renderflags ^= renderportal->MirrorFlags & RF_XFLIP;
// [RH] Flip for mirrors
renderflags ^= renderportal->MirrorFlags & RF_XFLIP;
// calculate edges of the shape
const double thingxscalemul = spriteScale.X / tex->Scale.X;
// calculate edges of the shape
const double thingxscalemul = spriteScale.X / tex->Scale.X;
tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->LeftOffset - 1) : tex->LeftOffset) * thingxscalemul;
double dtx1 = tx * xscale;
int x1 = centerx + xs_RoundToInt(dtx1);
tx -= ((renderflags & RF_XFLIP) ? (tex->GetWidth() - tex->LeftOffset - 1) : tex->LeftOffset) * thingxscalemul;
double dtx1 = tx * xscale;
x1 = centerx + xs_RoundToInt(dtx1);
// off the right side?
if (x1 >= renderportal->WindowRight)
return;
// off the right side?
if (x1 >= renderportal->WindowRight)
return;
tx += tex->GetWidth() * thingxscalemul;
int x2 = centerx + xs_RoundToInt(tx * xscale);
tx += tex->GetWidth() * thingxscalemul;
x2 = centerx + xs_RoundToInt(tx * xscale);
// off the left side or too small?
if ((x2 < renderportal->WindowLeft || x2 <= x1))
return;
// off the left side or too small?
if ((x2 < renderportal->WindowLeft || x2 <= x1))
return;
xscale = spriteScale.X * xscale / tex->Scale.X;
fixed_t iscale = (fixed_t)(FRACUNIT / xscale); // Round towards zero to avoid wrapping in edge cases
xscale = spriteScale.X * xscale / tex->Scale.X;
iscale = (fixed_t)(FRACUNIT / xscale); // Round towards zero to avoid wrapping in edge cases
double yscale = spriteScale.Y / tex->Scale.Y;
double yscale = spriteScale.Y / tex->Scale.Y;
// store information in a vissprite
vissprite_t *vis = R_NewVisSprite();
// store information in a vissprite
vis = R_NewVisSprite();
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
vis->xscale = FLOAT2FIXED(xscale);
vis->yscale = float(InvZtoScale * yscale / tz);
vis->idepth = float(1 / tz);
vis->floorclip = thing->Floorclip / yscale;
vis->texturemid = tex->TopOffset - (ViewPos.Z - pos.Z + thing->Floorclip) / yscale;
vis->x1 = x1 < renderportal->WindowLeft ? renderportal->WindowLeft : x1;
vis->x2 = x2 > renderportal->WindowRight ? renderportal->WindowRight : x2;
vis->Angle = thing->Angles.Yaw;
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
vis->xscale = FLOAT2FIXED(xscale);
vis->yscale = float(InvZtoScale * yscale / tz);
vis->idepth = float(1 / tz);
vis->floorclip = thing->Floorclip / yscale;
vis->texturemid = tex->TopOffset - (ViewPos.Z - pos.Z + thing->Floorclip) / yscale;
vis->x1 = x1 < renderportal->WindowLeft ? renderportal->WindowLeft : x1;
vis->x2 = x2 > renderportal->WindowRight ? renderportal->WindowRight : x2;
vis->Angle = thing->Angles.Yaw;
if (renderflags & RF_XFLIP)
{
vis->startfrac = (tex->GetWidth() << FRACBITS) - 1;
vis->xiscale = -iscale;
}
else
{
vis->startfrac = 0;
vis->xiscale = iscale;
}
vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - centerx + 0.5 - dtx1));
if (renderflags & RF_XFLIP)
{
vis->startfrac = (tex->GetWidth() << FRACBITS) - 1;
vis->xiscale = -iscale;
}
else
{
vis = R_NewVisSprite();
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
vis->xscale = FLOAT2FIXED(xscale);
vis->yscale = (float)yscale;
vis->x1 = renderportal->WindowLeft;
vis->x2 = renderportal->WindowRight;
vis->idepth = 1 / MINZ;
vis->floorclip = thing->Floorclip;
pos.Z -= thing->Floorclip;
vis->Angle = thing->Angles.Yaw + voxel->AngleOffset;
int voxelspin = (thing->flags & MF_DROPPED) ? voxel->DroppedSpin : voxel->PlacedSpin;
if (voxelspin != 0)
{
DAngle ang = double(I_FPSTime()) * voxelspin / 1000;
vis->Angle -= ang;
}
vis->pa.vpos = { (float)ViewPos.X, (float)ViewPos.Y, (float)ViewPos.Z };
vis->pa.vang = FAngle((float)ViewAngle.Degrees);
vis->startfrac = 0;
vis->xiscale = iscale;
}
vis->startfrac += (fixed_t)(vis->xiscale * (vis->x1 - centerx + 0.5 - dtx1));
// killough 3/27/98: save sector for special clipping later
vis->heightsec = heightsec;
vis->sector = thing->Sector;
@ -408,19 +202,9 @@ namespace swrenderer
vis->bInMirror = renderportal->MirrorFlags & RF_XFLIP;
vis->bSplitSprite = false;
if (voxel != nullptr)
{
vis->voxel = voxel->Voxel;
vis->bIsVoxel = true;
vis->bWallSprite = false;
DrewAVoxel = true;
}
else
{
vis->pic = tex;
vis->bIsVoxel = false;
vis->bWallSprite = false;
}
vis->pic = tex;
vis->bIsVoxel = false;
vis->bWallSprite = false;
// The software renderer cannot invert the source without inverting the overlay
// too. That means if the source is inverted, we need to do the reverse of what
@ -481,8 +265,7 @@ namespace swrenderer
}
else
{ // diminished light
vis->Style.ColormapNum = GETPALOOKUP(
r_SpriteVisibility / MAX(tz, MINZ), spriteshade);
vis->Style.ColormapNum = GETPALOOKUP(r_SpriteVisibility / MAX(tz, MINZ), spriteshade);
vis->Style.BaseColormap = mybasecolormap;
}
}

View File

@ -17,6 +17,6 @@
namespace swrenderer
{
void R_ProjectSprite(AActor *thing, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade);
void R_ProjectSprite(AActor *thing, const DVector3 &pos, FTexture *tex, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade);
void R_DrawVisSprite(vissprite_t *vis, const short *mfloorclip, const short *mceilingclip);
}

View File

@ -36,8 +36,11 @@
#include "swrenderer/drawers/r_thread.h"
#include "swrenderer/things/r_visiblesprite.h"
#include "swrenderer/things/r_voxel.h"
#include "swrenderer/scene/r_portal.h"
#include "swrenderer/r_main.h"
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor)
namespace swrenderer
{
namespace
@ -47,6 +50,182 @@ namespace swrenderer
uint8_t *OffscreenColorBuffer;
}
void R_ProjectVoxel(AActor *thing, DVector3 pos, FVoxelDef *voxel, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade)
{
// transform the origin point
double tr_x = pos.X - ViewPos.X;
double tr_y = pos.Y - ViewPos.Y;
double tz = tr_x * ViewTanCos + tr_y * ViewTanSin;
double tx = tr_x * ViewSin - tr_y * ViewCos;
// [RH] Flip for mirrors
RenderPortal *renderportal = RenderPortal::Instance();
if (renderportal->MirrorFlags & RF_XFLIP)
{
tx = -tx;
}
//tx2 = tx >> 4;
// too far off the side?
if (fabs(tx / 128) > fabs(tz))
{
return;
}
double xscale = spriteScale.X * voxel->Scale;
double yscale = spriteScale.Y * voxel->Scale;
double piv = voxel->Voxel->Mips[0].Pivot.Z;
double gzt = pos.Z + yscale * piv - thing->Floorclip;
double gzb = pos.Z + yscale * (piv - voxel->Voxel->Mips[0].SizeZ);
if (gzt <= gzb)
return;
// killough 3/27/98: exclude things totally separated
// from the viewer, by either water or fake ceilings
// killough 4/11/98: improve sprite clipping for underwater/fake ceilings
sector_t *heightsec = thing->Sector->GetHeightSec();
if (heightsec != nullptr) // only clip things which are in special sectors
{
if (fakeside == WaterFakeSide::AboveCeiling)
{
if (gzt < heightsec->ceilingplane.ZatPoint(pos))
return;
}
else if (fakeside == WaterFakeSide::BelowFloor)
{
if (gzb >= heightsec->floorplane.ZatPoint(pos))
return;
}
else
{
if (gzt < heightsec->floorplane.ZatPoint(pos))
return;
if (!(heightsec->MoreFlags & SECF_FAKEFLOORONLY) && gzb >= heightsec->ceilingplane.ZatPoint(pos))
return;
}
}
vissprite_t *vis = R_NewVisSprite();
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
vis->xscale = FLOAT2FIXED(xscale);
vis->yscale = (float)yscale;
vis->x1 = renderportal->WindowLeft;
vis->x2 = renderportal->WindowRight;
vis->idepth = 1 / MINZ;
vis->floorclip = thing->Floorclip;
pos.Z -= thing->Floorclip;
vis->Angle = thing->Angles.Yaw + voxel->AngleOffset;
int voxelspin = (thing->flags & MF_DROPPED) ? voxel->DroppedSpin : voxel->PlacedSpin;
if (voxelspin != 0)
{
DAngle ang = double(I_FPSTime()) * voxelspin / 1000;
vis->Angle -= ang;
}
vis->pa.vpos = { (float)ViewPos.X, (float)ViewPos.Y, (float)ViewPos.Z };
vis->pa.vang = FAngle((float)ViewAngle.Degrees);
// killough 3/27/98: save sector for special clipping later
vis->heightsec = heightsec;
vis->sector = thing->Sector;
vis->depth = (float)tz;
vis->gpos = { (float)pos.X, (float)pos.Y, (float)pos.Z };
vis->gzb = (float)gzb; // [RH] use gzb, not thing->z
vis->gzt = (float)gzt; // killough 3/27/98
vis->deltax = float(pos.X - ViewPos.X);
vis->deltay = float(pos.Y - ViewPos.Y);
vis->renderflags = renderflags;
if (thing->flags5 & MF5_BRIGHT)
vis->renderflags |= RF_FULLBRIGHT; // kg3D
vis->Style.RenderStyle = thing->RenderStyle;
vis->FillColor = thing->fillcolor;
vis->Translation = thing->Translation; // [RH] thing translation table
vis->FakeFlatStat = fakeside;
vis->Style.Alpha = float(thing->Alpha);
vis->fakefloor = fakefloor;
vis->fakeceiling = fakeceiling;
vis->Style.ColormapNum = 0;
vis->bInMirror = renderportal->MirrorFlags & RF_XFLIP;
vis->bSplitSprite = false;
vis->voxel = voxel->Voxel;
vis->bIsVoxel = true;
vis->bWallSprite = false;
DrewAVoxel = true;
// The software renderer cannot invert the source without inverting the overlay
// too. That means if the source is inverted, we need to do the reverse of what
// the invert overlay flag says to do.
INTBOOL invertcolormap = (vis->Style.RenderStyle.Flags & STYLEF_InvertOverlay);
if (vis->Style.RenderStyle.Flags & STYLEF_InvertSource)
{
invertcolormap = !invertcolormap;
}
FDynamicColormap *mybasecolormap = basecolormap;
if (current_sector->sectornum != thing->Sector->sectornum) // compare sectornums to account for R_FakeFlat copies.
{
// Todo: The actor is from a different sector so we have to retrieve the proper basecolormap for that sector.
}
// Sprites that are added to the scene must fade to black.
if (vis->Style.RenderStyle == LegacyRenderStyles[STYLE_Add] && mybasecolormap->Fade != 0)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, 0, mybasecolormap->Desaturate);
}
if (vis->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 (fixedcolormap != nullptr)
{ // fixed map
vis->Style.BaseColormap = fixedcolormap;
vis->Style.ColormapNum = 0;
}
else
{
if (invertcolormap)
{
mybasecolormap = GetSpecialLights(mybasecolormap->Color, mybasecolormap->Fade.InverseColor(), mybasecolormap->Desaturate);
}
if (fixedlightlev >= 0)
{
vis->Style.BaseColormap = mybasecolormap;
vis->Style.ColormapNum = fixedlightlev >> COLORMAPSHIFT;
}
else if (!foggy && ((renderflags & RF_FULLBRIGHT) || (thing->flags5 & MF5_BRIGHT)))
{ // full bright
vis->Style.BaseColormap = (r_fullbrightignoresectorcolor) ? &FullNormalLight : mybasecolormap;
vis->Style.ColormapNum = 0;
}
else
{ // diminished light
vis->Style.ColormapNum = GETPALOOKUP(r_SpriteVisibility / MAX(tz, MINZ), spriteshade);
vis->Style.BaseColormap = mybasecolormap;
}
}
}
void R_DrawVisVoxel(vissprite_t *sprite, int minZ, int maxZ, short *cliptop, short *clipbottom)
{
R_SetColorMapLight(sprite->Style.BaseColormap, 0, sprite->Style.ColormapNum << FRACBITS);

View File

@ -32,6 +32,7 @@ namespace swrenderer
enum { DVF_OFFSCREEN = 1, DVF_SPANSONLY = 2, DVF_MIRRORED = 4 };
void R_ProjectVoxel(AActor *thing, DVector3 pos, FVoxelDef *voxel, const DVector2 &spriteScale, int renderflags, WaterFakeSide fakeside, F3DFloor *fakefloor, F3DFloor *fakeceiling, sector_t *current_sector, int spriteshade);
void R_DrawVisVoxel(vissprite_t *sprite, int minZ, int maxZ, short *cliptop, short *clipbottom);
void R_FillBox(DVector3 origin, double extentX, double extentY, int color, short *cliptop, short *clipbottom, bool viewspace, bool pixelstretch);
kvxslab_t *R_GetSlabStart(const FVoxelMipLevel &mip, int x, int y);